[WCF] Pasar información entre las distintas “capas” del servidor

Hola a todos, siguiendo con los artículitos de WCF, os vengo a hablar de una solución que implementamos en un cliente para pasar información a través de su parte servidora sin tener que tocar la firma de los métodos, porque había unos cuantos. Esto se implementó a través del OperationContext que nos ofrece la activación del servicio WCF y la verdad es que funciona de vicio. Pero cómo me dijo un gran crack sobre esto, hay que tener cuidado con el OperationContext porque no deja de ser una sesión de servidor, pero es finita y se sabe en qué momento se invalida y se crea. Os paso a contar el problema que teníamos…

 

El problema

Bueno, el problema era más o menos sencillo, en la solución implementada existían entidades de datos muy, muy, muy pesadas y obtenerlas consumía mucho tiempo de base de datos e impactaba muchísimo en el rendimiento de la aplicación. Cómo la solución tenía una sesión de servidor ya implementada (cosa que ya quitamos), pues se metió una especie de cache que se creaba cuando se iniciaba la llamada al servicio y se destruía cuando se terminaba la ejecución del servicio. Pero estaba construida de aquella manera y cuando se sometió a pruebas de concurrencia… en fin, podría haber salido mejor.

 

¿Qué necesitabamos?

La necesidad era poder pasar las entidades que ya se habían obtenido de un método a otro, o de una capa a otra del servidor, para no tener que volver a obtenerlas una y otra vez. La respuesta clara y más sencilla… pasemos esa información en la llamada a los métodos. Después vimos que había que tocar muchos, muchos, muchos métodos y se descartó por tiempo y esfuerzo 🙁

 

La solución que implementamos

Un compañero muy listo que tengo me dijo “oye, mira a ver si en el contexto de operación puedes pasar información personalizada”, así que me puse manos a la obra y encontré que se puede, vaya si se puede, a través de la interfaz IExtension. La verdad es que se pasa una hashtable (nos encantan las hashtables, tenemos kilo y medio de ellas) con la información que queremos, no es muy bonito, de hecho es feote, pero funciona (esta frase es uno de los peores males en esto de la programación…).

Para hacer esto, creamos una clase que implemente la interfaz IExtension<IContextChannel>, porque queremos almacenar la información en el canal, y tenemos que implementar los métodos “Attach” y “Detach”.

Algo parecido a esto

using System.Collections;
using System.ServiceModel;

namespace TestIExtension
{
public class ExtensionTest : IExtension<IContextChannel>
{
Hashtable mHash = null;

public Hashtable Hash
{
get { return mHash; }
set { mHash = value; }
}

#region IExtension<IContextChannel> Members

public void Attach(IContextChannel owner)
{
if (mHash == null)
{
mHash = new Hashtable();
}
}

public void Detach(IContextChannel owner)
{

}

#endregion
}
}

Pensad que en vez de una hashtable en modo cajón desastre, se puede poner cualquier tipo de información.

Para utilizar esta extensión en vuestro código, para recoger la información o para insertarla tendremos que utilizar el siguiento código:

if (OperationContext.Current != null &&
OperationContext.Current.Channel != null &&
OperationContext.Current.Channel.Extensions != null)
{
TestIExtension testExtension = OperationContext.Current.Channel.Extensions.Find<TestIExtension>();
if (testExtension != null)
{
return cacheExtension.Hash;
}
}

 

Como esta información está “viva” durante toda la activación del servicio, da exactamente igual desde que “capa” llamemos a este código porque siempre estará disponible.

Otra cosa que encontramos que estaba bastante bien, es que aunque los servicios estén en modo Single, esta información se genera en cada llamada al servicio. Cosa totalmente lógica y normal, pero bueno en esto nunca se sabe :).

 

Conclusiones

WCF mola!!!! y el contexto de operación está genial y se le pueden hacer mil y una perrería, pero si me queda una cosa clara es que, la información que necesite un método se le debería pasar siempre por parámetros, vamos que un método debería disponer de toda la información que necesita de forma explícita y así no llevar a ninguna confusión, esto puede no ser cierto en todos los casos, pero en la medida de lo posible la simplicidad ayuda mucho (Keep it simple!!!!).

 

Saludicos.

[MSBuild] Crear y depurar una task personalizada

Hola a todos, vengo a hablar de una cosa que es tan sumamente sencilla que no haría falta escribir sobre ella, pero justamente por eso vamos a describirla. Vamos a crear una task personalizada para que nuestras builds automatizadas del VSTFS las ejecuten por nosotros.

Lo primero sería deciros que las task sirven para casi cualquier cosa que se nos ocurra en nuestras build, en mi caso particular la última vez que hice una era para sustituir un fichero .bat que organizaba unos ficheros de salida y claro con el task realmente hacia lo mismo, pero era más versátil y molaba más.

 

Crear una task

Esto es lo más sencillo, creamos un proyecto de tipo class library (por poner un ejemplo), y añadimos las siguientes referencias:

  • Microsoft.Build.Framework (en mi caso la versión 3.5)
  • Microsoft.Build.Utilities.v3.5

Generamos una clase y la hacemos heredar de “Task” (que se encuentra en Microsoft.Build.Utilities). Realizamos una implementación del método “Execute” de la base y listo, ya tenemos nuestra task personalizada.

Quedaría algo similar a esto,

using Microsoft.Build.Utilities;

namespace TestTask
{
public class HolaNombreTask : Task
{
public override bool Execute()
{
Log.LogMessage("Hola Mario!!!");
return true;
}
}
}

 

Notad que no he usado el hola mundo, he usado hola Mario porque soy un poco egocéntrico (aunque me contento con poquillo)

 

Añadir parámetros obligatorios

Ya tendríamos el task, ahora lo ideal es pasarle algún que otro parametrillo, la forma es igual de fácil, sólo tenemos que añadir una propiedad pública y ya lo tendríamos.

Vamos a añadir un parámetro obligatorio para que se indique un nombre.

Al final el código quedaría cómo sigue,

using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

namespace TestTask
{
public class HolaNombreTask : Task
{
[Required]
public string Nombre { get; set; }

public override bool Execute()
{
Log.LogMessage("Hola " + Nombre);
return true;
}
}
}

Vamos a ver cómo se depura esto a través del visual studio, porque lo que interesa es que se ejecute a través de msbuild, no probar el método que vemos que es muy sencillo y no debería fallar…

 

Depurar task con msbuild

Necesitaremos generar un xml que pueda leer el msbuild y que haga ejecutar nuestra task. Así que creamos un nuevo fichero xml (testtask.xmldebug) con el siguiente contenido

<?xml version="1.0" encoding="utf-8" ?>
<Project DefualtTargets="Debug" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="HolaNombreTask" AssemblyFile = "C:TestTaskbinDebugTestTask.dll" />
<Target Name="Debug">
<HolaNombreTask
Nombre="Mario!!!"
/>
</Target>
</Project>

 

 

A tener en cuenta, el tag “UsingTask” que evidentemente sirve para utilizar una task que esté en el ensamblado que le pongamos, en nuetro caso el que acabamos de generar, y poquito más, creo que está bastante claro el documentito xml.

 

Ahora tenemos que ir a las propiedades de nuestro proyecto, a la “pestaña” Debug y,

  • Marcamos la opción de “Start external program:” y buscamos el MSBuild.exe que normalmente se encuentra en %windir%Microsoft.NETv3.5MSBuild.exe
  • Y en “Command line argumetns” ponemos la dirección dónde se encuentra el fichero xml que hemos generado, en el caso del ejemplo (“C:TestTasktesttask.xmldebug”)
  • Ponemos algún puntico de parada si queremos
  • Pulsamos F5 y ya está…

 

Ya tenemos nuestra task funcionando y depurándola a nuestro gusto.

Como podéis observar es super sencillo generar nuevas task.

 

Un saludico y hasta la próxima.

[WCF] InstanceContextMode.Single y variables globales

Los servicios WCF (esos grandes amiguitos), tiene varios modos de instanciación (PerCall, PerSession y Single), la documentación oficial la podéis encontrar aquí, pero quería hablaros del comportamiento del single.

En mi proyecto actual se decidió cambiar la forma de instanciación de los servicios a Single para ganar rendimiento, y en un principio viendo el coste del cambio, “unas dos líneas de código”(jajajajajaja), se decidió hacerlo. Yo en un principio era un poco escéptico porque conocía como estaba construida la “casa” y en fin… tenía mis dudillas, y la verdad se nos complicó un poco el cambio, os cuento…

 

Un poquillo de culturilla, cuándo se instancia un servicio en modo Single, se crea una única instancia si no existe y si ya existe no se crea nada (lo que viene siendo un Singleton), esto es genial, lo que pasa es que todas las llamadas que haga ese servicio a nuevas clases realmente van a tener una única referencia y no se van a estar creando nuevas clases una y otra vez, vamos que el “new class()” realmente no tiene por qué crear una nueva instancia, si no reutilizar una ya creada. Este comportamiento, totalmente lógico, puede dar algún problema porque no es del todo explícito.

Yo hasta aquí, no le veo más que ventajas, nuestro proyecto actual tenía un montón de problemas de rendimiento porque se generaban muchas llamadas a servicios (bueno esa era una de las muchísimas razones), así que nos pusimos manos a la obra y… zas en toda la boca. De buenas a primeras los servicios no conseguían levantarse, y los que lo conseguían en unas mínimas pruebas de carga empezaron a dar problemas de concurrencia y los que no los daban no funcionaban como tenían que funcionar.

 

Después de los primeros momentos de pánico y miradas asesinas hacia los pobrecillos que hicimos el cambio, nos pusimos a mirar detenidamente y vimos que en nuestras clases de lógica de negocio y acceso a datos se usaban muchas, muchísimas variables globales (no, no, no…chicos malos). El “problema” es que cuando se está trabajando en un servicio en modo Single, cualquiera de sus clases que estén dentro del contexto de la llamada del servicio estarán apuntando a una única referencia y también “están” en modo single, así que a todos los efectos

public class UnaDAL()
{
List<int> listaEnteros = new List<int>();
}

se convierte en algo similar a esto

public class UnaDAL()
{
static List<int> listaEnteros = new List<int>()
}

Pues claro si luego la utilizas sin locks y sin pensar en la concurrencia, esto no funciona.

 

Conclusiones

Todos a una… “Las variables globales son malas”, aunque las generalizaciones son malas, en general no se deberían utilizar salvo en casos realmente necesarios y controlados. Y por otra parte, creo que utilizar los servicios en modo single se tiene que hacer cuándo tú aplicación lo soporta o está medianamente bien diseñada. En nuestro caso actual, estamos trabajando en ello y parece que vemos la luz del túnel y la verdad es que ahora mismo nuestras clases tienen mucha mejor forma y salud… Aunque debo deciros que los primeros momentos de pánico fueron muy graciosos…

 

Un saludico y hasta la próxima.

[WCF] Usar ClientMessageInspector para añadir información a las soapHeaders

Hay ocasiones que queremos pasar información del cliente al servidor, o vicerversa y no queremos cambiar la fachada de nuestros métodos, o bien porque implicaría mucho cambio, o bien porque la información que queremos transportar es una información de “estado” que no tiene sentido que esté en la fachada de nuestros métodos.

Pues esto lo vamos a poder hacer a través de los behavior de los endpoint y de los MessageInspector, que existen de dos clases, los de cliente (IClientMessageInspector) y los de servidor (IDispatchMessageInspector). Y me vais a perdonar porque no tienen que estar necesariamente en cliente o en servidor, pero este es un punto de partida.

 

1.- Definimos una clase que va a ser nuestro MessageInspector y hacemos que implemente la interfaz IClientMessageInspector

   1: namespace ClientInspector

   2: {

   3:     public class ClientMessageInspector : System.ServiceModel.Dispatcher.IClientMessageInspector

   4:     {

   5:         #region IClientMessageInspector Members

   6:  

   7:         public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)

   8:         {

   9:  

  10:         }

  11:  

  12:         public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)

  13:         {

  14:             return Guid.NewGuid();

  15:         }

  16:  

  17:         #endregion

  18:     }

  19: }

2.- En el método BeforeSendRequest, es dónde tenemos que añadir información en las soapHeaders, en el ejemplo vamos a insertar un guid, pero se podría insertar cualquier cosa

   1: public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)

   2: {

   4:     MessageHeader<Guid> mhg = new MessageHeader<Guid>(Guid.NewGuid());

   5:     MessageHeader untyped = mhg.GetUntypedHeader("GuidToken", "gtk");            

   6:     request.Headers.Add(untyped);

   7:     return Guid.NewGuid();

   8: }

 

Ahora mismo tenemos definido el MessageInspector de cliente y lo que hará cuando se llame, lo siguiente es aplicarlo a través de un EndPointBehavior.

3.- Definimos un custom Behavior para que aplique nuestro message inspector, así que creamos una clase que implemente la interfaz IEndpointBehavior

   1: namespace ClientInspector

   2: {    

   3:     public class InspectorBehavior : IEndpointBehavior

   4:     {

   5:         #region IEndpointBehavior Members

   6:         public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)

   7:         {

   8:         }

   9:  

  10:         public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)

  11:         {

  12:         }

  13:             

  14:         public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)

  15:         {

  16:         }

  17:  

  18:         public void Validate(ServiceEndpoint endpoint)

  19:         {

  20:         }

  21:         #endregion        

  22:     }

  23: }

4.- En el método ApplyClientBehavior, es dónde añadimos el MessageInspector que hemos creado en los pasos anteriores

   1: public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)

   2: {

   3:     ClientMessageInspector inspector = new ClientMessageInspector();

   4:     clientRuntime.MessageInspectors.Add(inspector);

   5: }

 

Con esto ya tendríamos el behavior listo y para aplicarlo por código, en una service reference ya creada en nuestro proyecto, tendríamos que añadirlo a la lista de behaviors del EndPoint, un ejemplo de esto sería.

   1: client.Endpoint.Behaviors.Add(new ClientInspector.InspectorBehavior());

 

Con estas tres líneas se puede leer la cabecera que hemos insertado. Esto se haría en la parte “servidora”

   1: //Leer información de las cabeceras

   2: //Recoger la cabecera que ha insertado el behavior

   3: if (OperationContext.Current.IncomingMessageHeaders.FindHeader("GuidToken", "gtk") >= 0)

   4: {

   5:     Console.WriteLine(OperationContext.Current.IncomingMessageHeaders.GetHeader<Guid>("GuidToken", "gtk").ToString());

   6: }

 

Os dejo el código fuente del ejemplito aquí.

 

Ya estaría, aunque faltaría un punto bastante importante, nosotros queremos hacer todo esto a través de un fichero de configuración porque no apetece nada tener que ir por el código añadiendo el behavior a cada service reference que tengamos… ¿verdad?…

 

¿Cómo añadir un behaviorExtension al fichero de configuración?

Bueno pues ese problema también está resuelto heredando de BehaviorExtensionElement.

1.- Añadimos la clase al ejemplito anterior

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Text;

   5: using System.ServiceModel.Configuration;

   6:  

   7: namespace ClientInspector

   8: {

   9:   public class InspectorBehaviorExtension : BehaviorExtensionElement

  10:   {

  11:     /// <summary>

  12:     /// BehaviorType

  13:     /// </summary>

  14:     public override Type BehaviorType

  15:     {

  16:       get { return typeof(InspectorBehavior); }

  17:     }

  18:  

  19:     /// <summary>

  20:     /// CreateBehavior

  21:     /// </summary>

  22:     /// <returns></returns>

  23:     protected override object CreateBehavior()

  24:     {

  25:       return new InspectorBehavior();

  26:     }

  27:   }

  28: }

Con esta clase ya compilada y funcionando, ya podríamos configurar el behavior en el fichero de configuración, aplicarlo al endpoint y quitar la llamada del código que hemos puesto.

Os muestro el fichero de configuración y luego os comento las entradas “especiales” (que no tienen nada de especiales) para que esto funcione. He quitado la parte del binding… porque en este caso no nos preocupa…

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="BehaviorConInspector">
<InspectorExtension />
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="InspectorExtension" type="ClientInspector.InspectorBehaviorExtension, ClientInspector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<bindings>
<ws2007HttpBinding>
<binding name="WS2007HttpBinding_ISampleService" ...>
</binding>
</ws2007HttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8090/SampleService" behaviorConfiguration="BehaviorConInspector"
binding="ws2007HttpBinding" bindingConfiguration="WS2007HttpBinding_ISampleService"
contract="ServiceReference1.ISampleService" name="WS2007HttpBinding_ISampleService" />
</client>
</system.serviceModel>
</configuration>

Aquí las cosas que hemos cambiado son, extensions, behaviors y el endpoint de client.

BehaviorExtension

Lo primero de todo es añadir una behaviorextension que es lo que hemos conseguido haciendo la clase que heredaba de BehaviorExtensionElement (su propio nombre lo indica), eso se añade con

<extensions>
<behaviorExtensions>
<add name="InspectorExtension" type="ClientInspector.InspectorBehaviorExtension, ClientInspector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>

 

Behavior

Hay que añadir un nuevo behavior que tenga nuestra extension para que se ejecute el inspector, como queremos hacer

<behaviors>
<endpointBehaviors>
<behavior name="BehaviorConInspector">
<InspectorExtension />
</behavior>
</endpointBehaviors>
</behaviors>

Aquí además se puede añadir cualquier tipo de configuración asociada a los behavior como se hace normalmente.

 

Client endpoint

Lo último, y bastante importante, es decirle a nuestro endpoint de cliente que utilice ese behavior, porque si no, esto no habría valido para nada 🙂

Para esto, sólo hay que añadir en la configuración de cliente el atributo behaviorConfiguration = “BehaviorConInspector”.

 

Y listo, ya podríamos probar quitando la línea que añade el inspector explícitamente en el código y funcionaría exactamente igual

 

Este post se acabó….

Os dejo el código fuente con esto cambiado aquí, por si queréis comparar.

Cómo habréis podido observar, me he roto los cuernos pensando los nombrecicos así que no lo toméis muy a mal… :). Esto de meter información en las cabeceras de los mensajes mola!!!. En el proyecto actual, lo usamos para quitar una sesión de servidor (sí…es malvada y no permite escalar las aplicaciones… por eso la queríamos quitar), y la verdad es que va muy bien.

 

Saludicos y hasta la próxima.

Producir, producir y producir!!!!

Actualmente, estoy trabajando desplazado en un cliente ayudándoles (o al menos intentándolo) al sacar adelante su aplicación interna de gestión, el trabajo es duro y el tiempo es corto… vamos que estamos en la mejor de las situaciones que imagino que muchos de vosotros, por desgracia, conoceréis.

 

De ahí, el tema del “post”, en una situación como la actual lo que se pide a los desarrolladores es que produzcan, produzcan y que produzcan… y que además lo produzcan bien (bueno esto último es un decir). Para ello nos dan una herramienta maravillosa que se llama Microsoft Visual Studio 2008 y una “bonita” solución de… 200 proyectos (y sí, habéis leído bien 200 proyectos!!!).

 

Nosotros le hemos cogido cariño a la solución y es nuestra “bicha”, y la susodicha tarda aproximadamente 20 minutos en compilar… ¿Os podéis imaginar el tiempo que se pierde para corregir una incidencia?……… MUCHO, de hecho muchísimo… además pierdes la concentración y al final pierdes las ganas de arreglar las incidencias.

 

¿Cómo se ha llegado a esto?

La verdad, no tengo ni idea, yo solo pasaba por allí. Pero hay una mezcolanza de arquitecturas y de formas de dividir una solución que al final hay muchísimos proyectos, todos relacionados entre sí y hasta alguna referencia circular… (sí, ya se que Visual Studio no te deja… pero es que también usamos reflection a cascoporro… así que “si quieres, puedes”).

Yo aquí sólo diría que una vez que nos ponemos a intentar organizar una solución y todos sus proyectos, podemos hacer divisiones de ensamblados funcionalmente, o técnicamente… que podemos dividirlos por “LogicaNegocio”, “CapaDatos”, “Modelo”,…. o por “Compras”, “Proveedores”, “Clientes”… pero por favor no los mezcléis porque si no… terminaréis con una “bicha” y os aseguro que no es para nada bueno…

 

¿Por qué tarda tanto en compilar?

La respuesta es sencilla y tiene dos o tres puntos:

1. Son muchos proyectos

2. Los proyectos tienen muchas referencias del tipo “Proyecto” a los distintos proyectos (redundante ¿eh? :-))

3. Existe algún proyecto excesivamente grande o con un número demasiado grande de referencias

Seguro que existen muchas más razones pero estas son las que se me ocurren a mí…

 

¿Se podría reducir el tiempo de compilación?

Sí, y la primera respuesta que se me viene a la cabeza es… “REUNIFICANDO PROYECTOS”, aunque también se podrían poner las referencias a ensamblados previamente compilados y no tardaría mucho, o intentar redefinir los proyectos con un elevado número de referencias.

 

¿Tiene algún tipo de fundamento reorganizar el código en menos proyectos?

Una vez visto el problema que tenemos en la parte de desarrollo y no olvidando nunca que nuestra función fundamente es producir, producir y producir un poquito más, estuve buceando un poco por Internet y preguntando a algún que otro crá de esto de la informática y al final creo que el sentido común es lo que triunfa.

Así que es mejor tener un proyecto un poco más grande que tener cinco proyectos pequeñitos, y cuándo este número crece mucho, se hace bastante importante, porque:

1. Se reduce el número de proyectos (esto es obvio)

2. Se reduce el número de referencias

3. Se puede evitar el efecto “rebase” (esto no es muy importante cuando se tienen pocos proyectos pero bueno… algo es algo)

4. El JITTER utiliza menos tiempo

5 …

 

Esto viene todo de un bonito sitio que se llama “Microsoft Pattern & Practices” y bueno parece que estos chicos saben un poquillo de esto, os dejo los links que son bastante aclaradores.

http://msdn.microsoft.com/en-us/library/ms998547.aspx#scalenetchapt05_topic33

http://msdn.microsoft.com/en-us/library/ms979052.aspx

 

¿Conclusión?

Bueno la conclusión es sencilla… da igual de qué forma se optimice el tiempo de compilación pero es un tiempo que debería ser nulo o muy pequeño si no queremos que el ritmo de producción se vea alterado por otras causas ajenas a nuestras meteduras de pata. Yo en este cliente en particular intento reducir el número de proyectos.

 

Perdonad por el rollazo, este es mi primer post de lo que espero sea una larga lista de ellos, y no tengo intención de que sean de este tipo si no algo más orientado a ayudas con el código para hacer ciertas cosas, pero es que este tema me tiene comidita la moral y creo que es muy importante que nosotros los desarrolladores no nos muramos cada vez que intentemos compilar una solución.