[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.

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

  1. Hay una cosa que no entiendo bien… esto solo funciona en servidor se supone no… la información que metes en el canal no viaja entre cliente y servidor de WCF ¿no? Si es así (que no estoy seguro)…

    ¿No sería mejor implementar un simple mecanismo basado en una cache global que todos los servicios puedan consultar?… mantener toda esa información en el canal, podría ser tan malo como mantenerla en el contexto… no veo mucha diferencia ¿no?. Pregunto por curiosidad, porque seguro que lo habéis pensado… conste que el post me parece sumamente interesante.

    También se me ocurre que podría ser buena idea implementar un behavior de cache, algo tip lo que comenté en est post: http://geeks.ms/blogs/rcorral/archive/2008/05/31/bricoman-237-a-a-241-adiendo-cach-233-a-nuestros-servicios-wcf.aspx, ¿no crees que ayudaría?.

    ¡Un saludo!

  2. Mario me encanta la solución, por poco intrusivo del código; pero (lo siento tengo que dejarte un pero 🙂 ¿¿¿ HashTables ???

    A mi los diccionarios me ponen un poco malhumorado de 0 a 100 como una Ferrari, ¿porqué? pues por que por lo general con el tiempo te encuentras con almacenamientos del tipo

    ht[0] = Customer
    ht[1] = Bool que define si se procesa en linea
    ht[2] = archivo de configuración
    ht[3] = aqui no se pasa nada, porque el desarrollador se paso de largo un indice
    ht[4] = referencia a ht[1]

    y claro, el código de esta forma se hace imposible de leer y de mantener. Y peor aún cuando, lo querramos o no, las HashTables se convierten en LOS CONTRATOS DE INTERFACES para el trabajo entre 2 partes.

    No puedo decir donde, pero te estoy hablando de gente iluminada que llegaba a trabajar con HybridDictionaries de más de 50 elementos, cada uno de su padre y de su madre.

    Una vez más, no es ataque a la solución porque la verdad es que no conocía esta capacidad de WCF y me parece potente y cojonuda, pero Hashtables … jejeje

    Saludos

  3. Lo primero gracias por comentar… os intento explicar el porqué de la solución, aunque ya os digo que a mí no me terminó de convencer, me encantan las posibilidades de WCF aunque esta… en fin… 🙂

    @Rodrigo: Esto es sólo para servidor, no viaja nada de cliente y lo primero que se planteó fue usar un framework de estos totalmente fiables y geniales para cachear como la EntLib (MODE IRONIC OFF), de hecho se hizo y se cacheó a nivel global y bueno… fue un autentico desastre por cómo estaba hecho el código y las entidades a cachear, así que sólo nos quedaba almacenar la información que se iba obteniendo en cada llamada a lo servicios y después desecharla y la única cosa que se nos ocurrió fue esto. Aunque debo decir que no habíamos pensado en otras soluciones como las que tú dices… es una lástima no tener a Unai siempre a tú lado… que siempre te puede decir algo… 🙂

    @Bruno: HashTables 4ever :-)… creo que me ha faltado poner un MODE IRONIC OFF o algo así, de hecho es de una cosa que nos quejabamos bastante, en el código había entre un kilo y medio y dos kilos de hashtables, para todo… que no se qué tipo pasar… pues hashtable que te crió… y sí… tuvimos muchísimos problemas con el tema de las hashtables. Y coincido contigo en que lo que más me gustó de esto es lo poco intrusivo en el código ya generado. Por cierto dices una cosa que de la que me he quejado mucho, porque en una parte de la solución se pasaban hashtables en modo contrato y claro… eso es un caos…

    La conclusión en mi caso sigue siendo la misma… WCF mola mucho!!!!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *