Serializar listas genéricas en aplicaciones WinRT

andorraenamora

Edit (11/03/2013): Gracias a una sugerencia del colega MVP Javier Torrecilla se ha modificado el código para especificar el Encoding (UTF8Encoding) y así evitar problemas. Thx dude! :)

 

Hola de nuevo,

Rompiendo un poco con la serie de posts sobre las ‘Parallel Series’, hoy quiero escribir acerca de algo totalmente distinto. Y es que ando haciendo mis pinitos con mi primera aplicación Windows Store, y me estoy encontrando con bastantes cosas que no conozco, y que desde mi absoluto desconocimiento de la plataforma, encuentro bastante tediosas de realizar.

Hoy por ejemplo estaba tratando de almacenar ciertos datos en local -ya que para esta aplicación no quiero depender de ninguna base de datos porque en realidad son cuatro datos- y no he encontrado una forma directa de persistir listas genéricas en el sistema de ficheros local.

Si que es cierto que las herramientas están ahí para ser usadas ‘a mano’, pero he echado en falta una forma más sencilla de hacerlo (que no quiere decir que no exista), de modo que he creado una clase para facilitarme el proceso.

Su propósito es muy específico, pero básicamente permite guardar y leer cualquier lista genérica List<T> a un fichero, que puede ser guardado en la carpeta Local, Temporal o de Roaming.

La clase es la siguiente (aunque supongo que es muy mejorable):

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Windows.Storage;

namespace MySampleApp.Domain
{
    public class LocalStorage<T>
    {
        public List<T> Data { get; set; }
        public string Filename { get; set; }
        public StorageFolder StorageFolder { get; set; }

        public LocalStorage(string filename)
        {
            Filename = filename;
            Data = new List<T>();
            StorageFolder = ApplicationData.Current.LocalFolder;
        }

        public async Task SaveAsync()
        {
            if (!await fileExistAsync(Filename))
            {
                await StorageFolder.CreateFileAsync(
                    Filename, CreationCollisionOption.ReplaceExisting);
            }
            await saveToLocalStorageAsync();
        }

        public async Task<List<T>> LoadAsync()
        {
            if (await fileExistAsync(Filename))
            {
                return await loadFromLocalStorageAsync();
            }
            else
            {
                await StorageFolder.CreateFileAsync(Filename);
                return null;
            }
        }

        public async void DeleteAsync()
        {
            try
            {
                if (await fileExistAsync(Filename))
                {
                    var file = await StorageFolder.GetFileAsync(Filename);
                    if (file != null) await file.DeleteAsync();
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        private async Task<bool> fileExistAsync(string fileName)
        {
            try
            {
                await StorageFolder.GetFileAsync(fileName);
                return true;
            }
            catch
            {
                return false;
            }
        }

        private async Task saveToLocalStorageAsync()
        {
            var sessionFile = await StorageFolder.CreateFileAsync(
                Filename, CreationCollisionOption.ReplaceExisting);
            using (var sessionRandomAccess = await sessionFile.OpenStreamForWriteAsync())
            {
                var serializer = new XmlSerializer(typeof(List<T>), new Type[] { typeof(T) });
                serializer.Serialize(new StreamWriter(sessionStream, new UTF8Encoding()), Data);
                await sessionStream.FlushAsync();
            }
        }

        private async Task<List<T>> loadFromLocalStorageAsync()
        {
            var sessionFile = await StorageFolder.CreateFileAsync(
                Filename, CreationCollisionOption.OpenIfExists);
            if (sessionFile == null) return null;
            using (var sessionInputStream = await sessionFile.OpenReadAsync())
            {
                var reader = XmlReader.Create(new StreamReader(
                    await sessionFile.OpenStreamForReadAsync(), new UTF8Encoding()));
                var serializer = new XmlSerializer(typeof(List<T>), new Type[] { typeof(T) });
                Data = (List<T>)serializer.Deserialize(reader);
                return Data;
            }
        }
    }
}

Y para utilizarla basta con disponer de una lista de objetos de un tipo T:

var customers = new List<Customer>();
customers.AddRange(getSampleCustomers());

Y posteriormente crear una instancia de LocalStorage:

var storage = new MySampleApp.Domain.LocalStorage<Customer>("customers.xml");
//Opcionalmente podemos cambiar la carpeta de destino (por defecto es LocalStorage)
storage.StorageFolder = Windows.Storage.ApplicationData.Current.RoamingFolder;
//Añadimos los datos a persistir
storage.Data.AddRange(customers );
//Guardar los datos al fichero customers.xml
await storage.SaveAsync();
//Recuperar los datos del fichero customers.xml
await storage.LoadAsync();
//Eliminar el fichero customers.xml
storage.DeleteAsync();

Si alguien tiene alguna sugerencia o mejora que no dude en escribir un comentario.

Nos vemos! :)

Amazing: Awarded MVP of the Year!

mvplogohor

Surprised. Puzzled. Amazed. These are the words that define better my current feelings.

However, while writing these lines I’m just realizing I have a blissful smile, or maybe just a stupid smile. Why? Because I just received an email from Lisa Feigenbaum (Microsoft Community Program Manager) with this message:

“Congratulations on being awarded C# MVP of the Year based on your contributions in 2011!”

WOW! That’s amazing, and sincerely, totally unexpected

For the last 9 years I have been awarded a Microsoft MVP, and believe me, that’s something very important for me. Maybe not for being recognized as an ‘expert’ (it is hard to use that word while there are so damn good people out there), but because they recognize the work of helping the community.

So now, in a private survey all the C# MVPs around the world and the product team have decided to recognize my contributions with the ‘C# MVP of the year’ award, whatever that means.

On the next March 2nd there will be an honorary dinner sponsored by S. Somasegar (“Soma”), Senior Vice President of the Developer Division at Microsoft, with other executives and community leads in the division. Unfortunately, I won’t be able to attend because I come back from Seattle the same day in the morning. Nevertheless I promise you while I am in Seattle I’ll try to have a beer with some of these guys.

From here I’d like to congratulate the rest of the winners (there are 29 in all categories) and thank all my colleagues. Hey people, you’re great!

Kind regards from Andorra,

PS – Next week I´ll start telling you my experiences @ Seattle.

Alucina: Premiado C# MVP of the year!

mvplogohor

Sorprendido. Perplejo. Flipado. Esas son ahora mismo las palabras que mejor pueden definir mi estado actual.

No obstante, a medida que voy escribiendo estas líneas y lo voy realizando voy experimentando una alegría enorme, que ya está se empezando a transformar en una sonrisa beatífica, por no decir estúpida. Y es que he recibido un mail de Lisa Feigenbaum (Microsoft Community Program Manager) con un mensaje que dice:

“Congratulations on being awarded C# MVP of the Year based on your contributions in 2011!”

WOW! Mola mucho, aunque la verdad y aunque suene a tópico no me lo esperaba ni de coña…

Durante los últimos 9 años he tenido la suerte de ser reconocido como Microsoft MVP y eso es algo que valoro mucho. No tanto por ser reconocido como ‘experto’ (cuesta mucho emplear esa palabra habiendo gente tan condenadamente buena), sino por el hecho que se reconozca la labor de ayudar a la comunidad. Que al fin y al cabo es lo que debería contar en el programa MVP, y -seamos sinceros- no siempre es lo único que cuenta.

Pues bien, ahora resulta que en una votación entre los 234 compañeros MVP de la categoría de C# repartidos por todo el mundo y el equipo de producto han decidido nombrarme MVP de C# del año, sea lo que sea eso, que la verdad, todavía no lo tengo muy claro.

De entrada el próximo 2 de Marzo, hay una cena en Seattle con S. Somasegar (“Soma”), Senior Vice President de la división de desarrollo en Microsoft, así como otros peces gordos y miembros destacados de la comunidad. Para mi desgracia, no voy a poder asistir pues vuelvo de Seattle en mismo día por la mañana pero durante mi estancia en el campus de Microsoft trataré de al menos tomarme una cerveza con alguno de estos personajes :-)

Desde aquí quiero dar la enhorabuena al resto de premiados (he contado 29 en todas las categorías) y a todos mis compañeros. De verdad gente, sois grandes! :-D

Un abrazo a todos,

PD – La semana que viene ya os empezaré a contar mis batallitas en Seattle, en directo.

Luces, cámara… Action!

Action2

Magia sin delegados

Los delegados de tipo Action son una de las pequeñas maravillas traídas a .NET desde la programación funcional. Pueden definirse como un método que tiene un sólo parámetro (en su sobrecarga más simple) y que no devuelve ningún valor. Habitualmente suelen usarse para almacenar referencias a métodos o para pasar un método como parámetro sin tener que declarar explícitamente un delegado. Basta definir el parámetro con la misma firma que se espera recibir y la magia empieza a actuar.

Un detalle importante que podemos ver al observar la firma de Action<T> es que el tipo T es contravariante, de modo que podemos usar este tipo en cualquier otro tipo derivado.  Si quieres saber más sobre covarianza y contravarianza en Generics dale un buen vistazo a este post del blog del colega Eduard Tomàs.

Veamos un poco de esta magia. Suponiendo que tenemos un método que admite un parámetro de tipo Action<string> podemos llamar al método y pasarle (o más bien inyectarle) el comportamiento deseado, es decir pasarle un método que cumpla con la firma por parámetro:

void test()
{
     string msg = "This is the value...";
     doSomethingWithStringValue(enqueueMessage, msg);
     doSomethingWithStringValue(saveToDatabase, msg);
     doSomethingWithStringValue(writeMessageToConsole, msg);
}

private void doSomethingWithStringValue(Action<string> actionToDo, string value)
{
     //do several things with this value
     validateMessage(value);
     compressMessage(value);
     //when finishing...
     actionToDo(value);
}

private void enqueueMessage(string value)
{
     //do something & enqueue this value
     Queue<string> messages = new Queue<string>();
     messages.Enqueue(value);
}

private void saveToDatabase(string value)
{
     //do something & save to db this value
     addLineToUserLog(value);
}

private void writeMessageToConsole(string value)
{
     //do something & output this value
     Console.WriteLine(value);
}

Fijaros: Por un lado tenemos tres métodos que hacen cosas distintas pero tienen la misma firma (todos esperan un parámetro de tipo string). Y por el otro tenemos un método que tiene un parámetro de tipo Action<string>. Es decir, este parámetro admite como valor cualquier método que tenga la misma firma que hemos declarado. De este modo, podemos invocarlo varias veces y en cada una de ellas de podemos decir que utilice un método distinto para hacer algo distinto. Muy similar a las funciones asíncronas de Javascript o al patrón Promise.

Bonito, eh? Es lo mismo que utilizar delegados pero, uhm… espera! Si, sin usarlos :)

Actions por todos lados

Pues cada vez son más las clases del framework que hacen uso de este tipo de delegados y de su hermano Func, que viene a ser lo mismo pero retornando un valor. Sin ir más lejos, los métodos extensores de LINQ (Select, Where, OrderBy) utilizan Func y casi toda la TPL se basa en el uso de Action, desde los bucles For y ForEach de la clase estática Parallel, hasta la creación explícita de tareas mediante la clase Task.

Por ejemplo, cuando deseamos ejecutar una tarea de forma asíncrona, podemos utilizar el método StartNew de la clase Task.Factory. Este método tiene una sobrecarga en el que acepta un parámetro de tipo Action o Func, y lo mejor de todo es que puede crearse inline (en línea), es decir en el mismo momento en que se realiza la llamada. Veamos unos ejemplos:

Partiendo de un método simple:

private void doSomething()
{
    //Pause for 0 to 10 seconds (random)
    Random r = new Random(Guid.NewGuid().GetHashCode());
    Thread.Sleep(r.Next(10000));
}

Puesto que es un método que ni recibe parámetros ni devuelve nada podemos llegar a utilizar su sobrecarga más sencilla:

Task.Factory.StartNew(doSomething);

Otra opción, si el método tuviese un parámetro int para especificar el número de segundos (en lugar de ser aleatorio) podría ser esta:

private void doSomething(int seconds)
{
    int mseconds = seconds * 1000
    Thread.Sleep(mseconds);
}

Task.Factory.StartNew(() => doSomething(5));

Aquí ya vemos algo más curioso. Algo que seguramente hemos observado muchas veces y utilizado antes: Una expresión lambda. Esta expresión es también algo tomado de la programación funcional, y puede leerse como: “va hacia”. En la parte izquierda de la expresión se especifican los  parámetros de entrada o variables (si existen, en este caso no), y en la parte derecha la propia expresión. El caso anterior es tan simple que no tiene parámetros y sólo usamos la parte derecha de la expresión para enviar el valor 5 al método.

Al usar una expresión lambda se permite que las instrucciones contenidas en dicha expresión puedan varias líneas, de modo que también podemos llegar a hacer algo como esto:

Task.Factory.StartNew(() =>
{
    int x = 5;
    doSomething(x);
    Console.WriteLine("finished!");
});

O directamente esto:

Task.Factory.StartNew(() =>
{
    int x = 5;
    int mseconds = seconds * 1000
    Thread.Sleep(mseconds);
    Console.WriteLine("finished!");
});

En este caso, podemos incluso omitir el método doSomething y usar el código inline directamente en la llamada a StartNew. No obstante, un consejo: No es conveniente abusar de las expresiones inline, de modo que si tenemos más de 5 ó 6 líneas tal vez será más conveniente refactorizar este código para no hacerlo demasiado complejo y respetar los buenos principios de diseño.

Ahora con parámetros

Hasta ahora al realizar la llamada siempre hemos usado un delegado de tipo Action sin parámetros, de ahí los paréntesis vacíos en la parte izquierda de la expresión lambda. Sin embargo encontraremos multitud de casos en los que debemos pasar parámetros. Sin ir más lejos el método Parallel.For tiene un parámetro de tipo Action al que hay que pasarle un valor de tipo int, lógico por otra parte ya que dentro de un bucle es muy necesario conocer en todo momento el valor de la iteración:

Parallel.For(1, 40, (i) =>
{
    serie.Add(i.Fibonacci());
});

Observar que no es necesario definir el tipo de datos de la variable i porque el propio compilador es capaz de inferirlo, pero evidentemente también podemos declarar el tipo previo al nombre de la variable, como siempre (int i).

Podemos pasar tantos parámetros como necesite la Action, el mismo método tiene otra sobrecarga que admite un objeto ParallelLoopState para poder cancelar el bucle:

Parallel.For(1, 40, (i, loopState) =>
{
    serie.Add(i.Fibonacci());
    if (i > 35) loopState.Break();
});

Y por supuesto podemos crearnos nuestras propias acciones con tantos parámetros como sean necesarios. Aunque al igual que ante, si necesitamos pasar más de 3 ó 4 parámetros a un Action tal vez deberíamos plantearnos si estamos haciendo las cosas bien.

private void saveToDatabase(string value, bool useDetails)
{
    addLineToUserLog(value);
    if (useDetails) addLineToUserLogDetails();
}

void test()
{
    //Define una acción que apunta al método saveToDatabase
    Action<string, bool> myAction = (v, s) =>
    {
        saveToDatabase(v, s);
    };

    string value = "This is the value...";
    bool usedetails = true;
    myAction(value, usedetails); //Aquí se llama a la acción y al método al que apunta
}

Resumiendo

Los delegados de tipo Action son muy útiles para simplificar el trabajo con delegados (ahora que lo pienso hace bastante tiempo que no los uso, ni para declarar eventos). Nos permiten especificar las acciones a realizar pudiendo llegar a tener hasta 16 parámetros -demasiados en mi opinión- y al igual que los método void no devuelven ningún valor. Si queremos lo mismo pero pudiendo retornar un resultado debemos utilizar su hermano Func<T, TResult> que es exactamente igual, pero en todas sus sobrecargas (y tiene tantas como Action) el último argumento representa el valor de retorno.

Espero que os haya quedado un poco más claro, para cualquier duda contactad conmigo.

Post complementario a la serie sobre la TPL. Ir al índice de contenidos

Oops! No soy tan original como pensaba…

Una vez terminado este post, me he percatado de que existe otro post sobre Action del conocido BlkRabbitCoder con el mismo título que he usado yo (en su caso es el título de una sección). He estado a punto de quitarlo, pero… que demonios! Para una idea buena que tengo :-D

Parallel Series: Parallel LINQ (PLINQ)

LINQ power!

Creo que estaremos todos de acuerdo en que LINQ ha supuesto una revolución en la forma de desarrollar, y ha hecho que muchos desarrolladores de otros lenguajes nos miren con cierto tono de envidia… E incluso que otras plataformas estén haciendo serios esfuerzos para incorporarlo en sus Frameworks :-)

Ahora, con la llegada de la Task Parallel Library, se abre un mundo de posibilidades gracias a PLINQ, que permite -de forma extremadamente sencilla- convertir cualquier consulta LINQ secuencial en una consulta paralelizable, permitiendo su segmentación y ejecución en los distintos cores en paralelo.

Es decir, cualquier consulta LINQ como ésta, en la que tenemos un array llamado numbers y un método IsPrime que devuelve un valor boolean en función de si un número es primo:

var query =
    from n in numbers
    where n.IsPrime()
    select n;

Puede ser paralelizada simplemente agregando esto:

var query =
    from n in numbers.AsParallel()
    where n.IsPrime()
    select n;

Método IsPrime:

public static class BaseTypesExtensions
{
    public static bool IsPrime(this int n) //1 = false, 2 = true, 3 = true...
    {
        if (n <= 1) return false;
        if ((n & 1) == 0)
        {
            if (n == 2) return true;
            else return false;
        }
        for (int i = 3; (i * i) <= n; i += 2)
        {
            if ((n % i) == 0) return false;
        }
        return n != 1;
    }
}

Partiendo de que el array de números contiene 10 millones de números enteros, y de que mi estación de trabajo actual tiene un procesador i7 con 8 cores, el resultado es abrumador:

La consulta LINQ tarda  5,2 segundos frente a los 1,3 segundos de la segunda.

Es decir, casi 4 segundos menos o un 400% más rápido.

¿Dónde está la magia?

La magia verdadera es que PLINQ nos abstrae de todo el proceso de paralelización, creación de tareas, threads, sincronización y consolidación de los datos.

Y además creo que lo hace de forma muy elegante :-)

Como ya sabemos, las consultas LINQ to objects se basan en IEnumerable<T> (gracias Generics!) que expone un enumerador para recorrer los elementos de una secuencia de elementos de tipo T. Esto hace que todas las colecciones que puedan devolverse en este tipo de consultas (IOrderedEnumerable, IQueryable, etc.) implementen esta interfaz. Hasta aquí nada nuevo bajo el sol.

Sin embargo, en la consulta PLINQ al utilizar el método extensor AsParallel() estamos transformando la secuencia de entrada de IEnumerable<T> a ParallelQuery <T> permitiendo la segmentación de los elementos de la secuencia y ejecutando cada uno de los segmentos en un thread distinto. Y por supuesto, repartiendo el trabajo en los diversos cores (si los hay).

AsParallel

La secuencia de entrada se particiona y se manda por fragmentos a distintos threads que invocan al método IsPrime devolviendo true (T) o false (F), y posteriormente los consolida en una secuencia de salida que puede ser consumida.

No obstante, el hecho de paralelizar el trabajo no garantiza que el resultado sea devuelto en el mismo orden, ya que es posible que un thread termine antes que otro y devuelva su resultado parcial antes de lo esperado. Así que, si la ordenación de los datos de salida es importante tenemos que ir un paso más allá.

asordered

Los primeros elementos deberían ser 2, 3, 5, 7… no 59 y 71 ¿?

PLINQ y la ordenación

Para asegurar la ordenación del conjunto de resultados, basta agregar el método AsOrdered() a la consulta. Este método asegura la correcta ordenación, a costa de implementar una serie de mecanismos de sincronización. Estos mecanismos, lógicamente retardan un poco el tiempo de entrega de los resultados, pero es despreciable. En mi estación de trabajo se arrojan unos valores de 1,311 segundos sin ordenar frente a 1,344 segundos ordenados (apenas 30 milésimas). Estos resultados son la media de una serie de 50 mediciones, con lo que son bastante fiables.

Una vez modificada la consulta:

var query =
    from n in numbers.AsParallel().AsOrdered()
    where n.IsPrime()
    select n;

El resultado es claro:

asordered2

Especificar el grado de paralelización

En la mayoría de las charlas que he dado sobre la TPL se acostumbra a preguntar respecto a funciones que acceden a recursos externos (servicios, sockets, etc.). En estos casos aparece claramente un cuello de botella, y no porque una función necesite hacer uso intensivo de la CPU, sino porque debe esperar un resultado externo. Aquí suele ser interesante especificar el grado de paralelización de deseamos. Otro caso interesante para especificar el grado de paralelización puede ser el típico escenario de productor/consumidor.

Es interesante notar que al especificar el grado de paralelización no estamos forzando a que se usen n particiones, sino que simplemente estamos especificando el valor máximo:

var cores = Environment.ProcessorCount;
var query =
    from n in numbers.AsParallel().AsOrdered().
        WithDegreeOfParallelism(cores / 2)
    where n.IsPrime()
    select n;

De este modo, al definir el grado de paralelización en la mitad del número de cores del procesador nos aseguramos que (por ejemplo) podremos tener un hilo que vaya creando elementos (productor) y otro hilo que vaya consumiendo dichos elementos (consumidor).

Cancelación de una consulta PLINQ

En ocasiones, una consulta PLINQ puede ser cancelada. Bien porque durante el proceso se ha encontrado un error y ya no es necesario terminar de calcular el resto de resultados, o simplemente porque ha sido cancelada por el usuario.

Es estos casos, es necesario utilizar un token de cancelación. Este token tiene su origen en la estructura CancellationTokenSource, que representa ‘una potencial cancelación’ y proporciona los mecanismos para cancelar y comprobar el estado de una tarea asíncrona, de modo que puede utilizarse con todos los elementos de la Task Parallel Library, no sólo con PLINQ.

A continuación, vamos a modificar el código del ejemplo que hemos usado hasta ahora para simular un error y comprobar el funcionamiento de la cancelación de tareas en PLINQ. Para ello lo primero que vamos a hacer es crear una sobrecarga del método IsPrime, que reciba un parámetro de tipo CancellationTokenSource, para poder cancelar la tarea:

public static bool IsPrime(this int n, CancellationTokenSource cs)
{
    if (n == 1000) cs.Cancel();
    return IsPrime(n);
}

A modo de ejemplo, cuando el número a calcular sea 1.000 cancelaremos la tarea, de modo que no sea necesario llegar a los 10 millones. De este modo, por un lado se lanzará una excepción y por otro el tiempo en ejecutar la consulta PLINQ será mucho menor.

private void plinq_cancellable()
{
    var numbers = Enumerable.Range(1, 10000000);
    using (var cs = new CancellationTokenSource())
    {
        clock.Restart();
        var query = numbers.AsParallel().AsOrdered().
            WithCancellation(cs.Token).
            Where(p => p.IsPrime(cs));
        try
        {
            var result = query.ToList();
        }
        catch (OperationCanceledException ex)
        {
            Console.WriteLine(ex.Message);
        }
        clock.Stop();
        this.Text = clock.ElapsedMilliseconds.ToString("n2");
    }
}

Por un lado tenemos que tener la precaución de envolver la consulta dentro de un bloque try-catch (en este caso sólo la llamada a ToArray() que es realmente cuando se ejecuta la consulta), y por el otro especificamos que la consulta puede ser cancelada mediante WithCancellation. A continuación creamos un objeto de tipo CancellationTokenSource para administrar la cancelación de esta consulta. Este objeto será el que finalmente pasemos al método IsPrime() y en caso que se cancele provocará que su propiedad IsCancellationRequested devuelva true y que se produzca una bonita excepción de tipo OperationCanceledException.

WithCancellation

Limitaciones de PLINQ

No quiero extenderme mucho más porque creo que hay material suficiente para hacer un post más adelante sobre temas avanzados. Sin embargo quiero dejar claro que existen algunas limitaciones en PLINQ, como el uso de algunos operadores (Take, SkipWhile) y de las versiones indexadas de Select o ElementAt.

Además existen otros casos en los que por cuestiones de rendimiento no es recomendable usar PLINQ en todos los casos, debido al sobrecoste que puede llegar a ocasionar, como el uso de Join, Union o GroupBy. Sin embargo, trataremos éstas cuestiones más adelante.

Próximamente veremos cómo utilizar la clase estática Parallel, optimizada para trabajar con procesos iterativos, esos típicos bucles que todas las aplicaciones tienen.

Volver al índice de contenidos

How to: Grouping groups

GroupPolicy

Today I would like to show a tip for grouping active directory groups using LINQ to objects.

Suppose this scenario: You wanna retrieve all the roles a user belongs, grouping them by their domain name, as shows:

Groups under:
– Group name: All
– Group name: LOCAL
Groups under: BUILTIN
– Group name: Users
– Group name: Administrators
Groups under: PRIMARY_DOMAIN_NAME
– Group name: xxx1
– Group name: xxx2
– Group name: xxx3
– Group name: xxx4
– Group name: xxxN
Groups under: NT AUTHORITY
– Group name: INTERACTIVE
– Group name: Authentified users

(*) As you can imagine, some names have been deleted for security reasons :-)

We can accomplish this using only one LINQ to objects sentence, and a couple of extension methods (extending the NTAccount class):

public static IOrderedEnumerable<IGrouping <string, NTAccount>>
    GetGroupsUnderDomains(this WindowsIdentity identity)
{
    var groups =
        from grIdentity in identity.Groups
        where grIdentity.IsValidTargetType(typeof(NTAccount))
        select grIdentity.Translate(typeof(NTAccount)) as NTAccount into ntAccounts
        let domainName = ntAccounts.GetDomainName()
        orderby domainName
        group ntAccounts by domainName
            into domainGroups
            orderby domainGroups.Key
            select domainGroups;
    return groups;
}

public static string GetDomainName(this NTAccount account)
{
    string[] split = account.Value.Split('\\');
    return split.Length == 1 ? string.Empty : split[0];
}

public static string GetAccountName(this NTAccount account)
{
    string[] split = account.Value.Split('\\');
    return split[split.Length - 1];
}

Awesome! LINQ rules :-)

If you would try this code, it’s quite simple:

var groups = WindowsIdentity.GetCurrent().GetGroupsUnderDomains();
foreach (var dg in groups)
{
    Console.WriteLine(string.Format("Groups under: {0}", dg.Key));
    foreach (var g in dg)
    {
        Console.WriteLine(string.Format("  - Group name: {0}", g.GetAccountName()));
    }
}

HYEI, happy coding!

December 2010

How to: Check if current user is member of ‘domain admins’

The scenario

Sometimes in business applications it’s interesting checking if current user is member of the ‘domain administrators’ role. For example I am used to checking if current user has administrative privileges in order to showing some advanced configuration options (changing the application’s connection string, or allow creating new users).

privileges_thumb

IsInRole

To acomplish this we could use WindowsPrincipal class and its IsInRole method (this method checks if an user is member of a Windows role and returns a bool value). One of its overrides allows to pass the SID of the role or a constant value based on the enumeration WindowsBuiltInrole.

Note: For performance reasons, it’s recommended to use the override: IsinRole(SecurityIdentifier).

To check if current user is a local administrator we only need to do this:

WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
return wp.IsInRole(WindowsBuiltInRole.Administrator);

Notice that it’s realy easy, but as -its name indicates- WindowsBuiltInrole enumeration only contains local roles. So, if we would check if our user is member of a domain group, we should find the role SID, and then copy this value in our code.

As you can imagine, this is not the best solution, isn’t it? Well, let’s investigate a little bit more…

WellKnownSidType

Let’s take a look at the following enumeration WellKnownSidType, this enumeration provides commonly used security identifiers. Uhm… sounds good! Let’s try to use it in our code:

WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.AccountDomainAdminsSid, null);
return wp.IsInRole(sid);

Do’h!It seems that we need to pass the second argument called DomainSId…

CurrentUserIsDomainAdminError

DomainSid

What the hell means DomainSId? At MSDN we can read a brief explanation: Represents the domain SID, and this value is required for some WellKnownSidType values.

At this point our goal should be know the domain SID, but wait… how can I retrieve the domain SID? After spend some time surfing the Internet, the only solution I could find was an utility called PSGetSid from Mark Russinovich inside PSTools components. If you want try it, you can download this utility and execute it from your console to know the SID of your domain (type your domain name as “microsoft.com” o “net.volvo.com”):

DomainSidConsole_thumb

However, I’m pretty sure exists a better solution to this issue. Thus, let’s try to ask to our domain their SID, using the namespace System.DirectoryServices:

Domain d = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, getDomainName()));
using (DirectoryEntry de = d.GetDirectoryEntry())
{
    byte[] domSid = (byte[])de.Properties["objectSid"].Value;
    string sdomainSid = sIDtoString(domSid);
    Console.WriteLine(sdomainSid);
}

Here we need a couple of auxiliar methods. The first one retrieves the domain name, and the second one retrieves a string that represents a SID value (from a byte array).

public static string getDomainName()
{
    return IPGlobalProperties.GetIPGlobalProperties().DomainName;
}

public static string sIDtoString(byte[] sidBinary)
{
    SecurityIdentifier sid = new SecurityIdentifier(sidBinary, 0);
    return sid.ToString();
}

Then, the value of sdomainSid corresponds to the SID of our domain. Great! Now, we can use it to retrieve the SID of the domain administrators role.

Putting it all together

Like my collegue and friend @alegrebandolero, I’m also a fan of extension methods. So, let’s create an extension method for the WindowsIdentity class:

using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Net.NetworkInformation;
using System.Security.Principal;

namespace TestAD
{
    public static class SecurityExtensions
    {
        public static bool IsDomainAdmin(this WindowsIdentity identity)
        {
            Domain d = Domain.GetDomain(new
                DirectoryContext(DirectoryContextType.Domain, getDomainName()));
            using (DirectoryEntry de = d.GetDirectoryEntry())
            {
                byte[] domainSIdArray = (byte[])de.Properties["objectSid"].Value;
                SecurityIdentifier domainSId = new SecurityIdentifier(domainSIdArray, 0);
                SecurityIdentifier domainAdminsSId = new SecurityIdentifier(
                WellKnownSidType.AccountDomainAdminsSid, domainSId);
                WindowsPrincipal wp = new WindowsPrincipal(identity);
                return wp.IsInRole(domainAdminsSId);
            }
        }

        private static string getDomainName()
        {
            return IPGlobalProperties.GetIPGlobalProperties().DomainName;
        }
    }
}

That’s all. Now, use it as follows:

if (WindowsIdentity.GetCurrent().IsDomainAdmin())
{
    //Some actions…
}

Edit 12/14/2010: Since Windows Vista, each Windows user have a couple of security tokens. The first one is the normal token with limited privileges, and the second one only works when you ‘run as administrator’. This code only works if you are using the second token, running the application as administrator.

HYEI, happy coding!

December 2010

How to: Retrieve all controls in a form, using generics (II) – Linq at rescue!

Hi again,

In my previous post, I created a recursive function to retrieve all controls inside a form and its containers. Today, my colleague and friend Eduard Tomàs (software architect @ RAONA) has posted another solution to the same topic based on Linq. It’s quite simply and really, really pretty:

tshirt

A new approach:

Before starting, we need to solve this: Linq works over IEnumerable<T>, but Control.Controls property returns a ControlCollection type. In fact, nowadays, since we have Generics this class has no sense (like other 1.000 similar classes), but remember that Generics doesn’t appeared until .NET Framework 2.0. So, our first step will be retrieve an IEnumerable<Control> from a ControlCollection. With using an extensor method this will be really easy:

public static IEnumerable<Control> AsEnumerable
    (this Control.ControlCollection @this)
{
    foreach (var control in @this)
        yield return (Control)control;
}

Note that using this code we are able to transform CollectionControl to IEnumerable<Control>, and get full access to the power of Linq. Now, let’s create a method to retrieve all controls of a type, as follows:

public static IEnumerable<T>
    GetAllControls<T>(this Control @this) where T : Control
{
    return @this.Controls.AsEnumerable().Where(x => x.GetType() == typeof(T)).
    Select(y=>(T)y).
        Union(@this.Controls.AsEnumerable().
        SelectMany(x => GetAllControls<T>(x)).
        Select(y=>(T)y));
}

It looks cool, isn’t it? No loops, no ifs… only pure Linq power! :-)

There’s a small difference with my original solution and this new one. In my original solution I used an internal List<T> to copy all controls references. The new one only iterates over the original collection. There’s no internal lists. This is the power of Linq.

Another difference present in Linq solution is: We are returning an IEnumerable, so, we loose the ForEach method (because IEnumerable doesn’t implements this method). But building our own ForEach method is trivial:

public static void ForEach<T>
    (this IEnumerable<T> @this, Action<T> action)
{
    foreach (T t in @this)
    {
        action(t);
    }
}

HYEI, happy coding!

November 2010

How to: Retrieve all controls in a form, using generics (I)

Note: This is a very common question in MSDN forums. For this reason I decided to write this post, and use it for reference in future questions.

tshirt

The typical question: How to clear the content of all the textboxes in a form?

Answer: Using generics it’s really easy… First of all, let’s create an extensor method, that will returns a collection of all the controls of a type in a Form (or container). And after, we will use this collection to do an action over each returned item.

The extensor method:

public static List<T> GetControls<T>(this Control container) where T : Control
{
    List<T> controls = new List<T>();
    foreach (Control c in container.Controls)
    {
        if (c is T)
            controls.Add((T)c);
        controls.AddRange(GetControls<T>(c));
    }
    return controls;
}

This method retrieves the collection of Controls of a control and then, it call itself recursively, retrieving the content of all his containers.

How to use it:

this.GetControls<TextBox>().ForEach(p => p.Text = string.Empty);

In this code, we will use the extensor method directly in a form (because Form class inherits from ContainerControl, that inherits from ScrollableControl, and ScrollableControl from Control). Or, in other words, our Form will implement our extensor method. So, at compile time, we should specify the type of the controls we want to retrieve (in the example we use TextBox, but you can use Button type instead), and then, use ForEach to apply an action on each one of the items returned.

Moreover, if we want to retrieve only the controls into a container (GroupBox, Panel, TabControl or another), we should call the method for this particular control.

this.GroupBox1.GetControls<TextBox>().ForEach(p => p.Text = "hello");
this.Panel1.GetControls<TextBox>().ForEach(p => p.Text = string.Empty);

Applying several actions on each control:

In most cases, we would apply several actions to each control (not only one). In this case, it’s quite easy: The only thing we have to do is create a method that receives a parameter of this type, and call it passing the control as an argument:

this.GetControls<TextBox>().ForEach(p => ApplyFormat(p));

private void ApplyFormat(TextBox text)
{
    text.BackColor = Color.LightGray;
    text.ForeColor = Color.Red;
    text.Text = "hello";
    text.TextAlign = HorizontalAlignment.Center;
}

Or maybe, using an ‘action delegate’, both options are correct:

this.GetControls<TextBox>().ForEach(p =>
{
    p.BackColor = Color.LightGray;
    p.ForeColor = Color.Red;
    p.Text = "hello";
    p.TextAlign = HorizontalAlignment.Center;
});

Happy coding! :-)

November 2010