El recolector de basura

Todo desarrollador que haya trabajado con .NET, alguna vez ha escuchado hablar del recolector de basura. En este artículo vamos a intentar poner un poco de luz sobre ese concepto, muchas veces misterioso para los programadores.

¿Por qué existe o necesitamos un recolector de basura?

El CLR es un maquina virtual en el que se ejecutan nuestras aplicaciones y .NET es un framework. Microsoft hizo este framework para tener una capa de abastración entre el sistema operativo y las aplicaciones. Una de las cosas más problemáticas en cuanto al desarrollo de aplicaciones es la gestión de memoria. La memoria no es infinita y necesita de una gestión, reservar, liberar, compactar, reorganizar. Es por esto que .NET tiene el recolector de basura, para ayudarnos a recolectar los elementos no utilizados y reorganizar la memoria.

Esta caracteristica permite que podamos usar los objetos detro de nuestros lenguajes de programación sin tener en cuenta como se reclican, nostros hacemos el new y el recolector de basura, cuando el objeto ya no sea usado, lo recolectará.

¿Como se produce esta recolección de basura? y ¿como el GC sabe que objetos no se están usando?.

Como todos sabreis todos los objetos del framework son referencias a objetos, y cuando nosotros igualamos (a excepción, claro, de que esté sobrecargado el operador ==) lo que estamos haciendo es copiar la referecia en memoria donde está el objeto, es decir copiarmos su dirección y no su contenido. Esto tambien se aplica a los ValueType (structs) solo que el framework trabaja de otra manera, pero eso está fuera de este articulo.

El hecho de que todo sean referencias, hace que cuando nostros tenemos una clase y dentro de esa clase tenemos un campo de un tipo, lo que realmente tenemos es la dirección de memoria donde vive el objeto que referenciamos, lo podemos simplificar en que tenemos un grafo, una serie de elementos representados por vertices y por las aristas que son las referencias entre objetos.

Pues bien cuando nosotros creamos un objeto y lo asignamos lo que estamos haciendo es añadiendo un vertice a nuestro grafo de referencias. Así que una vez que establecemos un objeto a null a menos que tengamos otra referencia (arista) a nuestro elemento ese objeto está completamente aislado del grafo y nadie puede acceder a el.

Pues sabiendo esto, ¿como el GC es capar de saber que un objeto ya no es necesario y puede ser recolectado?, teniendo en cuenta que nadie lo referencia. El secreto está en el heap. El heap mantiene una colección de todos los elementos que el runtime ha creado, es decir, de todos los objetos que tenemos en nuestro grafo pero en formato de lista. Pues bien lo que el GC hace es coger un objecto y saber si hay alguna referncia a ese objeto (una arista) si no es capaz de encontrar una arista hasta ese objeto es porque el objeto nadie lo está referenciado y por eso puede ser recolectado con seguridad. Así se simple.

Ahora bien, el recolector de basura no enumera todos los objetos que estan en el heap y por cada uno de ellos recorre todo el grafo para encontrar una referencia a ese objeto, en vez de eso lo que utiliza son unos objetos raiz, llamados GCRoots, por los cuales empieza el grafo de nuestra aplicación.

Todo esto que he contado como podemos tener evidencias de que es cierto, teniendo un entorno de depuración montado con simbolos y WinDBG + SOS. (Podeis encontrar información de cómo configurar el entorno de depuración en mi blog)

· !dumpheap para mostrar todos los elementos del heap

· !gcroot 0123292 para mostrar cuales son las referencias a un objeto que puede ser:

o En la pila

o En un GCHandle

o En un objeto listo para la finalización

o O en un objeto encontrado el los lugares anteriores

Además de todo eso si sois aventureros y os gusta las experiencias fuertes, podemos visualizar gráficamente el grafo de refencias con sus GCRoots a través una herramienta de profilling que tiene Microsoft, CLRProfiler disponible en www.microsoft.com/downloads

clip_image002

Aquí tenemos una captura del grafo de nuestra aplicación de ejemplo, en la que podemos ver el <root> del que os hablaba.

¿Qué son las generaciones?

Las generaciones son agrupaciones de las edades de los objetos en memoria. Cuando un objeto se crea está en la generación 0, si se produce una recoleccion de basura lo supervivientes de la generación 0, se les promueve a la generacion 1, y la generación 0 se queda libre y compactada. Se empiezan a crear objetos de nuevo, se lanza otra recoleccion de basura de 0 a 1, los objetos que sobreviven de la generacion 1 pasan a la 2 y los que sobreviven de las generacion 0 pasan a la 1, así sucesivamente.

Solamente existen 3 generaciones, la 0, 1 y 2. Normalmente donde más objeto se generan y se destruyen es en la generación 0 porque es la más usada.

Tamaños:

· Generacion 0: 256 kb (cache segundo nivel del procesador)

· Generacion 1: 2Mb

· Generacion 2: 10Mb

Además de todo eso hay una generación especial para los objetos muy grandes en el framework, LOH (Large object heap), que son los objetos con más de 64kb

¿Cuándo se lanza una recoleccion de basura?

Esta es un pregunta complicada porque no tiene una respuesta directa, hay maneras por el cual se puede generar una recolección de basura o por cuales se puede retrasar. Lo más importante a saber es que las recolecciones de basura se hacen cuando la generacion 0 del GC está llena y se va a crear un nuevo objeto, es decir la recoleccion de basura no se produce cuando se llena la memoria, sino cuando se llena la memoria y se intenta crear un objeto. Además de eso hay que tener en cuenta varios factores. El recolector de basura tiene una herustica que le permite tunearse para ofrecer el máximo rendimiento en cada tipo de aplicación, además de que tiene un historial de las acciones que realiza. Por ejemplo, una de las cosas más importantes para el GC es la cantidad de memoria que libera, no la cantidad de objetos que recolecta, si por ejemplo se lanza una recoleccion de memoria y se liberan 150000 objetos que representa 23kb, seguramente el recolector de basura hará que crezca más la memoria de la generacion 0 antes de hacer otra recoleccion, porque lo que le interesa es recolectar mucha memoria no muchas referecias. En ese sentido si el recolector de basura se encuentra con que ha recolectado 150 objetos que ha sido un total de 400kb seguramente la siguiente vez que llene la generación 0 automaticamente generará una nueva recoleccion de basura.

Porque nunca deberia de llamar a GC.Collect

Como he explicado antes el recolector de basura tiene su propia heurística que le permite tunearse de manera automática y sin intervención del programador. En las primeras versiones de .NET se podía llamar a la función GC.Collect (que teóricamente fuerza una recolección de basura), pero que en realidad lo que hacía era sugerir una recolección de basura. En ese sentido muchos desarrolladores se quejaron porque en sus aplicaciones llamaban incesantemente al recolector de basura pero no se lanzaba ninguna recolección (lo sabían porque miraban los contadores de rendimiento de .NET), así que Microsoft tuvo que dar marcha atrás e incluir una sobrecarga en la llamada de GC.Collect que aceptaba por parámetro un entero con la generación máxima en la cual se iba a producir la recolección, y los más importante de todo, un enumerado de tipo GCCollectionMode que permitia decir si la recolección era forzada u optimizada.

Como podeis imaginar el modo optimizado es el predeterminado, es decir, el modo en el que le sugieres al recolector de basura que haga su trabajo, pero el modo forzado, como su nombre indica, forzaba a una recolección de basura. Así que si llamamos a esa función así, GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced) estamos obligando a una recolección de basura completa en nuestra aplicación.

Ahora bien porque nunca se debería de llamar a esta función así, porque básicamente si nos encontramos en una situación en donde la memoria de nuestro proceso sube en todos los escenario y el recolector de basura en su modo de funcionamiento normal no es capaz de bajar la memoria de uso del proceso, nos encontramos entonces ante un escenario de pérdida de memoria (leaking) y no en una situación donde el recolector de basura no es capaz de hacer su trabajo. Porque os puedo asegurar que en el 99.99% de las veces en que he visto una aplicación que hacia llamadas al recolector de basura para intentar liberar memoria era porque el proceso en sí tenía problemas de pérdida de memoria, no porque el recolector no fuera capaz por si solo de hacer su trabajo bien.

Graficas de memoria en forma de montañas

Llegado a este punto mucha gente se imaginará que la ejecución de las aplicaciones es matemáticamente siempre la misma, es decir, que si en un punto de mi aplicación genero 40mb de memoria y después termino de usar esos objetos automáticamente tengo que ver como mi proceso baja esos 40mb de manera discreta. Pues malas noticias para todos, los sistemas de gestión de memoria sin increíblemente complejos y más para una aplicación de .NET.

Puede que el CLR haya decidido por un casual no liberar esa memoria nativa porque ya que la tiene reservada y no tiene que devolverla al S.O. y más adelante la podrá usar sin tener que volver a pedir memoria a Windows. En ese sentido el CLR también utiliza las funciones de memoria virtual de Windows (VirtualAlloc, VirtualFree, VirtualQuery, VirtualProtect) así que en ese sentido también Windows hace un uso de la memoria de manera conservativa es decir, que no por generar 40mb y ejecutar el recolector de basura automáticamente se liberan 40mb.

Así si por ejemplo el sistema necesita liberar páginas de memoria porque otro proceso, a parte del nuestro en .NET, está haciendo un uso de memoria virtual (no una gran reserva de memoria virtual, acordarse de lo que es una falta de página y como Windows gestiona la memoria de manera perezosa) en ese momento puede decidir recuperar las páginas de memoria de nuestro proceso y entonces nuestra memoria bajará.

Así que simplificar un sistema de gestión de memoria virtual de Windows más el sistema de recolección de basura del CRL de .NET de esa manera es desde mi punto de vista barbaridad. Si queremos saber cuál es el estado de nuestro proceso podemos consultar los contadores de rendimiento para .NET o podemos usar las columnas de Private Bytes, Working Set y Virtual Size en Process Explorer o el comando !address –summary en WinDBG para saber exactamente esa memoria privada en que se gasta en heap, images, ect.

¿Qué son los objetos pineados en memoria?

Cuando hablamos de recolección de basura, también hablamos de compactación de la memoria y para que esa compactación de la memoria pueda ocurrir es necesario mover los datos de direcciones de memoria. En un mundo ideal donde las aplicaciones de .NET sean completamente administradas, es decir 100% .NET sin llamadas a Windows esto debería de bastar, pero el caso es que desde .NET podemos hacer llamadas a componentes no administrados que están fuera del paraguas del recolector de basura.

Imaginaros por un momento que estáis haciendo una llamada nativa a una función hecha en C++ que os pide una dirección de memoria donde vive un objeto que él internamente va a utilizar para realizar su trabajo, resulta que como parte de su trabajo ese componente de C++ tiene un temporizador que cada 30sg comprueba una serie de parámetros en ese objeto en contra de un componente de Windows, pero resulta que entre timer y timer, se lanza una recolección de basura y justo el objeto que este componente de C++ utilizaba (porque recordad que le hemos pasado la dirección de memoria, donde vive) es movida por el recolector de basura en una recolección. Justo cuando el siguiente timer se lance y nuestro componente en C++ vaya a leer la memoria se encontrará con que su memoria ahora mismo está ocupada por otro componente.

Este es solo un ejemplo de que a veces no interesa que determinados objetos de .NET estén siempre en la misma dirección de memoria, cualquiera podría haber sugerido que hagamos una copia del objeto y se la pasemos a C++, pero recordad que siempre pasamos referencias y no copias de objetos.

Es por eso en .NET podemos pinear objetos en la memoria, que como su nombre indica, permite que podamos indicarle al recolector de basura que en ningún caso mueva de dirección de memoria este objeto.

A través de una structura llamada GCHandle podemos pinear objetos así: System.Runtime.InteropServices.GCHandle.Alloc(new object,System.Runtime.InteropServices.GCHandleType.Pinned). Esta llamada nos devuelve un objeto de tipo GCHandle en el que podemos consultar el IntPtr del objeto, si esta inicializado y podemos liberarlo.

Que son las referencias débiles y que es la resurrección de objetos zombies

Como hemos dicho anteriormente cada vez que hacemos una asignación estamos copiando la referencia en memoria de un objeto, es decir, estamos haciendo una referencia fuerte de un objeto. Si existe una referencia fuerte es porque existe una referencia débil, que siguiendo la analogía tiene que ser una referencia que el recolector de basura no tenga en cuenta para evaluar si un objeto es referenciado por otro.

Para poder usar esas referencias débiles tenemos una clase en .NET llamada WeakReference que como su nombre indica nos permite generar esas referencias débiles. Esta clase tiene varias propiedades interesantes como: IsAlive que nos permite consultar si el objeto al que apuntamos sigue vivo; Target que es una referencia (débil) del objeto y TrackRessurection que nos permite hacer tracking de la resurrección de un objeto.

Pero, ¿Qué es exactamente la resurrección de un objeto?

Cada vez que un objeto es eliminado del grafo de referencias de una aplicación, este pasa a una cola llamada la cola de finalización (comando de WinDBG !finlizaqueue) en la que se le da una última oportunidad de ejecutar el código que tenga en el destructor o en el método Dispose (si implementa IDisposable). En ese instante en el que el objeto está en la cola de finalización un objeto está fuera del grafo de objetos, pero si durante la ejecución de ese código se referencia a si mismo de otro objeto que está en el grafo de objetos de la aplicación a través de un objeto estático, diremos que el objeto ha sufrido una resurrección puesto que el recolector de basura sacará a ese objeto de la cola de finalización y el objeto será de nuevo referenciable y volverá a la vida (metafóricamente hablando).

¿Por qué el .NET tiene una finalización no determinista?

Si durante el desarrollo de nuestras clases implementamos IDisposable o creamos un destructor para nuestra clase, el CLR no nos puede asegurar que el destructor de nuestra clase será siempre ejecutado. ¿Por qué?. En ese sentido tenemos que recordar que el CLR es un runtime ejecutado dentro de un proceso y puede que el proceso o el dominio de aplicación se descargue de manera inesperada y en ese sentido el CRL no puede esperar a que todo el código que tengamos en nuestros destructores se ejecute. Por eso se dice que .NET no es determinista en cuanto a la finalización de objetos, porque solamente en el caso de que el dominio de aplicación se descargue o la aplicación se cierre el CLR no nos asegurará que nuestros destructores se ejecuten.

Pero qué pasa si necesito por contrato que el destructor de mi clase se ejecute, o dicho de otra manera, que pasa con las clases que representan recursos del sistema que tienen que ser liberados si o sí.

En este sentido podemos heredad de la clase System.Runtime.ConstrainedExecution.CriticalFinalizerObject haciendo así que el CLR nos asegure que SIEMPRE se ejecutará el destructor de la clase. Como ejemplo diremos que la clase Thread, ReaderWriterLock, SafeHandle y demás heredan de esta clase.

Conclusiones

A lo largo de este articulo hemos repasado los básicos de la gestión de memoria por parte del CLR, y hemos visto que es un sistema extraordinariamente complejo para poder simplificarlo de la manera que lo hacen algunos así que en ese sentido paciencia con la memoria y si tenéis algún problema no dudéis con contactar con el equipo DOT (Debugging and Optimization Team) de Plain Concepts que estaremos encantados de buscar problemas de memoria y rendimiento en vuestras aplicaciones.

Luis Guerrero.

Gestión de proxies de WCF en Silverlight 4

Una de las cosas que más esfuerzo me cuestan cuanto estoy desarrollando aplicaciones en Silverlight es la gestión del ciclo de vida de un proxy de WCF, es decir, crear la instancia del proxy con la configuración del binding correcta, subscribirme a los eventos complete de las operaciones que quiero invocar y en caso de falta en el proxy volver a hacer todo ese trabajo, de-subscribirme de los eventos complete y volver a repetir el proceso de nuevo.

Es por eso que en el día a día del desarrollo de aplicaciones de Silverlight siempre intento hacer que las cosas sean muy fáciles para mí y que pueda manejar el ciclo de vida de un proxy de una manera muy cómoda. Viendo un poco cuales son las limitaciones que tengo con los proxy de wcf, me encuentro con las que he comentado anteriormente:

  • Creación del proxy con la configuración del binding adecuada.
  • Invocación asíncrona de las operaciones
  • Ciclo de vida del proxy

La primera de las limitaciones se soluciona de manera fácil, con una factoría. Una clase helper o factoría que me permita instancias los proxy de manera cómoda con un sistema centralizado de configuración de bindings y demás opciones. Normalmente en un proyecto de Silverlight casi todos los proxy, por no decir todos, serán del mismo tipo, así que no tenemos que preocuparnos mucho por dar soporte a varios tipos de configuraciones.

public class ProxyFactory
{
    public static T CreateInstance<T, K>(Uri uri)
        where K : class
        where T : ClientBase<K>
    {
        T result = default(T);

        CustomBinding custom = new CustomBinding();
        custom.Elements.Add(new BinaryMessageEncodingBindingElement());
        custom.Elements.Add(new HttpTransportBindingElement()
        {
            MaxReceivedMessageSize = 2147483647,
            MaxBufferSize = 2147483647
        });
        SetDebugTimeouts(custom);

        EndpointAddress address = new EndpointAddress(uri.ToString());

        result = (T)(object)Activator.CreateInstance(typeof(T), custom, address);
        
        return result;
    }

    private static void SetDebugTimeouts(CustomBinding custom)
    {
        if (custom != null)
        {
            TimeSpan timeout = TimeSpan.FromSeconds(60 * 3);
            timeout = TimeSpan.MaxValue;
            custom.CloseTimeout = timeout;
            custom.OpenTimeout = timeout;
            custom.ReceiveTimeout = timeout;
            custom.SendTimeout = timeout;
        }
    }
}

Aquí tenemos el código de la factoría de proxy.

Si nos fijamos acepta dos parámetros genéricos, que son: K es la interfaz del contrato del canal de comunicaciones es decir el contrato de operaciones y T es la clase que hereda de ServiceBase<K>, es decir la clase que implementa el contrato de operaciones en cliente.

Así de esta manera en el cuerpo de la creación podemos crear a mano un custombinding y añadir los elementos que necesitamos, como por ejemplo: BinaryMessageEncondingBindingElement y HttpTransportBindingElement, además de configurar parámetros de esas clases. Creamos también una instancia de la clase EndpointAddress que contiene la dirección url del servicio wcf.

Una vez que tenemos todo esto podemos utilizar la clase Activator para crear una instancia dinámicamente del proxy (a través del tipo de T) pasándoles los parámetros previamente establecidos.

Para consumir el proxy sería de esta manera:

KeyPlayerServiceClient proxy = 
ProxyFactory.CreateInstance<KeyPlayerServiceClient, IKeyPlayerService>(ProxyUrl.KeyPlayerUrl);

Así podemos tener un sistema centralizado de creación de todos los proxies que queramos consumir desde Silverlight.

Manejar el resultado y el ciclo de vida

Pero esta manera de crear las instancias no soluciona el problema que tenemos de manejar el ciclo de vida del proxy, subscribirnos al evento complete de la operación y obtener el resultado de la operación. Es por eso que necesitamos una clase que nos permita invocar una operación asíncrona de un servicio web y que de alguna manera esa clase helper, cree la instancia de la clase, se subscriba al evento de complete, obtenga el resultado de la operación y llame a un delegado que nosotros le hemos especificado. Esto sería lo ideal.

Pues bien podemos hacer todo eso de manera cómoda con esta clase ProxyManager. Antes de centrarnos en cuál es la implementación concreta de la clase y los detalles vamos a ver cómo podemos consumir una operación típica de un servicio de wcf con esta clase ProxyManager.

Si tenemos un servicio con esta operación:

[ServiceContract]
public interface IServiceDemo
{
   [OperationContract]
   DateTime GetDateTime();
}

Tenemos una única operación que se llama GetDateTime y que obtenemos un objeto de tipo DateTime.

Una vez que hemos agregado la referencia al proxy de WCF desde nuestro proyecto de Silverlight, podemos hacer esto:

// manera directa de invocar un servicio web y solo centrarse en la respuesta segun su tipo
ProxyManager<ServiceDemoClient, IServiceDemo> manager = new ProxyManager<ServiceDemoClient, IServiceDemo>(ProxyUrl.DemoService);
// como sabemos que el servicio web devuelve un resultado de tipo DateTime, podemos
// agregar un Action<DateTime> porque DAteTiem es el tipo de devuelve
manager.InvokeOperation<DateTime, GetDateTimeCompletedEventArgs>(
    "GetDateTime",
    new Action<DateTime>(OnGetDateTimeCompleted),
    null);
private void OnGetDateTimeCompleted(DateTime dateTime)
{
}

En este ejemplo fijaros que utilizando la genericidad y la reflexión podemos hacer que la invocación del servicio sea mucho más cómoda, podemos resumirlo a una simple línea de código.

Requisitos tiene la clase ProxyManager

Para crear una instancia de la clase ProxyManager tenemos que pasar los mismos argumentos de tipos que el ProxyFactory, de hecho internamente utiliza el mismo mecanismo, además de la uri de la dirección del servicio web.

Una vez que tenemos el objeto creado tenemos que llamar al único método de la clase ProxyManager, InvokeOperation.

InvokeOperation acepta dos parámetros de tipo que son el tipo que devuelve la operación del servicio web, si nos acordamos era un DateTime, y el otro parámetro genérico es la clase que hereda de AsyncCompletedEventArgs que contiene el resultado de la invocación, en nuestro ejemplo, GetDateTimeCompletedEventArgs. De esta clase es donde el ProxyManager obtendrá el resultado de la operación.

Como parámetros de la función tenemos que suplir el nombre de la operación como un string, en nuestro caso GetDateTime (pero sin Async al final), después un delegado de tipo Action<T> con el resultado, y al final de todos los parámetros un array de tipo object con la palabra params que son los argumentos de la invocación, en nuestro caso null.

Lo bueno que tiene esta clase ProxyManager es que automáticamente por nosotros crea la instancia del proxy, se subscribe al evento complete de la operación que queremos invocar y automáticamente invoca nuestro delegado de tipo Action<T> con el resultado, además de eso cuando termina la invocación del objeto de tipo Action<T> se de-subscribe del evento y cierra el proxy. Toda una gozada.

Además de eso tenemos la posibilidad de utilizar una sobrecarga de la función InvokeOperation que nos permite tener también acceso al objeto de UserState de la invocación por si invocamos más de una vez la operación y necesitamos acceder a un objeto de usuario en la devolución de llamada:

// manera directa de invocar un servicio web y solo centrarse en la respuesta segun su tipo
ProxyManager<ServiceDemoClient, IServiceDemo> manager = new ProxyManager<ServiceDemoClient, IServiceDemo>(ProxyUrl.DemoService);
// como sabemos que el servicio web devuelve un resultado de tipo DateTime, podemos
// agregar un Action<DateTime> porque DAteTiem es el tipo de devuelve
manager.InvokeOperation<DateTime, GetDateTimeCompletedEventArgs>(
    "GetDateTime",
    new Action<DateTime>(OnGetDateTimeCompleted),
    null);

manager.InvokeOperation<DateTime, object, GetDateTimeCompletedEventArgs>(
    "GetDateTime",
    new Action<DateTime, object>(OnGetDateTimeWithArgumentsCompleted),
    null);
private void OnGetDateTimeWithArgumentsCompleted(DateTime result, object userState)
{

}

Con esto podemos hacer que la gestión de los proxies de WCF sea mucho más eficiente que cómoda para el programador que antes.

Codigo fuente completo de la clase ProxyManager:

using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.ServiceModel;

namespace ViewModelBinding.Services
{
    public class ProxyManager<TService, KServiceInterface>
        where KServiceInterface : class
        where TService : ClientBase<KServiceInterface>
    {
        public ProxyManager(Uri url)
        {
            proxy = ProxyFactory.CreateInstance<TService, KServiceInterface>(url);
        }

        public void InvokeOperation<TResult, KEventArgs>(string operationName, Action<TResult> action, params object[] args)
            where KEventArgs : AsyncCompletedEventArgs
        {
            if (!string.IsNullOrWhiteSpace(operationName))
            {
                InternalActionOf<KEventArgs, TResult> internalAction = new InternalActionOf<KEventArgs, TResult>(action);
                internalAction.EventInfo = proxy.GetType().GetEvent(string.Format("{0}Completed", operationName));
                internalAction.Delegate = new EventHandler<KEventArgs>(internalAction.OnActionExecuted);
                internalAction.EventInfo.AddEventHandler(proxy, internalAction.Delegate);
                internalAction.Proxy = proxy;

                if (args == null)
                {
                    args = new object[] { };
                }

                MethodInfo[] methods = proxy.GetType().GetMethods();
                string methodName = string.Format("{0}Async", operationName);
                var found = (from p in methods
                             where p.Name == methodName && p.GetParameters().Length == args.Length
                             select p).FirstOrDefault();



                if (found != null)
                {
                    found.Invoke(proxy, args);
                }
            }
        }

        public void InvokeOperation<TResult, TUSerState, KEventArgs>(string operationName, Action<TResult, TUSerState> action, params object[] args)
            where KEventArgs : AsyncCompletedEventArgs
        {
            if (!string.IsNullOrWhiteSpace(operationName))
            {
                InternalActionOf<KEventArgs, TResult, TUSerState> internalAction = new InternalActionOf<KEventArgs, TResult, TUSerState>(action);
                internalAction.EventInfo = proxy.GetType().GetEvent(string.Format("{0}Completed", operationName));
                internalAction.Delegate = new EventHandler<KEventArgs>(internalAction.OnActionExecuted);
                internalAction.EventInfo.AddEventHandler(proxy, internalAction.Delegate);
                internalAction.Proxy = proxy;

                if (args == null)
                {
                    args = new object[] { };
                }

                MethodInfo[] methods = proxy.GetType().GetMethods();
                string methodName = string.Format("{0}Async", operationName);
                var found = (from p in methods
                             where p.Name == methodName && p.GetParameters().Length == args.Length
                             select p).FirstOrDefault();



                if (found != null)
                {
                    found.Invoke(proxy, args);
                }
            }
        }

        private TService proxy;
    }
}
internal class InternalActionOf<EventArgs, TResult, TUserState>
       where EventArgs : AsyncCompletedEventArgs
{
   public InternalActionOf(Action<TResult, TUserState> action)
   {
       this.action = action;
   }

   internal void OnActionExecuted(object args, EventArgs e)
   {
       PropertyInfo property = e.GetType().GetProperty("Result", BindingFlags.Public | BindingFlags.Instance);
       if (property != null)
       {
           object result = property.GetValue(e, null);
           if (result != null)
           {
               if (typeof(TResult).IsAssignableFrom(property.PropertyType))
               {
                   action((TResult)result, (TUserState)e.UserState);
                   EventInfo.RemoveEventHandler(Proxy, Delegate);
               }
           }
       }
   }

   public EventHandler<EventArgs> Delegate { get; set; }
   public EventInfo EventInfo { get; set; }
   public object Proxy { get; set; }

   private Action<TResult, TUserState> action;
}
internal class InternalActionOf<EventArgs, TResult>
            where EventArgs : AsyncCompletedEventArgs
{
    public InternalActionOf(Action<TResult> action)
    {
        this.action = action;
    }

    internal void OnActionExecuted(object args, EventArgs e)
    {
        PropertyInfo property = e.GetType().GetProperty("Result", BindingFlags.Public | BindingFlags.Instance);
        if (property != null)
        {
            object result = property.GetValue(e, null);
            if (result != null)
            {
                if (typeof(TResult).IsAssignableFrom(property.PropertyType))
                {
                    action((TResult)result);
                    EventInfo.RemoveEventHandler(Proxy, Delegate);
                }
            }
        }
    }

    public EventHandler<EventArgs> Delegate { get; set; }
    public EventInfo EventInfo { get; set; }
    public object Proxy { get; set; }

    private Action<TResult> action;
}

Luis Guerrero.

Entrevista a plain concepts, equipo de desarrolladores de bye bye brain

Entrevista realizada en http://wp7connect.blogspot.com/

¿Podeis hacer una breve presentación sobre el equipo?

 

El equipo lo formamos Ricardo Acosta, Rodrigo Diaz y Luis Guerrero. Ricardo Acosta es nuestro diseñador gráfico, modelador 3d y texturizador, y tanto Rodrigo Diaz como yo somos programadores de .NET.

Supongo que os habéis dado cuenta que la mayoría de blogs especializados en el sector ,de medio mundo, están hablando de vosotros después de que anunciarais en vuestros blogs personales, Bye Bye Brain, el juego para WP7 que estáis desarrollando ¿Os esperabais tanta repercusión en tan poco tiempo? ¿Cómo surgió la idea de desarrollar Bye Bye Brain?

No esperábamos tener tanta acogida como la que hemos tenido, empezamos con el video en vimeo y la cosa fue subiendo hasta que fuimos portada de gizmodo.com toda una hazaña.
La idea de desarrollar ByeByeBrain surgió a principio de año cuando nos enteramos que Microsoft iba a desarrollar una nueva plataforma móvil, nuestra empresa Plain Concepts es Partner Gold de Microsoft y pensábamos en hacer un juego.

¿Por qué consideráis que WP7 es una buena plataforma para lanzar vuestro proyecto, aún cuando todavía no se ha lanzado?


Esta pregunta es complicada de responder, pero supongo que nos lanzamos por ser afines a Microsoft, porque no esperábamos que hubiera muchos desarrolladores haciendo cosas, porque las dos tecnologías en las que se desarrolla XNA y Silverlight las utilizamos a diario así que pensamos que era la oportunidad perfecta para nosotros.

Muchos comentarios resaltan el hecho de que un equipo de tres personas ha realizado un desarrollo tan bueno ¿Cuánto tiempo os ha supuesto desarrollar Bye Bye Brain? ¿Cuál ha sido el aspecto o proceso más difícil?


El primer checking del proyecto se hizo el día 2 de julio a las 12 de la mañana y desde ese momento no hemos parado de trabajar, eso implica definir un pequeño prototipo del juego, pantallas funcionalidad y demás. La parte más difícil del proyecto para mí fue acomodarme a XNA, venia de Silverlight que es un framework de alto nivel con cosas muy cómodas y en XNA no teníamos nada, así en unos de las primeras semanas, definimos un pequeño framework de animaciones basada en Silverlight y un sistema para definir controles y relaciones entre los controles en XNA. Evidentemente no podemos definir los controles igual que en Silverlight pero queríamos definir una relación padre hijo con los DrawableGameComponents de XNA para que fuera más fácil trabajar con ellos. Definimos las DependencyProperties para XNA y alguna que otra cosa más. Con todo eso pudimos después hacer todas las animaciones de los elementos 2D de una manera cómoda ya que animar es tan fácil como en Silverlight.

¿Qué ventajas pensáis que tiene realizar juegos en XNA respecto a los desarrollos que se pueden realizar en otras plataformas móviles como Iphone o Android?

Las ventajas para nosotros en el .NET Framework y C# ya que son nuestros lenguajes principales de desarrollo diario. .NET Framework tiene todo lo que un desarrollador puede soñar y XNA también, así que nos sentimos muy cómodos trabajando con las herramientas. Además de la perfecta integración con Visual Studio 2010.

¿Qué breves consejos le daríais a desarrolladores independientes que están empezando a plantearse desarrollar juegos o aplicaciones para WP7?

Pues que es el momento de hacerlo ya que no hay muchos desarrolladores interesados y eso puede hacer que les sea fácil brillar ya que la plataforma es nueva. Además, desde mi punto de vista, las herramientas de Microsoft son las mejores.

¿Qué opináis de las herramientas de desarrollo para WP7? ¿Cuáles son sus puntos fuertes y sus puntos débiles?


Los puntos fuertes ya los he comentado, las API o frameworks, XNA y Silverlight, son súper productivos para desarrolla aplicaciones, ya que Silverlight con Visual Studio 2010 y con Expression Blend se puede hacer cosas muy chulas en muy poco tiempo. Sobre las cosas malas, son herramientas beta eso significa que contienen algunos bugs que no tienen workaround y que quizás el tiempo de despliegue de tu aplicación al emulador y al devices es muy lento.

¿Desde vuestro punto de vista y habiendo podido acceder a un terminal para desarrolladores qué crees que debe mejorar WP7 a corto-medio plazo?


Esto es una pregunta trampa, Microsoft lo está haciendo bien con WP7 pero realmente es su primera versión del SO, las otras plataformas van por la versión 2.2 o 4 así que evidentemente le falta muchas cosas, pero es un buen comienzo.

¿Cuánto tiempo calculáis que pasará desde que enviéis una aplicación a Microsoft hasta que esté evaluada e incorporada al Marketplace? ¿Cuáles son los puntos críticos de este proceso?

Por ahora no lo sabemos pero Microsoft ha prometido que el proceso será rápido.

Si podéis contarnos algo ¿qué proyectos futuros tenéis en mente respecto a WP7?


Pues tenemos pensado seguir con el desarrollo de ByeByeBrain con más mapas, ataques especiales, más mini juegos, etc. Además de empezar el desarrollo de otros juegos o aplicaciones.

¿Quereis añadir algo más que creas interesante para los usuarios interesados en WP7?


Pues decirles que si son desarrolladores este es su momento de que se bajen el SDK y se pongan en serio a hacer su proyecto con calma.

Podéis saber más sobre Plain Concepts (Luis Guerrero, Rodrigo Díaz y Ricardo Acosta) y sus desarrollos en la web de Plain Concepts y sus blogs personales.

Les damos las gracias a los tres por concedernos esta entrevista y les deseamos un gran éxito en este y otros proyectos sobre WP7. Estamos seguros que Bye Bye Brain será uno de los juegos más populares del Marketplace de WP7.

ByeByeBrain – Juego de Tower defence de Plain Concepts

Hola a todos, estamos orgullosos de presentar desde Plain Concepts Game Studio, ByeByeBrain. Un juego de tower defence para Windows Phone 7. El juego ha sido desarrollado en XNA usando 3D para el gameplay, con 5 tipos de torretas y 4 tipos de zombines incluyendo un mini juego para los ataques especiales. El juego combina el clásico de defensa de torres con mini juegos y una cámara interactiva durante el juego. Tambien cuenta con integración de Facebook y Twitter para publicar tu puntuación.

Podeis ver un video en Vimeo http://vimeo.com/14723559 y una versión en HD con Silverlight en: http://games.plainconcepts.com/.

También unos fondos de pantalla.

cleaner1920x1200colonel1920x1200fuzz1920x1200nerd1920x1200spanker1920x1200

Algunas cosas interesantes sobre el juego:

· Tiene un sistema de propiedades basado en el de DependencyProperty como WPF y Silverlihgt

· Tiene un sistema de animacions como BeginAnimation y SingleAnimation.

· Approx. 20Mb de fichero XAP.

· 61139 lineas de codigo (Visual Studio 2010 metric system)

· El juego ha sido desarrollado en tres localizaciones diferentes durante los 2 meses de desarrollo

· Uno de los miembros es adicto a los donnetes

Luis Guerrero.

Logo desbloqueado – Nuevo geek a bordo, Rodrigo Díaz

Aprovechando la noticia del Windows Phone 7 y de Plain Concepts Game Studios, me gustaría presentar a Rodrigo Díaz un geek que se ha incorporado al departamento de juegos de Plain Concepts.

Rodrigo es un experto de XNA y nos ayudará al desarrollo de juegos para Windows Phone 7, aquí os dejo su blog para le echéis un vistazo, está hecho un crack 🙂

http://blog.r2d2rigo.es/

Bienvenido Rodrido!

Primer dispositivo de Windows Phone 7 en Plain Concepts

Hola a todos!

Ya tenemos teléfono de Windows Phone 7 en Plain Concepts, hoy mismo lo hemos recibido de Fedex. Es de la marca LG y parece que a todos los que estamos desarrollando para WP7 tenemos el mismo modelo.

El teléfono arranca es unos escasos 10 segundos desde que le das al teléfono hasta que aparece la lista de Tiles disponibles o la pantalla para introducir el pin, es impresionante la velocidad. Por lo demás muy chulo todo, el correo se configura súper rápido, la cuenta de Facebook y todo lo demás.

Para sincronizarlo con el PC el software de Zune, una versión que tenemos la gente que estamos en el TAP de WP7 y además puedes activarlo para ejecutar tus aplicaciones en él. Hay algunas aplicaciones en el marketplace de ejemplo y puedes depurar directamente en el dispositivo.

Os adjunto algunas fotos!.

_DSC0841_DSC0842_DSC0843_DSC0844_DSC0845_DSC0846_DSC0847

Por cierto también me gustaría presentaros, http://games.plainconcepts.com/ el nuevo departamento de desarrollo de video juegos de Plain Concepts.

Saludos.

Luis Guerrero.

Como acceder al teclado nativo en una aplicación XNA de Windows Phone 7

Una de las mejores de desarrollas aplicaciones en XNA es que tienes acceso al dibujado de bajo nivel para dibujar sprites y mayas 3d, pero en ocasiones necesitas objetos de alto nivel que proporcionen una funcionalidad específica, es el caso del teclado.

Si estamos desarrollando una aplicación de Windows Phone 7 en XNA y queremos empezar una nueva partida y queremos obtener el nombre del usuario tenemos que crear nuestro propio teclado. Esto puede ser un poco complicado hacerlo, es por eso que Microsoft ya incluye una API que nos permite invocar una Task dentro del teléfono para pedir datos al usuario.

image

Guide.BeginShowKeyboardInput(
       PlayerIndex.One,
       "You Win",
       "Insert your name",
       "",
       new AsyncCallback(OnEndShowKeyboardInput),
       null);

Con este código lo que estamos haciendo en invocar asíncronamente a la tarea del teclado, hay que tener en cuenta que la aplicación se desactivará en esta ejecución y el código que tengas en el evento se ejecutará. Una vez que el usuario termina de escribir su nombre y hace tap en aceptar volvemos a la aplicación.

image

private void OnEndShowKeyboardInput(IAsyncResult result)
{
   name = Guide.EndShowKeyboardInput(result);
}

Aquí tenemos el string que el usuario ha escrito.

Os podéis descargar una demo desde aquí.

Luis Guerrero.

Silverlight 4 Metro Training (7/7) Dashboard de administración de eventos

Hola a todos!

El día 7-8 de abril se celebró una formación de Silverlight 4 del programa Metro de Microsoft que impartí, así que os dejo las grabaciones del evento y el material.

Silverlight 4 Metron Training,

Dashboard de administración de eventos

 

Install Microsoft Silverlight

 

 

El resto del material:

 

Código fuente de los Labs aquí.

Saludos.

Luis Guerrero.

Silverlight 4 Metro Training (6/7) Impresión

Hola a todos!

El día 7-8 de abril se celebró una formación de Silverlight 4 del programa Metro de Microsoft que impartí, así que os dejo las grabaciones del evento y el material.

Silverlight 4 Metron Training,

Impresión

 

Install Microsoft Silverlight

 

 

El resto del material:

 

Código fuente de los Labs aquí.

Saludos.

Luis Guerrero.

Silverlight 4 Metro Training (5/7) Programador de tareas

Hola a todos!

El día 7-8 de abril se celebró una formación de Silverlight 4 del programa Metro de Microsoft que impartí, así que os dejo las grabaciones del evento y el material.

Silverlight 4 Metron Training,

Programador de tareas

 

Install Microsoft Silverlight

 

 

El resto del material:

 

Código fuente de los Labs aquí.

Saludos.

Luis Guerrero.