miércoles, 31 de diciembre de 2008

Una dudilla sobre C#

Hola… a punto todos para comernos las uvas????

Antes de que lo hagáis y os lanceis luego a brindar con cava por el nuevo año, y una cosa lleve a la otra y no esteis en condiciones, digamos de… pensar mucho, a ver si alguien me sabe responder una dudilla que me ha surgido hoy.

¿Porque este código no compila?

public class Foo
{
public string Name { get { return string.Empty; } }
public string Name() { return string.Empty ; }
}

Por si alguien (como yo) se pensaba que eso compilaba, pues no. Visual Studio se queja con un claro y explícito error CS0102: The type 'ConsoleApplication232.Foo' already contains a definition for 'Name'.


Alguien sabe el porque de esta limitación? Es decir, porque han evitado que podamos hacer esto? Alguien tiene alguna idea?


Epa!!! Buen año a tod@s y que el 2009 os sea lo más propicio posible!!!! Y no os comáis las uvas antes de tiempo! Recordad que el último minuto de este 2008 tiene un segundillo de más!!! xD


Para variar esto es un crosspost desde mi blog en geeks.ms

miércoles, 24 de diciembre de 2008

Mi carta a los reyes…

Aunque sería para unos reyes que pasaran más allá del 2010, pero bueno… por pedir que no quede :P

Estas son las cosas que me gustaría que algun dia se incorporasen a C#. Como son fiestas mágicas, pues aquí van para ver si los chicos de Redmond se animan y para algún milenio las tenemos…

Pongo ideas al margen de si son posibles/factibles con el CLR actual… simplemente son cosas que me gustarían que estuviesen en el lenguaje. Solo pongo las ideas y un ejemplo de lo que me gustaría, sin desarrollarlas a fondo… :)

1. Conceptos en genéricos

La idea es poder representar como restricción de un tipo genérico algo más allá que una interfaz. Por ejemplo:

concept HasHandle
{
IntPtr Handle{ get; }
}

class Foo
{
public static void Main(string[] args)
{
new Foo().Bar(new Form());
}

public void Bar<T> (T t)
where T : HasHandle
{
DoWork(t.Handle);
}
}

Este código deberia compilar porque el concepto HasHandle define una propiedad llamada Handle de tipo IntPtr. El mètode genérico Bar<T> utiliza esta propiedad. Y la llamada a Bar con un paramétro Form satisface el concepto, puesto que la clase Form tiene una propiedad IntPtr llamada Handle.


Los conceptos deberían poder ser genéricos a su vez:

concept HasXXX<T>
{
T XXX{ get; set;}
}

class Foo
{
public void Bar<T,U> (T t)
where T : HasXXX<U>
{
U u = t.XXX;
}
}

El método Bar<T,U> debería poder llamarse con cualquier tipo T que tuviese una propiedad U XXX {get; set;}


Los conceptos deberían poder hacer referencia a la existencia de métodos estáticos:

concept Comparable<T>
{
bool operator > (T t1, T t2);
}

class Foo
{
void Bar<T> (IEnumerable<T> items)
where T : Comparable<T>
{
}
}

El método Bar<T> debería poder llamarse con cualquier tipo T que tuviese definido el operador ‘>’ (aunque este esté definido de forma estática).


2. Constantes binarias


Pues eso mismo…

int i = 0b00001100;

Fácil, no??


3. Tipos anónimos que puedan implementar una interfaz


Los tipos anónimos tal y como estan ahora sirven para poco más que para LINQ. Sería interesante que pudiesen implementar una interfaz y que pudiesen ser devueltos a través de referencias a dicha interfaz:

interface ISomeInterface
{
int Foo(int);
}

class Bar
{
ISomeInterface Baz()
{
return new ISomeInterface { void Foo(int i) { return i+1;} };
}
}

El tipo anónimo creado en el método Baz, implementa la interfaz ISomeInterface y es devuelto a través de una referencia a dicha interfaz.


4. Referencias const


Al estilo de C++. Mira que esto es simple y útil y no se porque no lo han metido… Para más info: http://www.cprogramming.com/tutorial/const_correctness.html.


5. Enumeraciones con cualquier tipo


Estaría bien que los enums pudieran tener cualquier tipo base:

class Planeta
{
long Diametro { get; set; }
long DistanciaSol { get; set; }
}
enum SistemaSolar<Planeta>
{
Mercurio = new Planeta() { Diametro=4879, DistanciaSol=46000000},
Tierra = new Planeta() { Diametro=12742, DistanciaSol=150000000}
}
class Foo()
{
Bar () { this.Baz(SistemaSolar.Mercurio);}
Baz(SistemaSolar p)
{
if (p.Diametro > 10000) { ... }
}
}

El enum SistemaSolar se define como una enumeración de objetos de la clase Planeta.


El método Foo.Baz acepta como parámetro sólo SistemaSolar.Mercurio o SistemaSolar.Tierra. Pasarle cualquier otro objeto Planeta no debería compilar.


Felices fiestaaaaaaaaaaaaaaaaaaaaaaas!


Bueno… paro ya de pedir cosas, jejeeee… :)


Solo desearos a todos los geeks unas felices fiestas, llenas de alegría, familia, ceros y unos…


… y que el tió os cague muchos regaloooooooooooooooooooooooooooooooos!!!!


Crossposting desde mi blog de geeks.ms

jueves, 18 de diciembre de 2008

Duda metafísica sobre “contravarianza” en delegates

Hola… hoy voy a poner un post sobre una dudilla metafísica que me ha surgido, concretamente relativa a los delegates. Y he pensado… que mejor sitio que ponerla que aquí??? ;-)

Los delegates en C# 2.0 son contravariantes, es decir un delegate a un método que espera un parámetro tipo X aceptará cualquier método que espere un parámetro de cualquier tipo base de X.

Es decir, el siguiente código funciona bien:

delegate void Foo(Derived d);
public class Base { }
public class Derived : Base { }
public class SomeCode
{
SomeCode()
{
Foo foo = new Foo(this.SomeMethod);
}
private void SomeMethod(Base b) { }
}

Todos entendemos la lógica que hay tras ello: al ser todos los objetos Derived, objetos Base, es evidente que cualquier método que trate con objetos Base, lo podrá hacer con objetos Derived, y por ello el método SomeMethod es un destino bueno para el delegate Foo.


Ahora bien, imaginemos que tenemos el siguiente código:

delegate void Foo(Derived d);
public class Base { }
public class Derived
{
public static implicit operator Base(Derived d) { return new Base(); }
}
public class SomeCode
{
SomeCode()
{
Foo foo = new Foo(this.SomeMethod);
}
private void SomeMethod(Base b) { }
}

En este caso el código no compila, el compilador se queja con un No overload for 'SomeCode.SomeMethod(Base)' matches delegate 'Foo'.


La duda metafísica es… creeis que debería compilar? En cierto (lo pongo en cursiva) todos los objetos Derived tambien son objetos Base, puesto que hay definida una conversión implícita de Derived a Base… con lo que podríamos entender que hay una cierta contravarianza.


O creeis que no? Que ya está bien que no compile puesto que el operador de conversión no puede representar nunca una relación is-a y por lo tanto la contravarianza no tiene sentido…


MMmmm… yo reconozco que no estoy 100% posicionado a favor de ninguna opción…


Saludos!


Crossposting desde mi blog en geeks.ms

martes, 16 de diciembre de 2008

El valor de una certificación.

Bueno, aviso: estoy cabreado... y este post será polémico. Quien avisa no es traidor.

Estas últimas semanas me he sacado dos MCPs, en concreto el 70-529 y el 70-549, es decir el MCTS y el MCPD de aplicaciones distribuídas. No voy a hablar sobre si son fáciles o difíciles o si se ajustan a lo que realmente uno se encuentra en el mundo real, no… quiero exponer algo que ya hace tiempo me preocupa y me mosquea a partes iguales. Antes de nada he de decir que no tenía muy claro si escribir este post. Por hastío básicamente... lo digo porque lo que escribiré ahora es, lamentablemente, muy parecido a lo que escribí en mi antiguo blog en la casi-extinta clearscreen (un tick de silencio). Aquí dejo el enlace al post que escribí hará casi tres años, por si a alguien le apetece leerlo.

Antes de hacer ambos exámenes, eché una ojeada a esos pdfs que tienen preguntas parecidas a las del exámen, junto con sus respuestas (¿no hace falta poner nombres, verdad?). Lo que vi fue descorazonador... bueno, lo hubiese sido si no supiera de que va el tema, vamos... ahora ya empieza a resbalarme todo...

El caso del 70-529 es flagrante: todas (y todas significa todas) las preguntas exámen estaban en el pdf. Además éste estaba bastante bien (había algunas preguntas que creo que estaban mal y algunas otras que estaban mal seguro) o sea que alguien simplemente empollándose el pdf se sacaba perfectamente el exámen.

El caso del 70-549 no fue tan brutal. De las 60 preguntas que tenia el exámen había unas 45 que estaban en el pdf (ya veis, aunque no tan brutal sigue siendo lamentable). Eso sí, al menos el pdf del 70-549 estaba un poco peor (tenia más respuestas incorrectas)... aun así, empollándoselo uno aprueba el exámen.

No quiero ni voy a criticar a quien se empolla estos pdfs para sacarse MCPs... quiero criticar a quien permite explícitamente que esto siga así. A quien en mi opinión es el máximo culpable (aunque sea por inacción). Es decir, a Microsoft. Creía que la certificación servía para acreditar unos determinados conocimientos, pero veo que simplemente es otra patética herramienta para hacer dinero. Da igual que la certificación esté tan prostituída que los exámenes se encuentren en internet, mientras la gente siga pagando para hacerlos (donde digo gente también se puede leer empresas que quieran ser pon-aquí-tu-material-preferido certified partner). Anda que no sería fácil evitar estos pdfs teniendo un pool de centenares de preguntas por exámen en lugar de menos de 80 (el pdf del 70-529 tenia menos de 80 preguntas y repito: todas me salieron en el exámen). Y también ir cambiando las preguntas cada cierto tiempo ayudaría. ¿Cuanto le costaría hacer todo esto a Microsoft? ¿Por que no lo hace? Y más preguntas... ¿cómo es posible que determinadas academias ofrezcan un cursillo de pongamos 50 horas tras el cual garanticen tener MCPD? ¿No se suponía que estas certificaciones eran para gente con determinada experiencia? ¿50 horas en un cursillo es esta experiencia?

De ahí el título del post: ¿cuál es el valor de una certificación cuyos exámenes se encuentran (con respuestas incluídas) en internet? ¿Porque debo dedicar esfuerzo y dinero (esos exámenes no son gratis) en sacarme estas certificaciones? ¿Debo seguir jugando a este juego? ¿Hará algo al respecto Microsoft? (esta última pregunta es retórica, lo aclaro por si acaso).

¿Alguna respuesta convincente?

Crossposting desde mi blog en geeks.ms

viernes, 12 de diciembre de 2008

[CatDotNet] Última reunión del año

A toro pasado pero... bueno. Ayer (jueves 11 de diciembre), celebramos la última reunión de CatDotNet en este 2008.

La presentación corrió a cargo de Dani Mora y Sebastià Prat (de la empresa Freelander). El título de la presentación era "Desenvolupament eficient, sòlid i ultra- ràpid en Windows i Web amb el framework/ORM per .NET de DevExpress expressApp (XAF)". Como el título indica la presentación iba del framework XAF, desarrollado por DevExpress, que permite el desarrollo rápido de aplicaciones .NET enlazadas a datos.

Sebastià nos comentó los puntos básicos de XAF y como es la construcción de una aplicación XAF:

  1. Generación del "modelo" lógico (digamos... entidades lógicas) de la aplicación, usando código c-sharp. XAF automáticamente construye la base de datos subyacente, así como todos los formularios (windows y web) necesarios para editar todas y cada una de las entidades lógicas.
  2. Añadir módulos. XAF viene con varios módulos "predefinidos", que simplemente se añaden al proyecto mediante drag-and-drop. Nos mostraron en directo, el módulo de seguridad y el de auditoría.
  3. Personalización de los formularios: añadir, quitar campos y cambiarlos de posición. Todo ello de forma gráfica
  4. Personalización de los controladores. Para cada formulario XAF genera un controlador que tiene la opción de personalizar aun más el formulario, añadiendo opciones custom a la barra de herramientas.

Durante todo el proceso vimos que XAF no genera código, para los formularios: estos realmente se guardan mediante formato XML que en run-time el motor de XAF interpreta y muestra.

En apenas 1 hora y media y contando que lo iban explicando todo, desarrollaron una aplicación (windows y web) para dar de altas charlas y asistentes a las charlas. Solo los administradores podian dar de alta charlas y además cualquier modificación estaba auditada en la BBDD. El aspecto general de la aplicación (pese a usar "todo por defecto") era excelente (evidentemente usa los controles de DevExpress).

Mi opinión: me pareció un muy buen producto, tendrá sus cosillas (comentaron algunas y supongo que se callaron muchas más), pero como dijeron la clave está en no intentar hacer toda la aplicación usando XAF: haz el 90% con XAF y el 10% restante (el 10% ese que hace cosas "raras"), hazlo como quieras e integralo después. Me pareció un framework no de uso totalmente general, si no muy orientado a las "aplicaciones de gestión" (es decir aquellas que "básicamente" manipulan una BBDD)... Pero es evidente que hoy dia hay una gran parte de aplicaciones de este tipo. Yo no conocía el producto y me gustó bastante lo que ví, aunqué comentaron, eso sí, que la curba de aprendizaje era alta (unos 2 meses hasta que se empieza a ser productivo).

Para cualquier aclaración sobre XAF, os podeis poner en contacto con Sebastià. En Freelander hace más de dos años que usan el producto (empezaron con la beta), así que tienen mucha experiencia al respecto! Dado que Sebastià ha puesto su mail en foros de XAF, me permito ponerlo yo aquí también: sebastia_AT_freelander.cc.

Ah sí! Me olvidaba!! Comentaros que todos aquellos que queráis saber que organizamos en CatDotNet, os podeis poner en contacto conmigo!!!

martes, 11 de noviembre de 2008

[Depuración] Generación programática de mini dumps

Bueno… No voy a hablar sobre como fue el DevCamp de este pasado fin de semana en puesto que ya lo han hecho Jordi Nuñez y José Manuel Alarcon. Compartimos buenos momentos, buenos cubatas y buenas charlas.

De todas las charlas que se dieron, me interesa comentar especialmente la que dio Pablo Alvarez, una charla impresionante bajo el título de depurando hasta la saciedad. Aunque contó con apenas 45 minutos destripó a base de bien WinDbg y comentó los distintos escenarios de depuración, especialmente la depuración post-mortem (esto es, cuando el proceso ya ha reventado). Leeros su post y el ppt porque es imprescindible.

¿Y qué quiero comentar yo de la charla de Pablo? Pues bien, en la charla quedó claro que antes de meterse a depurar uno debe tener unos buenos… símbolos. Y no sólo eso sino que evidentemente es necesario tener el dump de la aplicación que ha reventado. Comentó distintas herramientas para generar este dump, pero a mí me interesa comentar un escenario que suele ser muy habitual cuando ponemos aplicaciones en producción: que sea la propia aplicación quien genere este dump cuando se produce un error. En un proyecto donde estoy trabajando tenemos nuestra aplicación desplegada en distintos clientes, y aunque simplemente con el log de excepciones managed cubrimos la mayoría de errores, en algunos casos necesitamos más información. Es ahí donde tener un dump de la aplicación nos es realmente útil.

Bueno… vamos a ver dos maneras de generar un dump para depuración post-mortem. La fácil y la no tan fácil.

La fácil

Os vais a la página de ClrDump y os lo descargáis. ClrDump es básicamente una DLL que podéis llamar desde vuestras aplicaciones .NET para generar dumps. En la propia página encontrareis la información de los métodos y sus firmas para P/Invoke.

P.ej. el siguiente código genera un dump completo cuando se produzca cualquier excepción (managed o nativa) no capturada:

SetFilterOptions(CLRDMP_OPT_CALLDEFAULTHANDLER);
string minidumpFile = string.Format(@"c:\temp\postmortem-{0}.dmp", DateTime.Now.ToString("dd-MM-yyyy"));
RegisterFilter(minidumpFile, MiniDumpWithFullMemory);

Las constantes y las firmas P/Invoke serian:

[DllImport("clrdump.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int RegisterFilter(string FileName, int DumpType);
[DllImport("clrdump.dll")]
static extern Int32 SetFilterOptions(int Options);
private const int CLRDMP_OPT_CALLDEFAULTHANDLER = 0x1;
private const int MiniDumpWithFullMemory = 0x2;

Cuando vuestra aplicación reviente tendréis vuestro minidump (en este caso será bastante grande puesto que volcará toda la memoria del proceso lo que puede dar lugar con facilidad a dumps de más de 100 ó 200 MB).

La no tan fácil

Bueno… ClrDump funciona realmente bien y no se me ocurre ninguna razón para no usarlo, excepto que os guste investigar un poco como funciona la generación de dumps… Si queréis podéis implementaros vuestra propia librería para generar dumps. Para ello nada mejor que C++, la librería dbghelp.dll y para adelante!

Dbghelp.dll es la librería que contiene, entre otras, las funciones de generación de dumps. Aunque Windows tiene una, lo mejor es usar la que viene con las Debugging Tools for Windows. Dado que es una librería unmanaged os recomiendo el uso de C++ (supongo que puede invocarse via p/invoke pero ni me lo he planteado, algunas funciones tienen firmas un poco complejas).

La función clave se llama MiniDumpWriteDump y si veis su información en la msdn podréis comprobar que tiene bastantes parámetros. Esta función es la que hace todo el trabajo de generar un minidump, ahora sólo nos queda saber cuándo llamarla: cuando se produzca cualquier excepción (managed o nativa) no controlada. Para ello debemos usar el método SetUnhandledExceptionFilter. Este método espera un puntero a una función que será la que deba ejecutarse cuando se produzca cualquier excepción no controlada. Es en este método cuando llamaremos a MiniDumpWriteDump.

El método SetUnhandledExceptionFilter espera un puntero a una función que reciba un LPEXCEPTION_POINTERS, eso es un puntero con los datos de la excepción que ha ocurrido. Esos datos se los debermos pasar a MiniDumpWriteDump para que pueda procesar la información.

A modo de ejemplo, he creado una clase DumpHelper, en C++ CLI que permite generar minidumps cuando se produzca una excepción no controlada. La cabecera sería así:

namespace DumpHelper {
    delegate LONG UnhandledExceptionFilterHandler(LPEXCEPTION_POINTERS pException);
    public ref class DumpHelper
    {
        private:
            UnhandledExceptionFilterHandler^ pManagedHandler;
            LPTOP_LEVEL_EXCEPTION_FILTER pFilter;
            LONG UnhandledExceptionFilter(LPEXCEPTION_POINTERS pException);
            void CreateMiniDump( EXCEPTION_POINTERS* pep );
            String^ name;
        public:
            BOOL SetExceptionHandler ();
            DumpHelper(String^ name);
    };
}


Defino un delegate (que contendrá el puntero a función) y simplemente dos funciones públicas: el constructor que espera una cadena (con el nombre de fichero a generar) y el método SetExceptionHandler para activar la generación de minidumps cuando el proceso reviente.

En la parte privada, tenemos la instancia del delegate (pManagedHandler), el puntero a función (pFilter), y dos funciones adicionales: UnhandledExceptionFilter y CreateMiniDump.

La implementación del método SetExceptionHandler es tal como sigue:

BOOL DumpHelper::SetExceptionHandler()
{
    pManagedHandler = gcnew UnhandledExceptionFilterHandler(this, &DumpHelper::UnhandledExceptionFilter);
    pFilter = reinterpret_cast<LPTOP_LEVEL_EXCEPTION_FILTER>(
        Marshal::GetFunctionPointerForDelegate (pManagedHandler).ToPointer());
    SetUnhandledExceptionFilter(pFilter);
    return TRUE;
}

Creamos el puntero pFilter para que apunte a la función UnhandledExceptionFilter del propio objeto DumpHelper. Para ello tenemos que hacerlo usando un delegate y conviertiendo luego el delegate a un puntero nativo usando la clase Marshal. Una vez tenemos el puntero, lo pasamos como parámetro al método de Windows SetUnhandledExceptionFilter. En este punto cuando se produzca una excepción no controlada en nuestro programa se nos llamará al método UnhandledExceptionFilter de nuestra clase DumpHelper. Este método es muy simplemente y simplemente llama a CreateMiniDump:

LONG DumpHelper::UnhandledExceptionFilter(LPEXCEPTION_POINTERS pException)
{
    CreateMiniDump(pException);          
// 0: Que se llame al manejador por defecto de Windows al finalizar
    return 0;

}


Finalmente el método CreateMiniDump es el que realiza todo el trabajo. Para ello llama a MiniDumpWriteDump:

void DumpHelper::CreateMiniDump( EXCEPTION_POINTERS* pep)
{

pin_ptr<const
wchar_t> fname = PtrToStringChars(name);
    HANDLE hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);      
    if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) )
    {  
        MINIDUMP_EXCEPTION_INFORMATION mdei;
        mdei.ThreadId = GetCurrentThreadId();
        mdei.ExceptionPointers = pep;
        mdei.ClientPointers = FALSE;
        MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithFullMemory |
                                                 MiniDumpWithFullMemoryInfo |
                                                 MiniDumpWithHandleData |
                                                 MiniDumpWithThreadInfo |
                                                 MiniDumpWithUnloadedModules );
        BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
            hFile, mdt, (pep != NULL) ? &mdei : NULL , NULL, NULL );
        CloseHandle( hFile );
    }
}


La función simplemente abre un fichero (usando CreateFile) y luego rellena los distintos parámetros de MiniDumpWriteDump para generar el minidump.

El uso de esta librería es muy simple. En vuestra aplicación simplemente añadís una referencia a ella, creáis un objeto DumpHelper y llamáis acto seguido a SetExceptionHandler. El mejor sitio para hacer esto es en vuestro método Main:

class Program
{
static void Main(string[] args)
{
DumpHelper h = new DumpHelper("C:\\temp\\test.dmp");
h.SetExceptionHandler();
// Resto de código…
}
}


Listos! Con esto vuestras aplicaciones ya generarán dumps cuando revienten!

Un saludo… y nos vamos viendo!
Crossposting desde mi blog de geeks.ms.

martes, 28 de octubre de 2008

IoC o el poder de ceder el control

Hablando con colegas de profesión, me he dado cuenta de que muchos de ellos no terminan de comprender el patrón IoC o las ventajas que su uso comporta… Así que sin ánimo de sentar cátedra he decidido escribir este post, por si le sirve a alguien…
IoC, que corresponde a las siglas de Inversion Of Control, agrupa a varios patrones que tienen en común que el flujo de ejecución del programa se invierte respecto a los métodos de programación tradicionales (wikipedia dixit). Generalmente el programador especifica las acciones (métodos) que se van llamando, pero en IoC lo que se especifican son las respuestas a determinados eventos o sucesos, dejando en manos de un elemento externo todas las acciones de control necesarias cuando lleguen estos sucesos.

Un claro ejemplo de IoC se encuentra en el modelo de eventos de Windows Forms. Cuando vinculamos una función gestora a un evento (p.ej. el Click de un Button), estamos definiendo la respuesta a un determinado evento y nos despreocupamos cuando se llamará a nuestra función gestora. Es decir, cedemos el control del flujo al framework para que sea él que llame cuando sea necesario a nuestro método.

Una de las principales ventajas de usar patrones IoC es que reducimos el acople entre una clase y las clases de las cuales depende, y eso cuando queremos utilizar por ejemplo tests unitarios es muy importante (no seré yo quien hable ahora de las ventajas de TDD cuando ya lo han hecho xxx). De los distintos patrones IoC me interesa comentar específicamente dos: Service Locator y cómo podemos usarlo en .NET. Para más adelante dejo Dependency Injection, otra forma de IoC que también es extremadamente útil.

Id a la nevera, coged una Voll-Damm o cualquier otra cervecilla y sentaos que este post es un poco largo…

Service Locator

El objetivo de Service Locator es reducir las dependencias que tenga una clase. Imaginemos una clase, que depende de otras dos clases (p.ej. ServicioSeguridad y ServicioLogin). Podríamos tener un código tal como:

class Client

{

static void Main(string[] args)

{

new Client().Run();
}

private void Run()

{

// En este punto necesitamos objetos de las clases ServicioSeguridad y ServicioLogger

ServicioSeguridad ss = new ServicioSeguridad();
ServicioLogger sl = new ServicioLogger();
//...

}

}

En este punto tenemos un fuerte acople entre la clase Client y las clases ServicioSeguridad y ServicioLoggger. Seguiríamos teniendo este mismo acople incluso aunque utilizáramos interfaces porque deberíamos hacer el "new":

IServicioSeguridad ss = new ServicioSeguridad();

IServicioLogger sl = new ServicioLogger();


Las principales desventajas de esta situación son:
  1. Las clases que implementan las dependencias (en nuestro caso ServicioSeguridad y ServicioLogger) deben estar disponibles en tiempo de compilación (no nos basta con tener solo las interfaces).
  2. El fuerte acople de la clase con sus dependencias dificulta de sobremanera su testing. Si queremos utilizar Mocks para de ServicioSeguridad o ServicioLogger vamos a tener dificultades
El patrón de ServiceLocator soluciona estos dos puntos, sustituyendo las dependencias de la clase Client por dependencias a los interfaces y a un elemento externo, que llamaremos Contenedor encargado de devolver las referencias que se le piden.

Cuando la clase necesita un objeto en concreto, lo pide al contenedor:

IServicioSeguridad ss = container.Resolve<IServicioSeguridad>("servicioseguridad");

IServicioLogger sl = container.Resolve<IServicioLogger>("serviciologger");

El método Resolve devolvería una referencia del tipo especificado en el parámetro genérico de acuerdo con un identificador. Evidentemente falta alguien que cree el contenedor y que agregue los servicios a él. Es decir, en algún sitio habrá algo como:

container = new IoCContainer();

container.Add<IServicioSeguridad, ServicioSeguridad>(new
ServicioSeguridad(), "servicioseguridad");

container.Add<IServicioLogger, ServicioLogger>(new
ServicioLogger(), "serviciologger");

La gran diferencia es que esto no tiene porque estar en la clase Client. Simplemente pasándole a la clase Client una referencia al contenedor, eliminamos todas las dependencias de la clase Client con las clases que implementan los servicios. Y donde creamos el contendor? Pues depende… si estamos en nuestra aplicación, lo podemos crear en el método que inicialice la aplicación, pero si queremos probar la clase Client con tests unitarios podemos crear el contenedor en la inicialización del test…. Y lo que es mejor: rellenarlo con Mocks de los servicios!

Así, nuestro programa podría tener una clase Bootstrapper que crea el contenedor de IoC y lo inicializa con los objetos necesarios:

class Bootstrapper

{

static void Main(string[] args)

{

IIoCContainer container = new IoCContainer();
container.Add<IServicioSeguridad, ServicioSeguridad>(new
ServicioSeguridad(), "servicioseguridad");

container.Add<IServicioLogger, ServicioLogger>(new
ServicioLogger(), "serviciologger");
new Client(container).Run();

}

}

Pero si queremos usar tests unitarios de la clase Client, podemos cambiar los objetos por Mocks fácilmente:

[ClassInitialize]

public static
void Init(TestContext context)

{

container = new IoCContainer();

container.Add<IServicioSeguridad, ServicioSeguridadMock>(new
ServicioSeguridadMock(), "servicioseguridad");

container.Add<IServicioLogger, ServicioLoggerMock>(new
ServicioLoggerMock(), "serviciologger");

}

[TestMethod]

public void TestMethod1()

{

Client c = new Client(container);

c.Run(); // Este método Run usará los Mocks!

}


Fijaos que podemos lanzar tests unitarios sobre la clase Client, sin necesidad alguna de cambiar su código y utilizando Mocks. Además, la clase Client no tiene ninguna dependencia con las implementaciones de los servicios que utiliza, así que no es necesario ni que existan para poder crear la clase Client (sólo necesitamos las interfaces).

Unity

Aunque existen varios contenedores IoC open source para .NET, Microsoft tiene el suyo, también open source, llamado Unity (http://www.codeplex.com/unity/). Unity proporciona soporte para los patrones Service Locator y Dependency Injection.
Para que veais un poco su uso he dejado un proyecto de herramienta de línea de comandos para listar los ficheros de un directorio (vamos un dir, jejejee…. :P).

La solución está dividida en varios proyectos:
  1. DemoIoC: Contiene el Bootstrapper, la clase que inicializa el contenedor de Unity, agrega la clase llamada ServicioFicheros y utiliza un objeto Cliente para realizar las acciones de la línea de comandos.
  2. Cliente: Contiene la implementación de la clase Cliente.
  3. Interfaces: Contiene las interfaces del servicio (en este caso sólo una)
  4. Implementations: Contiene las implementaciones del servicio (en este caso sólo una)
  5. Mocks: Contiene las implementaciones de los Mocks (en este caso sólo una)
  6. UnitTests: Contiene tests sobre la clase Cliente, usando un Mock del servicio ServicioFicheros.
El ejecutable (proyecto DemoIoC, assembly DemoIoC.exe) es un archivo de línea de comandos que acepta dos parámetros:
DemoIoC –l para listar todos los ficheros (del directorio actual)
DemoIoC –e:fichero.ext Indica si el fichero "fichero.ext" existe (en el directorio actual).
Si lo ejecutáis veréis que NO funciona bien: lista los ficheros correctamente, pero devuelve que un fichero existe cuando no es cierto y viceversa. Si miráis el código de la clase Cliente, encontrareis el error, ya que es obvio, pero lo bueno es que el proyecto UnitTest, testea este método de la clase Cliente, usando un Mock del ServicioFicheros y el UnitTest detecta el error. Observad lo fácil que ha sido sustituir el ServicioFicheros por un Mock sin alterar la clase Cliente, gracias al uso del patrón Service Locator!
Saludos!!!
PD: Estooo... que me dejado de adjuntar el código de ejemplo!! :P Lo encontrareis aquí! :)

Referencias

Os dejo algunas referencias para su lectura por si os interesa profundizar un poco en el tema tratado:

martes, 21 de octubre de 2008

[WCF] Y finalmente, llegó el cliente!

Jejejee... pues sí! Finalmente veremos como crear un cliente para nuestros servicios WCF. En las sesiones anteriores, hemos visto como crear un servicio, configurarlo y hospedarlo. Pero de què serviria todo esto sin un cliente que consuma el servicio? Sinceramente para muy poco, así que vamos a ver como en un plis-plas creamos un cliente que se conecte a nuestro servicio...
Para este post voy a suponer que partimos de una solución que tiene ya tres proyectos:
  • Una WCF Service Library, es decir una dll con el código del servicio
  • Una console application con el servidor
  • Una winforms application con el esqueleto inicial del cliente.
El código para esta solución inicial lo podeis encontrar en: http://cid-6521c259e9b1bec6.skydrive.live.com/self.aspx/BurbujasNet/Wcf1/ServiciosCalculo|_INICIAL.zip

Si cargais la solución en VS2008, vereis los tres proyectos. Si les echais una ojeada observareis que:
  1. El proyecto ClienteCalculo solo tiene el formulario creado, sin código (lógico, es lo que vamos a hacer)
  2. El proyecto ServiciosCalculo tiene el código servicio (la interfaz y la clase que la implementa). El fichero de configuración del servicio no está en este proyecto
  3. El proyecto Servidor, tiene el código para hospedar el servicio, así como el fichero de configuración del servicio que indica los endpoints que tiene nuestro servicio. Si os fijais el proyecto de Servidor tiene una referencia al proyecto ServiciosCalculo.
Ahora estamos listos para empezar a codificar el cliente...
El primer paso será agregar una "Service Reference" desde el proyecto del cliente hacia el servidor. Para ello, haceis click con el botón derecho en el nodo "references" i le dais a "Add Service Reference". Esto nos despliega un cuadro de diálogo donde básicamente Visual Studio nos pregunta la URL en la que está corriendo el servicio.
Porqué necesita Visual Studio que el servicio esté corriendo? Muy fácil: para poder descargarse el archivo de metadatos que todo servicio WCF expone y que le permite a Visual Studio generar el proxy de forma automática. Bueno, dado que necesitamos que esté corriendo el servicio, vamos a poner en marcha el Servidor. Os vais a la carpeta bin\debug\ del proyecto Servidor y ejecutais Servidor.exe (jejeje.... si no habiais compilado la solución cerrad el cuadro de dialogo y compiladla ;-)). Ahora sí, con el servidor corriendo, os vais de nuevo al Visual Studio, y entrais la URL donde está el servicio (fijaos que el Servidor os dice la URL por la cual escucha el servicio). Si todo ha ido bien (que es de esperar que sí), Visual Studio os mostrará información sobre el servicio (básicamente que métodos tiene):
Entrad el namespace en el que quereis que se generen las clases proxy (p.ej. CalculadoraService) y cuando le deis a "Ok" visual studio generará las clases para poder acceder a nuestro servicio.
Que es lo que ha hecho visual studio en este punto?
  1. Ha generado unas clases proxy (dentro del namespace que nosotros le hemos dicho) para poder acceder al servicio wcf
  2. Ha añadido o modificado el fichero app.config de la aplicación cliente, para añadir la configuración WCF necesaria.
El segundo punto igual os sorprende: no estaba la configuración en el servidor? La respuesta es que está en los dos lados: en el servidor se definen todos los endpoints que soporta el servicio, mientras que en el cliente se define cual de los endpoints queremos usar.
Una vez generado todo esto, lo que queda es trivial: basta con usar las clases generadas dentro del namespace que le hemos indicado para llamar al servicio, como si de una llamada normal a .NET se tratara.
Por ejemplo, en el evento click del boton de sumar vinculais el método:
private void CmdSuma_Click(object sender, EventArgs e)
{
    double op1 = Double.Parse(txtOp1.Text);
    double op2 = Double.Parse(txtOp2.Text);
    // LLamamos al servicio
    ClienteCalculo.CalculadoraService.CalculadoraClient srv =
        new ClienteCalculo.CalculadoraService.CalculadoraClient();
    double resultado = srv.sumar(op1, op2);
    txtResultado.Text = resultado.ToString();
}
Fijaos como instanciamos la clase "CaluladoraClient" (la clase proxy generada por visual studio) y llamamos a sus métodos (en este caso sumar) que son los definidos en la interfaz del servicio.
Para probarlo, poneis en marcha el Servidor y ejecutais el cliente... y listos!

Evidentemente nos han quedado cosas por ver (como llamadas asíncronas)... ya iremos profundizando un poco más en WCF, pero de momento... ya tenemos lo básico!!! :)
Saludos!
PD: El código final lo teneis en http://cid-6521c259e9b1bec6.skydrive.live.com/self.aspx/BurbujasNet/Wcf1/ServiciosCalculo|_FINAL.zip (jejejeee... el cliente no está completado, eh? sólo suma, pero vamos el resto es trivial...).

martes, 14 de octubre de 2008

[WPF] Library project file cannot specify ApplicationDefinition element

Imagina la siguiente situación: Tienes un proyecto en WPF, con varias ventanas o controles WPF creados, y de repente te da por reorganizarlo todo un poco. Así, que añades un proyecto de tipo "Class Library" a la solución, y luego arrastras desde el Solution Explorer, algunas de las ventanas y/o controles al nuevo proyecto.
Cuando más o menos lo tienes todo, le das a compilar y Visual Studio se queja con dos errores:
  • error MC1002: Library project file cannot specify ApplicationDefinition element.
  • error BG1003: The project file contains a property value that is not valid.
Además aunque le des doble-click en la ventana de errores, Visual Studio no está dispuesto a decirte en que línea o al menos que fichero es el causante de los dos errores.
El error se produce cuando al arrastrar los controles xaml al nuevo proyecto, Visual Studio cambia la "Build Action" de los controles que hayas arrastrado de "Page" a "ApplicationDefinition", y una librería no puede tener ningún control o ventana xaml con "ApplicationDefinition". Así pues, seleccionas en el "Solution Explorer" los ficheros xaml que hayas arrastrado (si arrastras más de un archivo te los cambia todos) y en propiedades, pones "Build Action" a "Page"... y listos!
Saludos!
PD: El fichero que tiene la Build Action como "ApplicationDefinition" es aquel que proporciona el punto de entrada de la aplicación y por lo tanto solo es válido en ejecutables (suele ser el App.xaml).
Crosspost desde mi blog de geeks.ms.

viernes, 10 de octubre de 2008

[Catdotnet] Ya pasó El Guille por Igualada :)

Bueno... ya pasó El Guille por Igualada, en la sexta etapa de la Guille Community Tour.
La verdad es que para un grupo de usuarios como CatDotNet fue un honor que un ponente de su categoría, se acercara a hacernos una visita, y deleitarnos a todos con su magnífica presentación sobre las novedades que trae Visual Basic 2008 (o VB9), amenizada con numerosas bromas y simpáticos ejemplos. Nos contó la anécdota de "MiAmiguito" con el fondo rosa que menciona Jose Luis Latorre, pero nuestro proyector funcionaba bien, así que no pudimos verla, jejejeee... :P
Como no podía ser menos batimos todos los récords de asistencia, con unas 35 personas más o menos, y El Guille demostró porque es uno de los mejores ponentes de toda España.
En fin, fue una magnífica presentación (como no podía ser menos)... solo aprovechar para decir que si hay alguien de Igualada o cerquita, o simplemente interesado en saber qué movidas vamos organizando, que se ponga en contacto conmigo o con Jose Luis Torres y vamos hablando!!!!!
Nos vemos!!!!
PD: Uuuuups.... no tengo las fotos a mano ahora, pero tan buen punto las tenga, colgaré algunas para que podais verlas ;-)
(Crossposting desde geeks.ms)

martes, 7 de octubre de 2008

[Catdotnet] El Gulle en Igualada

Hola a todos!
Sólo una reseña, para comentaros que "El guille", uno de los MVPs más antiguos y autor de uno de los portales más visitados de desarrollo en .net, se pasará este jueves 09 de octubre para Igualada, en el marco de su gira "Guille Community Tour 2008".
No hay que decir que se trata de una oportunidad única para poder ver a uno de los mejores ponentes de la actualidad, quien nos presentará todas las novedades de la última versión de Visual Basic...
¿Te lo vas perder?
Cuando: Este jueves (09/10/2008) a las 19:00
Donde: Centre d'atenció a les empreses (Av Mestre Muntaner 86 - Igualada)

jueves, 25 de septiembre de 2008

[WCF] Hospedando servicios

Bueno... en esta serie de posts sobre esta excitante tecnología que es WCF, hemos visto como crear un servicio, y como configurar un servicio usando el fichero de configuración.
Pero un servicio por si sólo no es nada: estaría bien que tuviese al menos un cliente (porqué si no es posible que se sienta un poco inútil). Vale, vale... aceptamos pulpo como animal de compañía, un servicio puede vivir sin ningún cliente pero lo que no me podeis negar es que lo que sí que necesita forzosamente es un servidor que lo acoja en su seno proceso.
Sí: los servicios en esto son como los virus: si no hay alguien que los hospede, son totalmente inútiles :)


Vale, tenemos claro que necesitamos hospedar nuestro flamante servicio pero... donde? Necesitamos comprar un "servidor de servicios" ? Podemos usar IIS? No lleva VS ningún servidor de piltrafilla que nos sirva en desarrollo? Pues (como ya viene siendo habitual en el mundo Microsoft) hay muchas maneras de enfocar la historia...


En general, el proceso que hospeda un servicio WCF es, básicamente, el CLR. Esto viene a significar que cualquier proceso .NET puede hospedar un servicio. Sí, sí: he dicho cualquier proceso. Una aplicación winforms? Pues sí. Una aplicación de línea de comandos? Pues también. Y claro está IIS también es una opción disponible, al igual que un servicio windows. Entonces? Bueno, decidir como hospedamos nuestros servicios es una decisión que se toma basándose en los requerimientos y en la arquitectura global de la solución. Cada sistema tiene sus ventajas y sus inconvenientes.
Por ejemplo, si usamos un ejecutable (sea winforms o linea de comandos), evidentemente el dicho ejecutable debe estar en marcha para que nuestros servicios esten disponibles. Esto invalida entornos desasistidos donde no habrá nadie para "poner en marcha" nuestro host, en estos entornos será mucho mejor un servicio windows. Por otro lado los hosts que son ejecutables estándar, son muy fáciles de crear y de depurar. De hecho no es extraño que durante el desarrollo, se use un servidor que sea un ejecutable, para migrar a un servidor "real" en una fase final.


Y... IIS? Hombre, pues claro. IIS puede hospedar servicios. Además, seguramente, es el mejor hosting posible, ya que si IIS sabe hacer algo és hospedar cosas y servirlas a sus clientes. Y que ventajas nos aporta IIS? Pues varias y muy importantes, entre las que destacaríamos temas de monitorizacion, activación del servicio on-demand y reciclaje de procesos. Estos temas deben "codificarse" a mano si uno opta por un host propio, mientras que en IIS nos vienen de serie. Además IIS es eficiente y altamente escalable... que razón para no usarlo? Lamentablemente podría haber una... Que pasa si mi transporte NO es http ó https? Sabe gestionar otros protocolos de transporte nuestro querido IIS? La respuesta, como todo es... depende.


Tienes XP y tienes un servicio que no usa http(s) como transporte? Pues lo siento, pero NO puedes usar IIS como hosting: En XP y 2003 IIS sólo soporta servicios con transporte http(s). Por otro lado si tienes Vista o 2008 entonces... entonces estás de suerte: WAS viene en tu ayuda!


Estoooo... WAS? Que narices es WAS? No hablábamos de IIS? WAS es el acrónimo de "Windows Activation Services", que es un nuevo sistema de activación de procesos, disponible sólo de Vista para adelante. IIS7 usa internamente WAS, para cualquier tipo de servicio (sea http(s) o no). Pero IIS7 no es un requisito de WAS, es decir podemos tener WAS sin IIS7 y hospedar cualquier tipo de servicio y no usar IIS7 a menos que lo necesitemos para otras cosas (p.ej. ASP.NET). Y no os preocupeis por las ventajas que nos ofrecía IIS7 (reciclaje de procesos, activación on-demand, etc): WAS también las ofrece (recuerdo: IIS7 usa WAS internamente).


Así, tendriamos las siguientes opciones:
  • Ejecutable (winforms o consola): Sencillo, fácil y útil en etapas de desarrollo. No apto en producción.
  • Servicio Windows: Única opción para hospedar servicios que no usen http(s) en XP y 2003.
  • IIS 5.1 ó 6 en XP y 2003: Ideal para todos los servicios que usen http(s). Ganamos todas las ventajas que nos ofrece IIS.
  • WAS: Ideal para cualquier servicio, pero requiere Vista, 2008 o posterior. Ganamos todas "las ventajas de IIS"... sin necsidad de tener IIS.
  • IIS7 en Vista o 2008: Ideal para cualquier tipo de servicio. Tenemos todas las ventajas de IIS y además permite interoperar nuestros servicios WCF con ASP.NET.
Una vez visto el abanico de opciones disponibles para hospedar nuestros servicios, vamos a ver un ejemplo de como hospedar un servicio WCF, usando la aplicación más simple posible: una aplicación de linea de comandos.


Para hospedar un servicio se usa la classe ServiceHost. El constructor de esta clase espera un parámetro que es un objeto Type con la información de la clase que implementa el servicio. Por ejemplo, si tengo la clase CalculadoraService que me implementa un servicio, para ponerlo en marcha, debo construir un ServiceHost y abrir el canal de comunicaciones:
ServiceHost shCalc = new ServiceHost(typeof(CalculadoraService));
shCalc.Open();
// ....
shCalc.Close();
 
Y listos! Esto es todo! Esta es la manera más simple de poner en marcha un servicio. El servicio utilizará los endpoints que haya definido en el fichero de configuración de la aplicación host.
Evidentemente con la clase ServiceHost podemos personalizar más el proceso de hosting, por ejemplo podemos configurar endpoints programáticamente (en lugar de usar el fichero deconfiguración).

Bueno.... ya sólo nos queda ver una cosilla para cerrar el círculo de esa introducción de WCF: Sí, sí... el cliente!


Saludos!

    miércoles, 3 de septiembre de 2008

    Catdotnet - Este viernes... de lujo!

    Pues sí!
    Este viernes, en catdotnet nos vestimos de gala! La razón?


    Muy fácil, tendremos una sesión de un autentico crack: Miguel Llopis, flamante vencedor de la última ImagineCup, estará en Igualada, para poner un poco de luz en todo lo que significa y es Oslo y el paradigma de SaaS.


    Además, para redondear el dia, Jordi Bonilla, nos ofrecerá una interesante charla sobre  software y servicios, los paradigmas SaaS y S+S... en fin, el complemento ideal a la charla de Miguel.


    Donde?
    En el Centre de Serveis a les empreses en Igualada (Av Mestre Muntaner 86).


    Cuando?

    Este viernes 05/09/2008 a las 19:00


    No falteis!! Os esperaaaaaaaaaaaaaaaaaaamos!!


    Editado el 15/09/2008: En la página de catdotnet, teneis la presentación de Miguel Llopis para que os la descargueis!

    jueves, 7 de agosto de 2008

    Y me voy a geeks!

    Buenas :)
    Este post es para deciros que  abro un blog en geeks.ms, una de las comunidades de blogs tecnológicos más importantes sobre tecnologías Microsoft en castellano.

    Es la muerte de este blog? No pues haré crossposting de uno a otro (manualmente, porque no se como hacerlo automáticamente... si alguien lo sabe que me lo diga). Así que este blog sigue vivo, pero si quieres pasate también por mi blog en geeks.ms 


    Un saludo!

    viernes, 1 de agosto de 2008

    [WCF] Configurando mis servicios

    Bueno.... justo empieza agosto, vacaciones y demás, y antes de que decaiga toda la actividad mundial, aprovecho para contaros algo más de WCF... :) La configuración de los servicios.

    En el post anterior vimos como crear un servicio sencillito (ya lo iremos complicando). Lo que hicimos básicamente fueron dos cosas:
    • Definir el contrato del servicio (una interfaz de .NET decorada con ServiceContract).
    • Implementar el contrato (una clase de .NET que implementaba la interfaz)
    Luego vimos que ejecutando el proyecto, Visual Studio nos hospedaba nuestro servicio en un servidor de pruebas y nos permitia probarlo con un cliente de pruebas.

    Pero recordais los primeros posts de esta serie? Los endpoints??? Sí, sí...el ABC de WCF: Address, Binding, Contract... dónde está mi servicio, cómo accedo a él y qué hace el servicio.
    Pues bien, una de las claves de WCF es que el endpoint se define mediante un fichero de configuración (puede hacerse programáticamente, pero esto ahora no nos interesa).

    Es decir, tanto la URI de mi servicio, como el protocolo que usaremos para acceder a él, se define mediante el fichero de configuración... Hoy quieres acceder a tu servicio en http://servidor/servicio1 mediante SOAP en HTTP? Pues lo configuras en el fichero de configuración. Mañana cambias de idea y quieres acceder a tu servicio mediante MSMQ? Pues ningún problema: edita el fichero de configuración. Y listos. No toques ni una línea de código.
    Es por esto que decimos que WCF unifica todas las APIs de comunicaciones existentes hasta el momento.

    El fichero de configuración de WCF es el estándard de .NET (que VS llama app.config), y toda la configuración de WCF se lleva a cabo en la etiqueta <system.serviceModel>.
    Veamos un ejemplo de como puede ser la configuración de UN servicio:


          <service name="ServiciosCalculo.CalculadoraService" behaviorConfiguration="ServiciosCalculo.Service1Behavior">
            <host>
              <baseAddresses>
                <add baseAddress = "http://localhost:8731/Design_Time_Addresses/ServiciosCalculo/Service1/" />
              </baseAddresses>
            </host>
            <endpoint address ="" binding="wsHttpBinding" contract="ServiciosCalculo.ICalculadora">
            </endpoint>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          </service>



    Por un lado dentro de la etieuta "service" tenemos dos etiquetas principales:
    • host: Que nos permite establecer la dirección (URI) base de este servicio
    • endpoint: Que nos define UN endpoint. Recordad que un servicio puede tener MAS de un endpoint
    Dentro del endpoint se definen los tres aspectos principales:
    1. La dirección. Atributo address que contiene una URI relativa a la dirección base establecida en la etiqueta "host".
    2. El binding. Atributo binding que contiene el nombre identificativo del binding que vamos a usar.
    3. El contrato. Atributo contract que contiene el nombre de la interfaz de .NET que representa este contrato.
    En el código de ejemplo vemos que el servicio implementa dos endpoints:
    1. Uno con dirección relativa vacía (o sea que la URI de este endpoint es la misma que la definida en la etiqueta host), con el contrato ServiciosCalculo.ICalculadora (la interfaz que hicimos en el post anterior)
    2. Otro con dirección relativa "mex", con el contrato IMetadataExchange.
    El contrato IMetadataExchange es un contrato que implementan todos los servicios de WCF, y que sirve para que el servicio pueda informar al cliente de sus metadatos (p. ej. los datos del binding o del contrato, para que el cliente sepa a que atenerse... vendría a ser como "la oficina de información" del servicio).

    Si os fijais en el trozo de ejemplo que he puesto, en los dos endpoints los dos bindings que hay son:
    • wsHttpBinding para el primer endpoint
    • mexHttpBinding para el segundo endpoint
    Si os preguntais donde definimos la codificación (binaria, SOAP,...) o el transporte (TCP, MSMQ, HTTP) de estos bindings, aquí no lo vais a encontrar ya que estos bindings son bindings predefinidos de WCF.
    En este post de Maor David podeis encontrar una comparación de los bindings predefinidos de WCF.
    Pero no estamos limitados a estos bindings: un binding es configurable (podemos añadirle o quitarle "elementos") o bien nos podemos crear nuestros propios bindings... pero bueno, esto ya es harina de otro costal. La verdad es que con los bindings predefinidos cubrimos un amplio espectro de necesidades.


    Por último los más observadores habreis visto que la etiqueta "service" del ejemplo, definia un atributo llamado "behaviorConfiguration" (con valor "ServiciosCalculo.Service1Behavior"). Esto sirve para indicar el behavior del servicio... y claro que es un behavior?
    Pues bien, básicamente son datos de configuración del servicio, que NO forman parte de su endpoint. Por ejemplo: si el servicio da una excepción, queremos enviar información detallada al cliente o no? Los behaviors que tengamos se definen con la etiqueta behavior (dentro de serviceBehaviors) y se asocian a los servicios con el atributo que hemos comentado.
    Por, ejemplo un behavior puede se puede definir así:
           <serviceBehaviors>
            <behavior name="ServiciosCalculo.Service1Behavior">
              <serviceMetadata httpGetEnabled="True"/>
              <serviceDebug includeExceptionDetailInFaults="False" />
            </behavior>
          </serviceBehaviors>



    En posts sucesivos veremos más información sobre los behaviors.
    Bien!!!! En el próximo post de la serie veremos como... crear un cliente y conectarnos a nuestros servicios!!!!

    Buenas vacaciones a todos los afortunados que las hagais!!
    Nos leemos! ;-)