<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>O bruxo mobile</title><link>http://geeks.ms/blogs/unai/default.aspx</link><description>Grandes historias sobre pequeños dispositivos</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>.NET 4.0 y Arquitecturas orientadas al Dominio</title><link>http://geeks.ms/blogs/unai/archive/2010/03/08/net-4-0-y-arquitecturas-orientadas-al-dominio.aspx</link><pubDate>Mon, 08 Mar 2010 20:04:11 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:169497</guid><dc:creator>Unai</dc:creator><slash:comments>8</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=169497</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2010/03/08/net-4-0-y-arquitecturas-orientadas-al-dominio.aspx#comments</comments><description>&lt;p&gt;El miércoles 24 de Marzo de 2010 se celebra en las oficinas de Microsoft España de Madrid un evento para arquitectos&amp;#160; y desarrolladores en el que como reza el título trataremos de dar una visión profunda de las posibilidades de .NET 4.0 para la creación de arquitecturas basadas en el dominio. La verdad es que llevamos mucho tiempo para la preparación de este evento, puesto que no es un evento tradicional en el que unos cuantos ponentes presentamos unas ppt y contamos nuestra visión del mundo. En este evento nos mojaremos de verdad , y lo haremos porque presentaremos un proyecto completo basado en la ola 4.0 y además acompañaremos el mismo con documentación abundante…, muchos se llevarán una agradable sorpresa.. sobre todo los que vengan :-)&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Espero realmente que os animéis a llenar el evento, el registro &lt;a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032443724&amp;amp;Culture=es-ES" target="_blank"&gt;aquí&lt;/a&gt;, y, para los que no vengáis que colaboréis con la solución, que estara disponible como código fuente abierto para la comunidad, con vuestros comentarios, sugerencias de código, mejoras, problemas etc etc…&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Saludos&lt;/p&gt;  &lt;p&gt;Unai&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=169497" width="1" height="1"&gt;</description></item><item><title>EF 4.0: ¿Que artefacto de generación seleccionamos?</title><link>http://geeks.ms/blogs/unai/archive/2010/03/04/ef-4-0-191-que-artefacto-de-generaci-243-n-seleccionamos.aspx</link><pubDate>Wed, 03 Mar 2010 23:12:52 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:168675</guid><dc:creator>Unai</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=168675</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2010/03/04/ef-4-0-191-que-artefacto-de-generaci-243-n-seleccionamos.aspx#comments</comments><description>&lt;p&gt;Como seguramente todos sabréis una de las ventajas mas acogidas dentro de la comunidad con respecto a EF 4.0 está precisamente en la capacidad de adaptar como queremos que se genere tanto el código de nuestras entidades como el código del contexto de trabajo de EF. Aunque hasta la llegada de VS 2010 por defecto solamente teníamos la opción de generación&amp;#160; de clases prescriptivas, en cada una de las CTP de EF Feature Pack veíamos como disponíamos de&amp;#160; opciones para seleccionar nuevos artefactos como la generación ,POCO ( Plain Old CLR Objects ) o STE ( Selft Tracking Entities ) por medio de plantillas T4 que podríamos llegar a adaptar para satisfacer nuestras necesidades, por muy rebuscadas que fueran. Con el&amp;#160; reciente lanzamiento de VS 2010 RC la plantilla de generación STE la tenemos por defecto como opción, sin tener&amp;#160; que recurrir a la instalación de Feature Pack, por su parte para la generación de clases POCO Microsoft pone a nuestra disposición estas plantillas por medio de una extensión accesible desde el Extension Manager de VS 2010.&lt;/p&gt;  &lt;p&gt;La pregunta realmente para muchos consiste en saber ahora que artefacto de generación seleccionar, cuando decantarnos por objetos POCO, STE o la generación por defecto de clases prescriptivas. Aunque la respuesta no siempre es sencilla quizás este gráfico, salido de &lt;a href="http://msdn.microsoft.com/es-es/magazine/ee335715.aspx" target="_blank"&gt;Danny Simmons&lt;/a&gt;, os resulta atractivo para hacer una valoración respecto a esta selección y aspectos arquitectónicos dentro de la solución, aspectos como integración de clientes no .NET, facilidad en el desarrollo etc…&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/ee335715_5F00_simmons_5F00_figure1enus_5F00_3A6E6573.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;" title="ee335715_simmons_figure1(en-us)" border="0" alt="ee335715_simmons_figure1(en-us)" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/ee335715_5F00_simmons_5F00_figure1enus_5F00_thumb_5F00_17CA26F8.png" width="244" height="235" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;En poco tiempo espero escribir mas largo y tendido sobre este tema … &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Saludos&lt;/p&gt;  &lt;p&gt;Unai&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=168675" width="1" height="1"&gt;</description></item><item><title>EF 4 – Features CTP 2 y VS2010 RC</title><link>http://geeks.ms/blogs/unai/archive/2010/02/12/ef-4-features-ctp-2-y-vs2010-rc.aspx</link><pubDate>Fri, 12 Feb 2010 17:45:36 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:167262</guid><dc:creator>Unai</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=167262</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2010/02/12/ef-4-features-ctp-2-y-vs2010-rc.aspx#comments</comments><description>&lt;p&gt;Para los que estéis probando EF 4 Features CTP tened en cuenta los cambios en VS2010 y la compatibilidad de estas features en la nueva versión de Visual Studio. Si estais usando STE ( Selft Tracking Entities ) ahora están ‘out-of-box’ en VS 2010 RC y por lo tanto no necesitais instalar Features CTP, que además os fastidiaría los nuevos ttinclude y por lo tanto no serían compatibles. Para los que os interesen las plantillas de POCO estas estarán disponibles como extension a VS y por lo tanto descargables automáticamente desde el Extensions Manager de Visual Studio ( tampoco estarán en EF Features ). &lt;/p&gt;  &lt;p&gt;Por lo tanto, que queda en EF FEATURES?? pues solamente la posibilidad de hacer ‘Code Only’…&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Espero que os sirva de interes y que no tengais que reparar la instalación de la RC como un servidor…&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Saludos&lt;/p&gt;  &lt;p&gt;Unai&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=167262" width="1" height="1"&gt;</description></item><item><title>Entity Framework y Specification Pattern</title><link>http://geeks.ms/blogs/unai/archive/2010/02/09/entity-framework-y-specification-pattern.aspx</link><pubDate>Tue, 09 Feb 2010 18:37:42 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:167045</guid><dc:creator>Unai</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=167045</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2010/02/09/entity-framework-y-specification-pattern.aspx#comments</comments><description>&lt;h3&gt;Introducción&lt;/h3&gt; &lt;p&gt;Hace ya unos cuantos dias que vengo dándole vueltas a la cabeza para escribir un post sobre especificaciones y como construirlas sobre la infraestructura de&lt;strong&gt; Entity Framework&lt;/strong&gt;, aunque en realidad sería igual sobre cualquier elemento &lt;strong&gt;IQueryable&lt;/strong&gt;, aunque con alguna nota de implementación. Pensando en esta entrada no sabía si comenzar con una explicación sobre este patrón o ceñirme directamente a una posible implementación,&amp;nbsp; puesto que, me parece magnifica la documentación sobre el mismo que &lt;strong&gt;Fowler&lt;/strong&gt; y &lt;strong&gt;Evans&lt;/strong&gt; tienen en el &lt;a href="http://martinfowler.com/apsupp/spec.pdf" target="_blank"&gt;documento de referencia&lt;/a&gt;. Al final, y despues de darle muchas vueltas me quedaré entre medias puesto que creo que es necesario realizar una pequeña introducción, aunque aconsejo encarecidamente desde aquí leerse el documento anterior si nunca ha visto información acerca de este patrón.&lt;/p&gt; &lt;p&gt;Sintetizándolo, aunque sea demasiada síntesis, podríamos decir que el patrón espeficación trata de lograr una separación entre la sentencia que unos objetos deberían de cumplir y el objeto que realiza la selección. Por ejemplo una especificación podría describir “los clientes que pertenecen a una determinada situación geográfica” pero no saber nada acerca de como realizar dicha selección. En definitiva no se trata nada más y nada menos que agregar una responsabilidad desacoplada de los objetos de dominio que la usan. &lt;/p&gt; &lt;p&gt;Este patrón es muy escuchado y usado en arquitecturas basadas en modelos de dominio y puesto en práctica en muchas arquitecturas para definir “criterios” de selección. Basándonos en la definición formal de este patrón, mostrada en la Figura 1, podríamos ver a primeras que una implementación de este patrón trabajando con IQueryable no tendría mucho sentido.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Specification_5F00_UML_5F00_3BF5884A.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;" title="Specification_UML" border="0" alt="Specification_UML" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Specification_5F00_UML_5F00_thumb_5F00_40F7C5F9.png" width="307" height="193" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;La razón principal de la afirmación anterior viene de la propia definición del patron, la cual implica trabajar con objetos directamente en memoria puesto que el método &lt;strong&gt;IsSatisfiedBy&lt;/strong&gt; tomaría una instancia del objeto en el cual queremos comprobar si cumple un determinado criterio y devolver &lt;strong&gt;true&lt;/strong&gt; o &lt;strong&gt;false&lt;/strong&gt; según se cumpla o no, algo que por supuesto no deseamos por la sobrecarga que esto implicaría. Por todo esto podríamos modificar un poco nuestra definición de Specification para que en vez de devolver un booleano negando o afirmando el cumplimiento de una especificación determinada podríamos devolver una “expression” con el criterio a cumplir. En el siguiente fragmento de código tendríamos un esqueleto de nuestro contrato base con esta ligera modificación.&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Base contract for Specification pattern, for more information&lt;/span&gt;
    &lt;span class="rem"&gt;/// about this pattern see http://martinfowler.com/apsupp/spec.pdf&lt;/span&gt;
    &lt;span class="rem"&gt;/// or http://en.wikipedia.org/wiki/Specification_pattern.&lt;/span&gt;
    &lt;span class="rem"&gt;/// Really this is variant implementation for add feature of linq and&lt;/span&gt;
    &lt;span class="rem"&gt;/// lambda expression into this pattern.&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;typeparam name=&amp;quot;TEntity&amp;quot;&amp;gt;Type of entity&amp;lt;/typeparam&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ISpecification&amp;lt;TEntity&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; TEntity : &lt;span class="kwrd"&gt;class&lt;/span&gt;,&lt;span class="kwrd"&gt;new&lt;/span&gt;()
    {
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Check if this specification is satisfied by a &lt;/span&gt;
        &lt;span class="rem"&gt;/// specific expression lambda&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
        Expression&amp;lt;Func&amp;lt;TEntity, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; SatisfiedBy();
    }&lt;/pre&gt;
&lt;h3&gt;Profundizando&lt;/h3&gt;
&lt;p&gt;Llegados a este punto podríamos decir que ya tenemos la base y la idea de lo que queremos construir, ahora, solamente falta seguir las propias normas y guias de este patrón empezándonos a crear nuestras especificaciones directas o “hard coded specifications” y nuestras especificaciones compuestas, al estilo And, Or …&lt;/p&gt;
&lt;p&gt;Según avanzas en esta aproximación uno se da cuenta de que tendrá que realizar un buen esfuerzo de trabajo con árboles de expresiones, algo en el que no todo el mundo está muy puesto, y a lo que se le tiene algo de miedo, del que uno se puede curar leyendo el &lt;a href="http://shop.campusmvp.com/Product-C-3.0-y-LINQ_1.aspx" target="_blank"&gt;excelente libro&lt;/a&gt; de mi amigo y colega Octavio :-)&lt;/p&gt;
&lt;p&gt;Mi primera intentona, y fallida a mi pesar, era similar a lo siguiente:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// A logic AND Specification&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;typeparam name=&amp;quot;T&amp;quot;&amp;gt;Type of entity that check this specification&amp;lt;/typeparam&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AndSpecification&amp;lt;T&amp;gt;
       : CompositeSpecification&amp;lt;T&amp;gt;
       &lt;span class="kwrd"&gt;where&lt;/span&gt; T : &lt;span class="kwrd"&gt;class&lt;/span&gt;,&lt;span class="kwrd"&gt;new&lt;/span&gt;()
    {
        &lt;span class="preproc"&gt;#region&lt;/span&gt; Members

        &lt;span class="kwrd"&gt;private&lt;/span&gt; ISpecification&amp;lt;T&amp;gt; _RightSideSpecification = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; ISpecification&amp;lt;T&amp;gt; _LeftSideSpecification = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Public Constructor

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Default constructor for AndSpecification&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;leftSide&amp;quot;&amp;gt;Left side specification&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;rightSide&amp;quot;&amp;gt;Right side specification&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; AndSpecification(ISpecification&amp;lt;T&amp;gt; leftSide, ISpecification&amp;lt;T&amp;gt; rightSide)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (leftSide == (ISpecification&amp;lt;T&amp;gt;)&lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;leftSide&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (rightSide == (ISpecification&amp;lt;T&amp;gt;)&lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;rightSide&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;this&lt;/span&gt;._LeftSideSpecification = leftSide;
            &lt;span class="kwrd"&gt;this&lt;/span&gt;._RightSideSpecification = rightSide;
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Composite Specification overrides

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Left side specification&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; ISpecification&amp;lt;T&amp;gt; LeftSideSpecification
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _LeftSideSpecification; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Right side specification&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; ISpecification&amp;lt;T&amp;gt; RightSideSpecification
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _RightSideSpecification; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;see cref=&amp;quot;Microsoft.Samples.NLayerApp.Domain.Core.Specification.ISpecification&amp;quot;/&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;see cref=&amp;quot;Microsoft.Samples.NLayerApp.Domain.Core.Specification.ISpecification&amp;quot;/&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; SatisfiedBy()
        {
            Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; left = _LeftSideSpecification.SatisfiedBy();
            Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; right = _RightSideSpecification.SatisfiedBy();

            InvocationExpression invokedExpr = Expression.Invoke(right, left.Parameters.Cast&amp;lt;Expression&amp;gt;());
            &lt;span class="kwrd"&gt;return&lt;/span&gt; Expression.Lambda&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt;(Expression.AndAlso(left.Body, invokedExpr), left.Parameters);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;


&lt;p&gt;Os podreís imaginar que la especificacion OR era similar a esta, simplemente modificando Expression.AndAlso por Expression.Or. Todo funcionaba de maravilla en mis test contra mi mock de los ObjectSet de Entity Framework hasta que pasando las pruebas de integración me di cuenta que el QueryProvider de Entity Framework no soportaba el método Invoke, al contrario que un QueryProvider sobre objetos en memoria, y que por lo tanto esta forma no me servía :-(.&lt;/p&gt;
&lt;p&gt;Aunque ahora mismo pondré la solución fijaros como, de una forma elegante, manteniendo el principio de separación de responsabilidades y dejando un concepto de negocio como es un tipo especial de búsqueda perfectamente explícito, se podrían declarar especificaciones como la siguiente&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; Seguramente que alguna vez ha pensado como hacer consultas distintas en función de parámetros usando conjunciones o disjunciones de expressiones, pues esta es una posible solución.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// AdHoc specification for finding orders&lt;/span&gt;
    &lt;span class="rem"&gt;/// by shipping values&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; OrderShippingSpecification
        :Specification&amp;lt;Order&amp;gt;
    {
        &lt;span class="preproc"&gt;#region&lt;/span&gt; Members

        &lt;span class="kwrd"&gt;string&lt;/span&gt; _ShippingName = &lt;span class="kwrd"&gt;default&lt;/span&gt;(String);
        &lt;span class="kwrd"&gt;string&lt;/span&gt; _ShippingAddress = &lt;span class="kwrd"&gt;default&lt;/span&gt;(String);
        &lt;span class="kwrd"&gt;string&lt;/span&gt; _ShippingCity = &lt;span class="kwrd"&gt;default&lt;/span&gt;(String);
        &lt;span class="kwrd"&gt;string&lt;/span&gt; _ShippingZip = &lt;span class="kwrd"&gt;default&lt;/span&gt;(String);

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Constructor

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Default constructor for this specification&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;shippingName&amp;quot;&amp;gt;Shipping Name or null for not include this value in search&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;shippingAddress&amp;quot;&amp;gt;Shipping Address or null for not include this vlaue in search&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;shippingCity&amp;quot;&amp;gt;Shipping City or null for not include this value in search&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;shippingZip&amp;quot;&amp;gt;Shipping Zip or null for not include this value in search&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; OrderShippingSpecification(&lt;span class="kwrd"&gt;string&lt;/span&gt; shippingName,&lt;span class="kwrd"&gt;string&lt;/span&gt; shippingAddress,&lt;span class="kwrd"&gt;string&lt;/span&gt; shippingCity,&lt;span class="kwrd"&gt;string&lt;/span&gt; shippingZip)
        {
            _ShippingName = shippingName;
            _ShippingAddress = shippingAddress;
            _ShippingCity = shippingCity;
            _ShippingZip = shippingZip;
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Specification Overrides

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;see cref=&amp;quot; Microsoft.Samples.NLayerApp.Domain.Core.Specification.Specification{TEntity}&amp;quot;/&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;see cref=&amp;quot; Microsoft.Samples.NLayerApp.Domain.Core.Specification.Specification{TEntity}&amp;quot;/&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; System.Linq.Expressions.Expression&amp;lt;Func&amp;lt;Order, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; SatisfiedBy()
        {
            Specification&amp;lt;Order&amp;gt; beginSpec = &lt;span class="kwrd"&gt;new&lt;/span&gt; TrueSpecification&amp;lt;Order&amp;gt;();

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_ShippingName != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                beginSpec &amp;amp;= &lt;span class="kwrd"&gt;new&lt;/span&gt; DirectSpecification&amp;lt;Order&amp;gt;(o =&amp;gt;o.ShippingName!=&lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp;  o.ShippingName.Contains(_ShippingName));

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_ShippingAddress != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                beginSpec &amp;amp;= &lt;span class="kwrd"&gt;new&lt;/span&gt; DirectSpecification&amp;lt;Order&amp;gt;(o =&amp;gt; o.ShippingAddress !=&lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; o.ShippingAddress.Contains(_ShippingAddress));

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_ShippingCity != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                beginSpec &amp;amp;= &lt;span class="kwrd"&gt;new&lt;/span&gt; DirectSpecification&amp;lt;Order&amp;gt;(o =&amp;gt; o.ShippingCity != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; o.ShippingCity.Contains(_ShippingCity));

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_ShippingZip != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                beginSpec &amp;amp;= &lt;span class="kwrd"&gt;new&lt;/span&gt; DirectSpecification&amp;lt;Order&amp;gt;(o =&amp;gt; o.ShippingZip != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; o.ShippingZip.Contains(_ShippingZip));

            &lt;span class="kwrd"&gt;return&lt;/span&gt; beginSpec.SatisfiedBy();

        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;
&lt;h3&gt;Una posible solución para especificaciones And y OR&lt;/h3&gt;
&lt;p&gt;Os podreís imaginar que seguramente existe más de una aproximación para este tema y que yo probablemente me haya decantado por una aproximación algo dura, pero la verdad es que me parecía la más adecuada. Releyendo algún post sobre el tema me acorde de la serie que &lt;a href="http://blogs.msdn.com/mattwar/pages/linq-links.aspx" target="_blank"&gt;Matt Warren&lt;/a&gt; tenía sobre el tema y como hacía uso del patrón &lt;strong&gt;Visitor&lt;/strong&gt; para evaluar las expresiones, &lt;a href="http://msdn.microsoft.com/en-us/library/system.linq.expressions.expressionvisitor(VS.100).aspx" target="_blank"&gt;ExpressionVisitor&lt;/a&gt;. Además, navegando, me encontré con un ejemplo aceptable que resolvía este tema en el blog de &lt;a href="http://blogs.msdn.com/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx" target="_blank"&gt;Colling Meek&lt;/a&gt; el cual fué la solución que adopte. &lt;/p&gt;
&lt;p&gt;Dada la explicación, lo que necesitamos es la siguiente clase que nos haga una recomposición de las expressiones en vez de un InvocationExpression, esta clase de apoyo es la siguiente:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Extension methods for add And and Or with parameters rebinder&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ExpressionBuilder
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Expression&amp;lt;T&amp;gt; Compose&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; Expression&amp;lt;T&amp;gt; first, Expression&amp;lt;T&amp;gt; second, Func&amp;lt;Expression, Expression, Expression&amp;gt; merge)
        {
            &lt;span class="rem"&gt;// build parameter map (from parameters of second to parameters of first)&lt;/span&gt;
            var map = first.Parameters.Select((f, i) =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; { f, s = second.Parameters[i] }).ToDictionary(p =&amp;gt; p.s, p =&amp;gt; p.f);

            &lt;span class="rem"&gt;// replace parameters in the second lambda expression with parameters from the first&lt;/span&gt;
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
            &lt;span class="rem"&gt;// apply composition of lambda expression bodies to parameters from the first expression &lt;/span&gt;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; Expression.Lambda&amp;lt;T&amp;gt;(merge(first.Body, secondBody), first.Parameters);
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; And&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; first, Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; second)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; first.Compose(second, Expression.And);
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; Or&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; first, Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; second)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; first.Compose(second, Expression.Or);
        }

    }&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;p&gt;La definición completa por lo tanto de una especificación And queda como sigue:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// A logic AND Specification&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;typeparam name=&amp;quot;T&amp;quot;&amp;gt;Type of entity that check this specification&amp;lt;/typeparam&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AndSpecification&amp;lt;T&amp;gt;
       : CompositeSpecification&amp;lt;T&amp;gt;
       &lt;span class="kwrd"&gt;where&lt;/span&gt; T : &lt;span class="kwrd"&gt;class&lt;/span&gt;,&lt;span class="kwrd"&gt;new&lt;/span&gt;()
    {
        &lt;span class="preproc"&gt;#region&lt;/span&gt; Members

        &lt;span class="kwrd"&gt;private&lt;/span&gt; ISpecification&amp;lt;T&amp;gt; _RightSideSpecification = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; ISpecification&amp;lt;T&amp;gt; _LeftSideSpecification = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Public Constructor

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Default constructor for AndSpecification&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;leftSide&amp;quot;&amp;gt;Left side specification&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;rightSide&amp;quot;&amp;gt;Right side specification&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; AndSpecification(ISpecification&amp;lt;T&amp;gt; leftSide, ISpecification&amp;lt;T&amp;gt; rightSide)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (leftSide == (ISpecification&amp;lt;T&amp;gt;)&lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;leftSide&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (rightSide == (ISpecification&amp;lt;T&amp;gt;)&lt;span class="kwrd"&gt;null&lt;/span&gt;)
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;rightSide&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;this&lt;/span&gt;._LeftSideSpecification = leftSide;
            &lt;span class="kwrd"&gt;this&lt;/span&gt;._RightSideSpecification = rightSide;
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Composite Specification overrides

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Left side specification&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; ISpecification&amp;lt;T&amp;gt; LeftSideSpecification
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _LeftSideSpecification; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Right side specification&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; ISpecification&amp;lt;T&amp;gt; RightSideSpecification
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _RightSideSpecification; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;see cref=&amp;quot;Microsoft.Samples.NLayerApp.Domain.Core.Specification.ISpecification&amp;quot;/&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;see cref=&amp;quot;Microsoft.Samples.NLayerApp.Domain.Core.Specification.ISpecification&amp;quot;/&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; SatisfiedBy()
        {
            Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; left = _LeftSideSpecification.SatisfiedBy();
            Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; right = _RightSideSpecification.SatisfiedBy();

            &lt;span class="kwrd"&gt;return&lt;/span&gt; (left.And(right));
         }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;h3&gt;¿Por dónde continuamos?&lt;/h3&gt;
&lt;p&gt;Dentro de la jerarquía de especificaciones que se propone en el documento de Eric y Fowler podemos encontrar desde la especificación Not hasta una base para LeafSpecifications que tendríamos que construir… es decir, un poquito más de curro para poder disfrutar…&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Un resumen&lt;/h3&gt;
&lt;p&gt;La verdad espero que le encontréis utilidad a esta forma de implementar el patrón Specification, y por supuesto, si no lo conociais espero que os levante un poco la curiosidad y veais las bondades que este puede tener&amp;nbsp; dentro de vuestros desarrollos, por supuesto me encantaría ver vuestras opiniones al respecto y si realmente esta forma de encajar criterios es adecuado para vuestras soluciones…&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Saludos &lt;/p&gt;
&lt;p&gt;Unai Zorrilla&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;


&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=167045" width="1" height="1"&gt;</description></item><item><title>EF 4.0: POCO y proxies dinámicos</title><link>http://geeks.ms/blogs/unai/archive/2010/01/19/ef-4-0-poco-y-proxies-din-225-micos.aspx</link><pubDate>Tue, 19 Jan 2010 00:20:10 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:165278</guid><dc:creator>Unai</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=165278</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2010/01/19/ef-4-0-poco-y-proxies-din-225-micos.aspx#comments</comments><description>&lt;p&gt;Para ser sinceros, entre el comienzo del nuevo libro de &lt;strong&gt;EF 4.0&lt;/strong&gt; y el papel en blanco que esto representa, no sabía por dónde empezar a escribir sobre EF. Son tantas y en mi opinión tan acertadas las nuevas novedades que no tenía ni idea del sitio en el que poner mi granito de arena.&lt;/p&gt;  &lt;p&gt;Desde la primera versión, y por ahora única, de &lt;strong&gt;Entity Framework&lt;/strong&gt;, muchas han sido las reclamaciones y recomendaciones de mejora que este framework ha recibido por parte de la comunidad, seguro muchos conocéis el famoso &lt;a href="http://efvote.wufoo.com/forms/ado-net-entity-framework-vote-of-no-confidence/" target="_blank"&gt;“Vote of No Confidence”&lt;/a&gt;&amp;#160; que algunos &lt;strong&gt;MVP&lt;/strong&gt; firmaron y que tanto revuelo levanto en su tiempo. De todas las recomendaciones y falta de confianza en esta primera versión del producto una muy comentada fue el hecho de no poder disponer de objetos &lt;strong&gt;POCO&lt;/strong&gt; dentro de nuestro modelos de dominio, algo imprescindible para incluir el concepto de ignorancia de la persistencia, &lt;strong&gt;PI&lt;/strong&gt; ( Persistent Ignorant ) dentro de nuestros desarrollos.&lt;/p&gt;  &lt;p&gt;Por suerte, en esta segunda versión esta &lt;em&gt;feature&lt;/em&gt; tan solicitada está disponible dentro de la nueva versión del producto, así como plantillas T4 para la generación automática de las clases del modelo. Para una introducción rápida podéis leer los infinitos blogs que tratan este tema, y como no, en esta misma comunidad mis vecinos de blog, &lt;a href="http://geeks.ms/blogs/ciin/archive/2010/01/17/ado-net-ef-recursos-y-trabajo-con-plantillas-t4.aspx" target="_blank"&gt;Juan Carlos&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/adiazmartin/archive/2010/01/17/poco-en-entity-framework-4-0.aspx" target="_blank"&gt;Alberto Diaz&lt;/a&gt; tienen entradas relativas que recomiendo leer.&lt;/p&gt;  &lt;h1&gt;&lt;font color="#404040"&gt;Objectos POCO&lt;/font&gt;&lt;/h1&gt;  &lt;p&gt;Para no repetirme en el tema, en mi entrada me gustaría comentar algunas interioridades de estos objetos &lt;strong&gt;POCO&lt;/strong&gt; y como trabajan internamente. Me imagino, que al igual que yo, una pregunta que os haréis es como se gestionan los cambios que sobre estos objetos se producen, dentro del ámbito de un contenedor, para que posteriormente puedan ser llevados hasta el almacen relacional configurado y como se manejan las relaciones entre los mismos.&lt;/p&gt;  &lt;p&gt;Pongámonos en contexto y empecemos definiendo, tal y como muestran las entradas anteriormente mencionadas, un par de entidades, que denominaremos Blog y Post, mostradas a continuación.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Blog&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="preproc"&gt;#region&lt;/span&gt; Properties&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Id { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Title { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Description { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        List&amp;lt;Post&amp;gt; Posts { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Post&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Id { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Title { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Body { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; BlogId { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; Blog Blog { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Ahora realicemos una sencilla operación de cambio en un conjunto de entidades, por ejemplo los blogs almacenados en nuestro almacen de datos:&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; (BlogModelContainer container = &lt;span class="kwrd"&gt;new&lt;/span&gt; BlogModelContainer())&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;       List&amp;lt;Blog&amp;gt; blogs = container.Blogs.ToList();&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;       blogs.ForEach(blog =&amp;gt; blog.Title = &lt;span class="str"&gt;&amp;quot;Changed in code!&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;       container.SaveChanges();&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Si comprobamos nuestra base de datos veremos como estos cambios se han realizado correctamente, ¿como es posible esto? Fijaos que en nuestras clases Blog y Post ya no disponemos de los eventos &lt;strong&gt;RaisePropertyChanged&lt;/strong&gt; que notificaba a la infraestructura un cambio en el valor de esta propiedad, sin embargo todo sigue funcionando correctamente. Como os podéis haber imaginado alguien se ha encargado de sincronizar nuestros objetos POCO con&amp;#160; los elementos que manejan el estado de todas las entidades dentro de la infraestructura de Entity Framework, nuestras ya famosas e hiper-conocidas &lt;strong&gt;ObjectStateEntry. &lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Este proceso de sincronización de cambios puede realizarse de dos formas diferentes, la primera de forma imperativa mediante una llamada a un nuevo método de los contextos de trabajo llamado &lt;strong&gt;DetectChanges&lt;/strong&gt;, y el segundo, como hemos visto en nuestro objeto, de forma implícita en la llamada a &lt;strong&gt;SaveChanges&lt;/strong&gt;, el cual en su implementación ya realiza este proceso por defecto.&lt;/p&gt;

&lt;p&gt;Por supuesto, por poner pegas que no sea, este sistema no es del todo eficiente, pensemos que en realidad el proceso es básicamente la creación de un snapshot de las entidades materializadas y posteriormente comparar estos snapshot con los elementos a guardar para conocer o sincronizar los cambios. ¿Cómo podemos mejorar este proceso? La respuesta es mediante los &lt;strong&gt;“Change Tracking Proxies”&lt;/strong&gt; de los cuales hablaremos a continuación.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h1&gt;Algunas notas importantes sobre los Objetos POCO&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Una característica que los objetos POCO también deben soportar es el manteniemiento de las relaciones entre los objetos,asegurando la consistencia de las relaciones. Aunque este trabajo lo podemos hacer nosotros a mano tal y como se muestra en el &lt;a href="http://blogs.msdn.com/adonet/archive/2009/05/21/poco-in-the-entity-framework-part-1-the-experience.aspx" target="_blank"&gt;siguiente enlace&lt;/a&gt; en la sección Fix-up relationships la plantilla por defecto que el equipo de producto de EF nos ofrecerá por defecto ya contendrá esta característica funcamental.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h1&gt;Change Tracking Proxies&lt;/h1&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Un Change Tracking Proxy no es mas que una subclase de nuestros objetos POCO que implementa la infraestructura de gestión de cambios que se define en Entity Framework, es decir, implementa la interfaz &lt;strong&gt;IEntityWithChangeTracker &lt;/strong&gt;Por supuesto, con solo decir que es una subclase ya estamos imponiendo una&amp;#160; serie de restricciones dentro de nuestros objetos, por ejemplo el hecho de que no pueda ser una clase sellada. A continuación se muestra una lista de las restricciones que se deben de cumplir para disponer de esta capacidad dentro de nuestros objetos:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Las clases POCO no pueden estar selladas&lt;/li&gt;

  &lt;li&gt;Las clases POCO tienen que tener un constructor por defecto público.&lt;/li&gt;

  &lt;li&gt;Las propiedades deben declararse como publicas y virtuales para que puedan ser sobreescritas por la subclase.&lt;/li&gt;

  &lt;li&gt;El tipo de las propiedades de navegación debe de ser ICollection&amp;lt;TEntity&amp;gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Veamos un ejemplo en la práctica modificando nuestras entidades anteriores para que cumplan estas restricciones:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Blog&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="preproc"&gt;#region&lt;/span&gt; Properties&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Id { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Title { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Description { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; ICollection&amp;lt;Post&amp;gt; Posts { get; set; }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Post&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;        &lt;span class="preproc"&gt;#region&lt;/span&gt; Properties&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Id { get; set; }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Title { get; set; }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Body { get; set; }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; BlogId { get; set; }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; Blog Blog { get; set; }&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Si realizamos un pequeño ejemplo de cambio en una entidad y observamos los valores que el objeto ObjectStateEntry asociado a la entidad tiene en sus valores originales y actuales podremos ver ‘la magia’ de nuestros “change tracking proxies”.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; (BlogModelContainer container = &lt;span class="kwrd"&gt;new&lt;/span&gt; BlogModelContainer())&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;                Blog firstQueriedBlog = container.Blogs.First();&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;                firstQueriedBlog.Title = &lt;span class="str"&gt;&amp;quot;Changed in code!&amp;quot;&lt;/span&gt;;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;                ObjectStateEntry entry = container.ObjectStateManager.GetObjectStateEntry(firstQueriedBlog);&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; original = entry.OriginalValues[&lt;span class="str"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;].ToString();&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt; current = entry.CurrentValues[&lt;span class="str"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;].ToString();&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;                Console.ReadLine();&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;¿De dónde viene esta “magia”? Si observamos con detalle el tipo de Blog obtenido veremos como en realidad el resultado es una subclase emitida en tiempo de ejecución que hará de proxy de nuestros objetos POCO. De esta forma tenemos PI en nuestros desarrollos y rendimiento en la gestión de los cambios de los mismos.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/img1_5F00_4FEBD091.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="img1" border="0" alt="img1" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/img1_5F00_thumb_5F00_204DB205.png" width="731" height="141" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h1&gt;Algunas notas importantes sobre Change Tracking Proxies&lt;/h1&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Aunque el uso de proxies dinámicos es una buena solución, en mi opinión mejor que la inyección de IL como proponen &lt;a href="http://msmvps.com/blogs/matthieu/archive/2009/12/30/another-better-way-to-do-poco.aspx" target="_blank"&gt;otros MVP&lt;/a&gt; , también tienen algunas consideraciones que debemos tratar. La primera y más imporatante es como afectan estos proxies en aplicaciones N-Tier en las que podríamos serializar estas entidades como contratos de datos, puesto que no sabemos a priory el nombre del tipo creado y por lo tanto no lo podremos establecer como &lt;strong&gt;KnownType&lt;/strong&gt; o &lt;strong&gt;ServiceKnowType&lt;/strong&gt; para facilitar el proceso de serialización. Con el fin de soportar esta problemática WCF 4.0 dispone de un nuevo mecanismo para resolver dinámicamente los tipos conocidos por medio de un nuevo elemento llamado &lt;strong&gt;DataContractResolver&lt;/strong&gt;, sobre el cual podréis leer &lt;a href="http://blogs.msdn.com/youssefm/archive/2009/06/05/introducing-a-new-datacontractserializer-feature-the-datacontractresolver.aspx" target="_blank"&gt;aquí&lt;/a&gt; y &lt;a href="http://blogs.msdn.com/adonet/archive/2010/01/05/poco-proxies-part-2-serializing-poco-proxies.aspx" target="_blank"&gt;aquí&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=165278" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category><category domain="http://geeks.ms/blogs/unai/archive/tags/EF+4.0/default.aspx">EF 4.0</category><category domain="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework+4.0/default.aspx">Entity Framework 4.0</category></item><item><title>WCF 4.0:WS-Discovery y DynamicEndpoint</title><link>http://geeks.ms/blogs/unai/archive/2009/12/21/wcf-4-0-ws-discovery-y-dynamicendpoint.aspx</link><pubDate>Mon, 21 Dec 2009 17:55:17 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:163173</guid><dc:creator>Unai</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=163173</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/12/21/wcf-4-0-ws-discovery-y-dynamicendpoint.aspx#comments</comments><description>&lt;p&gt;En otras entradas, la verdad que de hace un pequeño tiempo, hicimos alguna introducción a las novedades que la siguiente versión de &lt;strong&gt;WCF 4.0&lt;/strong&gt; incorporará en&lt;strong&gt; Visual Studio 2010&lt;/strong&gt;, de entre la lista de novedades seguramente una que llamará mucho la atención y que será de uso frecuente en nuestros desarrollos es la implementación de WS-Discovery, vista y tratada en las entradas siguientes, &lt;a href="http://geeks.ms/blogs/unai/archive/2009/05/26/ws-discovery-i-novedades-en-wcf-4-0.aspx" target="_blank"&gt;WS-Discovery Parte I&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/unai/archive/2009/05/26/ws-discovery-ii-novedades-en-wcf-4-0.aspx" target="_blank"&gt;WS-Discovery Parte II&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;A lo largo de la siguiente entrada tocaremos también algo relacionado con esta implementación, pero en este caso mediante &lt;strong&gt;DynamicEndpoint. &lt;/strong&gt;Como su nombre indica, &lt;strong&gt;DynamicEndpoint&lt;/strong&gt; representa un extremo capaz de direccionarse automáticamente, y utiliza para ello la implementación de &lt;strong&gt;WS-Discovery&lt;/strong&gt; realizada en &lt;strong&gt;WCF 4.0&lt;/strong&gt;. Al igual que las clases vistas en las entradas anteriores lo primero que necesitamos es un criterio de búsqueda, algo que por regla general se hace en base al contrato que implementa el servicio que queremos buscar.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;font color="#0000ff"&gt;DynamicEndpoint&lt;/font&gt; dynamicEndpoint = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;font color="#0000ff"&gt;DynamicEndpoint&lt;/font&gt;(
    ContractDescription.GetContract(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ICalculatorService)),
    &lt;span class="kwrd"&gt;new&lt;/span&gt; NetTcpBinding());
CalculatorServiceClient client = &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorServiceClient(dynamicEndpoint);&lt;/pre&gt;

&lt;p&gt;Con este sencillo paso y de forma automática para todos los servicios que usen las capacidades de descubrimiento ya tendremos disponible nuestro proxy de cliente sin necesidad de saber de antemano la dirección física en la que están expuestos los servicios a los que nos queremos comunicar.&lt;/p&gt;

&lt;p&gt;Otra de las &lt;em&gt;features &lt;/em&gt;que nos permite DynamicEndpoint es la de hacer búsquedas de nuestros servicios en función de ámbitos de los mismos. Imagínese que usted ha creado un servicio de WCF para impresión y que este servicio está repetido dentro de la red de una empresa por muchas plantas, por supuesto, cada uno para trabajar con una impresora de la planta concreta. Si hicieramos uso de DynamicEndpoint este nos devolvería el extremo del primer servicio descubierto, pero que puede que no fuera del que quisiéramos hacer uso. Para resolver este problema, dentro de los comportamientos de nuestros extremos podremos agregar uno nuevo conocido como &lt;strong&gt;endPointDiscoveryBehavior &lt;/strong&gt;el cual nos permitirá establecer en la configuración de despliegue de un servicio el ámbito del mismo. Este ámbito puede ser una dirección URI, una dirección LDAP o bien un identificador único&amp;#160; tal y como podemos ver en la &lt;a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.discovery.findcriteria_fields(VS.100).aspx" target="_blank"&gt;documentación de MSDN al respecto&lt;/a&gt;. El siguiente fragmento XML podemos ver un comportamiento de extremo con soporte para ámbitos de descubrimiento.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt; &amp;lt;endpointBehaviors&amp;gt;
                &amp;lt;behavior name=&lt;span class="str"&gt;&amp;quot;discoveryScopeBehavior&amp;quot;&lt;/span&gt;&amp;gt;
                    &amp;lt;endpointDiscovery&amp;gt;
                        &amp;lt;scopes&amp;gt;
                            &amp;lt;add scope=&lt;span class="str"&gt;&amp;quot;http://www.microsoft.com&amp;quot;&lt;/span&gt; /&amp;gt;
                        &amp;lt;/scopes&amp;gt;
                    &amp;lt;/endpointDiscovery&amp;gt;
                &amp;lt;/behavior&amp;gt;
&amp;lt;/endpointBehaviors&amp;gt;&lt;/pre&gt;

&lt;p&gt;Ahora, si queremos que nuestro &lt;strong&gt;DynamicEndpoint&lt;/strong&gt; se base en un ámbito concreto para la búsqueda solamente tendremos que incluir en la propiedad Scopes de su elemento &lt;strong&gt;FindCriteria&lt;/strong&gt;, los ámbitos concretos que hay que buscar en la red.&lt;/p&gt;

&lt;p&gt;Para todos aquellos que deseeis ver algun ejemplo concreto sobre este tema y alguno más relacionado con las novedades de WCF os recomiendo &lt;a href="http://msdn.microsoft.com/en-us/netframework/cc896557.aspx" target="_blank"&gt;descargaros los Samples de WCF 4.0 para Visual Studio 2010 Beta 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Saludos&lt;/p&gt;

&lt;p&gt;Unai&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=163173" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category><category domain="http://geeks.ms/blogs/unai/archive/tags/WS+Discovery/default.aspx">WS Discovery</category><category domain="http://geeks.ms/blogs/unai/archive/tags/WCF/default.aspx">WCF</category></item><item><title>Artalde .NET – EF v 4.0 entre otras cosas</title><link>http://geeks.ms/blogs/unai/archive/2009/09/03/artalde-net-ef-v-4-0-entre-otras-cosas.aspx</link><pubDate>Wed, 02 Sep 2009 23:07:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:155165</guid><dc:creator>Unai</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=155165</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/09/03/artalde-net-ef-v-4-0-entre-otras-cosas.aspx#comments</comments><description>&lt;p&gt;El pr&amp;oacute;ximo Jueves 16 de Septiembre tendr&amp;eacute; el placer de compartir con mis &amp;ldquo;amigos&amp;rdquo; de Artalde .NET una charla sobre Entity Framework V 4.0 entre otras cosas. Para los que pod&amp;aacute;is asistir en Bilbao a esta charla os dejo el enlace de &lt;a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032425206&amp;amp;Culture=es-ES"&gt;registro&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Artalde.NET:&lt;/strong&gt; &lt;strong&gt;ADO.NET&amp;nbsp; Entity Framework Presente y Futuro&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;D&amp;iacute;a&lt;/b&gt;: 16 de Septiembre Mi&amp;eacute;rcoles. &lt;br /&gt;Hora: 19:00 a 21:00. &lt;br /&gt;Ponente: Unai Zorrilla &lt;br /&gt;&lt;b&gt;Agenda:&lt;/b&gt; &lt;br /&gt;19:00 - 19:15 Registro. &lt;br /&gt;19:15 - 21:00 &lt;strong&gt;ADO. NET Entity Framework Presente y Futuro&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Introducci&amp;oacute;n a Entity Framework&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modelos conceptuales&lt;/li&gt;
&lt;li&gt;Desajuste de impedancias&lt;/li&gt;
&lt;li&gt;Domain Driven Design&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Entity Framework v.1&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creaci&amp;oacute;n de modelos conceptuales con EDM&lt;/li&gt;
&lt;li&gt;Modelos conceptuales avanzados&lt;/li&gt;
&lt;li&gt;Los servicios de Objetos y Linq To Entities&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Entity Framework v.4&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nuevos modelos de generaci&amp;oacute;n de c&amp;oacute;digo&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;middot; POCO&lt;/p&gt;
&lt;p&gt;&amp;middot; Selft Tracking Entities&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Novedades en el modelador de entidades&lt;/li&gt;
&lt;li&gt;Model First&lt;/li&gt;
&lt;li&gt;Object First&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Lugar:&lt;/strong&gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Universidad de Deusto &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Edificio ESIDE, Aula de videoconferencia (2&amp;ordm; piso) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Avda Universidades, 24 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 48007, BILBAO&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=155165" width="1" height="1"&gt;</description></item><item><title>EF 4.0: Testeando nuestros repositorios</title><link>http://geeks.ms/blogs/unai/archive/2009/07/18/ef-4-0-testeando-nuestros-repositorios.aspx</link><pubDate>Sat, 18 Jul 2009 16:48:15 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:152600</guid><dc:creator>Unai</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=152600</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/07/18/ef-4-0-testeando-nuestros-repositorios.aspx#comments</comments><description>&lt;p&gt;De todos es sabido mi cariño por esta tecnología, reflejado sin duda en los numerosos artículos, entradas de blog y por su puesto el &lt;a href="http://shop.campusmvp.com/Product-ADO.NET-Entity-Framework_64.aspx"&gt;Libro ADO.NET EF&lt;/a&gt; publicado sobre la misma junto a mis colegas &lt;a href="http://geeks.ms/blogs/ohernandez/"&gt;Octavio Hernandez&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/quintas/"&gt;Eduardo Quintás&lt;/a&gt;. Por supuesto, ya desde hace bastante tiempo han salido &lt;a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;amp;FamilyID=7fd7164e-9e73-43f7-90ab-5b2bf2577ac9"&gt;betas y CTP sobre features&lt;/a&gt; que tendremos disponibles en &lt;strong&gt;Visual Studio 10&lt;/strong&gt; para lo que se ha llamado “Entity Framework 4.0”. A lo largo de futuros post y por supuesto de la segunda versión del libro intentaremos desgranar lo bueno de esta nueva versión y todos los ‘inconvenientes’ que hace más sencillos para la gente que se ha enfrentado a esta tecnología, sobre todo, para aquellos que la han implementado ( o intentado implementar ) en aplicaciones N-CAPAS.&lt;/p&gt;  &lt;p&gt;Para esta primera entrada, de verdad :-), sobre &lt;strong&gt;EF 4.0&lt;/strong&gt;, me gustaría centrarme en aspectos de test y test-doubles, es decir, ver como podemos con las nuevas API’s tratar&amp;#160; de testear nuestros repositorios de datos, y como hacer test-doubles de los mismos sin necesidad de acudir realmente a la base de datos.&lt;/p&gt;  &lt;p&gt;El primer cambio importante que uno ve cuando de entrada crea un proyecto con EDM en Visual Studio 2010 y hecha un vistazo al código, independientemente de la plantilla de &lt;strong&gt;T4&lt;/strong&gt; seleccionada ( Clases prescriptivas, POCO o Selft Tracking Entities ) es que nuestros objetos de consulta que el contenedor pone a nuestra disposición ya no son directametne &lt;strong&gt;ObjectQuery&amp;lt;T&amp;gt;&lt;/strong&gt; sinó &lt;strong&gt;ObjectSet&amp;lt;T&amp;gt;. &lt;/strong&gt;Esta nueva clase, no es más que una herencia de la anterior, la cual, además de los tradicionales métodos de construcción de consultas agrega una serie de elementos que nos simplificarán un poco las cosas, como son por ejemplo los métodos &lt;em&gt;AddObject&lt;/em&gt;, &lt;em&gt;Attach&lt;/em&gt; y &lt;em&gt;DeleteObject&lt;/em&gt;. Aunque a priori pueda parecer una nimiedad fíjese como en la versión actual de &lt;strong&gt;EF&lt;/strong&gt; cuando queremos ‘Atachar’ una entidad dentro del contexto debemos realizar una especificación del &lt;strong&gt;EntitySet&lt;/strong&gt; por medio de una cadena de caracteres, algo no muy elegante a la par de una fuente propensa de errores cuando el proyecto evoluciona, es decir, cuando los modelos tienen una frecuencia de cambio relativamente alta. Le recomiendo la lectura &lt;a href="http://blogs.msdn.com/alexj/archive/2009/05/01/tip-16-how-to-mimic-net-4-0-s-objectset-t-today.aspx"&gt;del post de Alex James&lt;/a&gt; dónde expone estos simples cambios y de paso como podríamos simularlos en .&lt;strong&gt;NET 3.5 SP1&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;Además de los métodos comentados, la parte más interesante de esta nueva clase es que la misma se basa en la implementación de una interfaz, &lt;strong&gt;IObjectSet&amp;lt;T&amp;gt;,&lt;/strong&gt; y por lo tanto es susceptible de ser simulada con cierta rapidez. Precisamente, es este punto, el que nos interesa dentro del trabajo a realizar para la creación de test-doubles con los contenedores de &lt;strong&gt;EF&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;Supongamos que creamos un nuevo modelo de entidades que disponga de una entidad &lt;em&gt;Person&lt;/em&gt; y que sobre el mismo decidimos crear nuestra implementación de contedor y entidades &lt;strong&gt;POCO&lt;/strong&gt;. &lt;/p&gt;  &lt;p&gt;Un ejemplo de nuestro contenedor podría ser algo similar a lo siguiente:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;   &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; ModelContainer
        :ObjectContext
{
        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Constructor

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ModelContainer()
            :&lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;quot;name=ConnectionStringName&amp;quot;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;quot;ContainerName&amp;quot;&lt;/span&gt;)
        {
        }

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;

        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; ObjectSets

        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ObjectSet&amp;lt;Person&amp;gt; mPerson = &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ObjectSet&amp;lt;Person&amp;gt; Person
        {
            get
            {
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; mPerson ?? &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.CreateObjectSet&amp;lt;Person&amp;gt;();
            }
        }

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Como podrá observar sería muy sencillo readaptar nuestro contenedor para que el mismo se basara en una interfaz, que por ejemplo llamaremos &lt;strong&gt;IContainer &lt;/strong&gt;y que tendría la siguiente firma.&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:96.94%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;height:100px;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IContainer
{    
    IObjectSet&amp;lt;Person&amp;gt; Person { get; }
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; ModelContainer
        :ObjectContext,IContainer
{
        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Constructor

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ModelContainer()
            :&lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;quot;name=ConnectionStringName&amp;quot;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;quot;ContainerName&amp;quot;&lt;/span&gt;)
        {
        }

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;

        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; ObjectSets

        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ObjectSet&amp;lt;Person&amp;gt; mPerson = &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IObjectSet&amp;lt;Person&amp;gt; Person
        {
            get
            {
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; mPerson ?? &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.CreateObjectSet&amp;lt;Person&amp;gt;();
            }
        }

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Llegados a este punto, podríamos decir que ya tenemos las bases para poder hacer simulaciones de un contendor de trabajo. La pieza que tendríamos que simular sería una implementación ‘dummy’ de la interfaz IContainer, la cual puede ser fácilmente construída con Stub’s del que ya hemos visto cosillas en un video de &lt;a href="http://channel9.msdn.com/posts/Daniel+Garzon/Introduccion-a-Stubs/"&gt;Channel9@Spain&lt;/a&gt; o bien con cualquier otro framework de Mockering-Stubing como NMock, RhinoMock etc.. El problema principal que nos queda por resolver es la creación de nuestras simulaciones de &lt;strong&gt;IObjectSet&lt;/strong&gt;, puesto que además de los elementos vistos esta interfaz es &lt;strong&gt;IQueryable&amp;lt;T&amp;gt;&lt;/strong&gt; y por lo tanto debermos de dar una implementación a los métodos de la misma. Para resolver esta problemática utilizaremos el método extensor, AsQueryable(), que todos los elementos &lt;strong&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/strong&gt; ,como las listas genéricas, poseen y mediante el cual, podemos transformar directamente una colección de este tipo a Queryable&amp;lt;T&amp;gt;. &lt;/p&gt;

&lt;p&gt;Con el fin de hacer esto de una forma más genérica y reutilizable para todos nuestros &lt;em&gt;ObjectSet&lt;/em&gt;&amp;#160; partiremos de la siguiente clase.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; MockObjectSet&amp;lt;T&amp;gt;
        :IObjectSet&amp;lt;T&amp;gt;
        &lt;span style="color:#0000ff;"&gt;where&lt;/span&gt; T:&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt;

    {
        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Members

        List&amp;lt;T&amp;gt; mInnerList = &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;

        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Constructor

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; MockObjectSet(List&amp;lt;T&amp;gt; innerList)
        {
            &lt;span style="color:#008000;"&gt;//Set InnerList&lt;/span&gt;
            mInnerList = innerList;
        }

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;

        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; IObjectSet&amp;lt;T&amp;gt; Members

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; AddObject(T entity)
        {
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (mInnerList != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
                mInnerList.Add(entity);
        }

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Attach(T entity)
        {
            &lt;span style="color:#008000;"&gt;//TODO: For future post :-)&lt;/span&gt;
        }

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; DeleteObject(T entity)
        {
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ( mInnerList != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt; )
                mInnerList.Remove(entity);
        }

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;

        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; Members

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IEnumerator&amp;lt;T&amp;gt; GetEnumerator()
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; mInnerList.GetEnumerator();
        }

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;

        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.GetEnumerator();
        }

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;

        &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; IQueryable Members

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Type ElementType
        {
            get { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(T); }
        }

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; System.Linq.Expressions.Expression Expression
        {
            get { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; mInnerList.AsQueryable().Expression; }

        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IQueryProvider Provider
        {
            get { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; mInnerList.AsQueryable().Provider; }

        }
                

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Cómo se puede observar, esta nueva clase nos es más que la implementación de la interfaz&lt;strong&gt; IObjectSet&lt;/strong&gt; a partir de una lista de elementos cualquiera y puede ser construída fácilmente por medio, por ejemplo, de un método extensor aplicado a las listas genéricas.&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Extensions
{
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; MockObjectSet&amp;lt;T&amp;gt; AsObjectSet&amp;lt;T&amp;gt;(&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt; List&amp;lt;T&amp;gt; list)
            &lt;span style="color:#0000ff;"&gt;where&lt;/span&gt; T:&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt;
    {
         &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; MockObjectSet&amp;lt;T&amp;gt;(list);
    }
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Llegados aquí, ya hemos construídas todas las bases de nuestro trabajo, vamos entonces, a realizar la tarea que nos ocupaba que consistía en realizar la implementación de Test de nuestros contenedores sin tener que acudir a la base de datos, para ello iremos utilizando todas las partes que hemos visto y creado anteriormente.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;[TestMethod()]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; TestPersonObjectSet()
{
            &lt;span style="color:#008000;"&gt;//Triple AAA ( Arrange, Act, Assert.. )&lt;/span&gt;

           &lt;span style="color:#008000;"&gt;/*&lt;/span&gt;
&lt;span style="color:#008000;"&gt;            * Arrange&lt;/span&gt;
&lt;span style="color:#008000;"&gt;            */&lt;/span&gt;

           &lt;span style="color:#008000;"&gt;//Create a dummy implementation of IContainer&lt;/span&gt;
           SIContainer containerDouble = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SIContainer();

           &lt;span style="color:#008000;"&gt;//Create a list of dummy values for Person ObjectSet&lt;/span&gt;
           List&amp;lt;Person&amp;gt; persons = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List&amp;lt;Person&amp;gt;()
           {
               &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Person(){IdPerson=1,FistName=&lt;span style="color:#006080;"&gt;&amp;quot;Unai&amp;quot;&lt;/span&gt;,LastName=&lt;span style="color:#006080;"&gt;&amp;quot;Zorrilla&amp;quot;&lt;/span&gt;},
               &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Person(){ IdPerson=2,FistName=&lt;span style="color:#006080;"&gt;&amp;quot;Pablo&amp;quot;&lt;/span&gt;,LastName=&lt;span style="color:#006080;"&gt;&amp;quot;Alvarez Doval&amp;quot;&lt;/span&gt;}
           };

           &lt;span style="color:#008000;"&gt;//Set Stub ObjectSet&lt;/span&gt;
           containerDouble.PersonGet = () =&amp;gt; persons.AsObjectSet();

           &lt;span style="color:#008000;"&gt;/*&lt;/span&gt;
&lt;span style="color:#008000;"&gt;            * Act&lt;/span&gt;
&lt;span style="color:#008000;"&gt;            */&lt;/span&gt;

           Person personId1 = ((IContainer)containerDouble).Person.Single(p =&amp;gt; p.IdPerson == 1);

           List&amp;lt;Person&amp;gt; collection = ( from c &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; ((IContainer)containerDouble).Person
                                       orderby c.IdPerson select c).ToList();

           &lt;span style="color:#008000;"&gt;/*&lt;/span&gt;
&lt;span style="color:#008000;"&gt;            * Assert&lt;/span&gt;
&lt;span style="color:#008000;"&gt;            */&lt;/span&gt;

           Assert.AreEqual(personId1.FistName, &lt;span style="color:#006080;"&gt;&amp;quot;Unai&amp;quot;&lt;/span&gt;);
           Assert.AreEqual(personId1.LastName, &lt;span style="color:#006080;"&gt;&amp;quot;Zorrilla&amp;quot;&lt;/span&gt;);
           Assert.IsTrue(persons.Count &amp;gt; 0);
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Como podemos observar en el código anterior, nuestro ejemplo de test crea una instancia de un contenedor creado por Stub’s, al cual le asignamos como ObjectSet de Person el creado a partir de una lista con nuestro nuevo método extensor, posteriormente, haremos las consultas, de igual forma que si estuvieramos trabajando contra ObjectSet de nuestros modelos de EF, es decir, como si estuvieramos trabajando con bases de datos. &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Por supuesto, esto no es más que un ejemplo de trabajo sencillo, en futuras entradas iremos viendo como poner en práctica todo esto contra repositorios de nuestros contenedores de trabajo y como modificar nuestras plantillas de &lt;strong&gt;T4&lt;/strong&gt; para que podamos tener un alto grado de productividad, tanto para la realización de aplicaciones con &lt;strong&gt;EF 4.0 &lt;/strong&gt;como para que las mismas sean fácilmente testeables.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Espero que os guste…&lt;/p&gt;

&lt;p&gt;Un saludo&lt;/p&gt;

&lt;p&gt;Unai Zorrilla Castro&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=152600" width="1" height="1"&gt;</description></item><item><title>.NET 4.0 y System.Data.OracleClient</title><link>http://geeks.ms/blogs/unai/archive/2009/06/16/net-4-0-y-system-data-oracleclient.aspx</link><pubDate>Tue, 16 Jun 2009 09:26:01 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:150561</guid><dc:creator>Unai</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=150561</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/06/16/net-4-0-y-system-data-oracleclient.aspx#comments</comments><description>&lt;p&gt;Himanshu Vasishth acaba de anunciar en el &lt;a href="http://blogs.msdn.com/adonet/archive/2009/06/15/system-data-oracleclient-update.aspx"&gt;blog de ADO.NET&lt;/a&gt; que para .NET 4.0 el driver de Oracle para ADO.NET estará marcado como &lt;strong&gt;deprecated&lt;/strong&gt;, por lo tanto su utilización no estará recomendada. Por supuesto, seguirán dando soporte a clientes que lo usen y resolviendo los issues que se produzcan…&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=150561" width="1" height="1"&gt;</description></item><item><title>WCF 4: Pequeñas novedades en REST</title><link>http://geeks.ms/blogs/unai/archive/2009/06/12/wcf-4-peque-241-as-novedades-en-rest.aspx</link><pubDate>Fri, 12 Jun 2009 10:50:37 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:150407</guid><dc:creator>Unai</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=150407</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/06/12/wcf-4-peque-241-as-novedades-en-rest.aspx#comments</comments><description>&lt;p&gt;A lo largo de unos post anteriores he venido presentando algunas de las novedades de WCF 4.0 que ya podemos probar en Visual Studio 2010 Beta 1. Para continuar con esta serie de novedades veremos algunas pequeñas mejoras introducidas en los servicios REST-style que podremos construir&amp;#160; en esta nueva versión. La primera de ellas aunque simple consiste en la posibilidad de disponer automáticamente de una página de ayuda que muestra las distintas operaciones REST que nuestro servicio puede ofrecer, así como ejemplos de llamadas tanto en XML como Json para los estilos de los mensajes. Para incluir esta información simplemente tendremos que establecer el atributo &lt;strong&gt;enableHelpPage=true &lt;/strong&gt;a nuestro comportamiento de extremo webHttp, tal y como se muestra a continuación.&lt;/p&gt;  &lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;   &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;height:102px;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;endpointBehaviors&amp;gt;
    &amp;lt;behavior name=&lt;span style="color:#006080;"&gt;&amp;quot;webHttpEndPointBehavior&amp;quot;&lt;/span&gt;&amp;gt;
        &amp;lt;webHttp enableHelp=&lt;span style="color:#006080;"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; /&amp;gt;
    &amp;lt;/behavior&amp;gt;
&amp;lt;/endpointBehaviors&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Con esta simple tarea agregando el path /help a nuestra dirección base de servicio se nos presentará en formato RSS una página similar a la siguiente, en la que podremos ver una completa información de nuestro servicio REST.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/help_5F00_0F9C2398.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="help" border="0" alt="help" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/help_5F00_thumb_5F00_08303E1E.png" width="668" height="324" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;La segunda de las novedades tiene que ver con la posibilidad de incluir un sistema de ‘Caching’ automático a nuestras operaciones GET, para ello disponemos de un nuevo atributo denominado [AspNetCacheProfile(&amp;quot;Nombre-Cache&amp;quot;)]. Este atributo hará uso de una sección de configuración donde podremos especificar la duración de la cache y los parámetros que puedan invalidarla, como ejemplo de esta configuración tenemos el siguiente fragmento.&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;system.web&amp;gt;
    &amp;lt;caching&amp;gt;
      &amp;lt;outputCacheSettings&amp;gt;
        &amp;lt;outputCacheProfiles&amp;gt;
          &amp;lt;add name=&lt;span style="color:#006080;"&gt;&amp;quot;Nombre-Cache&amp;quot;&lt;/span&gt; duration=&lt;span style="color:#006080;"&gt;&amp;quot;60&amp;quot;&lt;/span&gt; varyByParam=&lt;span style="color:#006080;"&gt;&amp;quot;format&amp;quot;&lt;/span&gt;/&amp;gt;
        &amp;lt;/outputCacheProfiles&amp;gt;
      &amp;lt;/outputCacheSettings&amp;gt;
    &amp;lt;/caching&amp;gt;
  &amp;lt;/system.web&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Como nota importante decir que este sistema de caché solamente esta habilitado cuando el servicio está configurado con compatibilidad con ASP.NET y el mismo corre bajo IIS, es decir, no podremos hostearlo en un Servicio de Windows por poner un ejemplo.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Saludos&lt;/p&gt;

&lt;p&gt;Unai&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=150407" width="1" height="1"&gt;</description></item><item><title>Channel9@Spain: Pex + Stub’s</title><link>http://geeks.ms/blogs/unai/archive/2009/06/08/channel9-spain-pex-stub-s.aspx</link><pubDate>Mon, 08 Jun 2009 13:57:42 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:150155</guid><dc:creator>Unai</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=150155</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/06/08/channel9-spain-pex-stub-s.aspx#comments</comments><description>&lt;p&gt;&lt;object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="320" height="240"&gt; &lt;param name="source" value="http://channel9.msdn.com/App_Themes/default/vp09_04_23.xap" /&gt; &lt;param name="initParams" value="m=http://mschnlnine.vo.llnwd.net/d1/ch9/3/6/0/1/7/4/Stubs_2MB_ch9.wmv,autostart=false,autohide=true,showembed=true, thumbnail=http://mschnlnine.vo.llnwd.net/d1/ch9/3/6/0/1/7/4/Stubs_large_ch9.png, postid=471063" /&gt; &lt;param name="background" value="#00FFFFFF" /&gt; &lt;a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration:none;"&gt; &lt;img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none;" /&gt; &lt;/a&gt; &lt;/object&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Saludos&lt;/p&gt;  &lt;p&gt;Unai&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=150155" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category><category domain="http://geeks.ms/blogs/unai/archive/tags/Stubs/default.aspx">Stubs</category><category domain="http://geeks.ms/blogs/unai/archive/tags/Unit+Testing/default.aspx">Unit Testing</category><category domain="http://geeks.ms/blogs/unai/archive/tags/Pex/default.aspx">Pex</category></item><item><title>Channel9@Spain: PEX en detalle</title><link>http://geeks.ms/blogs/unai/archive/2009/06/04/channel9-spain-pex-en-detalle.aspx</link><pubDate>Thu, 04 Jun 2009 21:23:02 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:149969</guid><dc:creator>Unai</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=149969</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/06/04/channel9-spain-pex-en-detalle.aspx#comments</comments><description>&lt;p&gt;&lt;object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="320" height="240"&gt; &lt;param name="source" value="http://channel9.msdn.com/App_Themes/default/vp09_04_23.xap" /&gt; &lt;param name="initParams" value="m=http://mschnlnine.vo.llnwd.net/d1/ch9/1/6/0/1/7/4/PEX_2MB_ch9.wmv,autostart=false,autohide=true,showembed=true, thumbnail=http://mschnlnine.vo.llnwd.net/d1/ch9/1/6/0/1/7/4/PEX_large_ch9.png, postid=471061" /&gt; &lt;param name="background" value="#00FFFFFF" /&gt; &lt;a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration:none;"&gt; &lt;img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none;" /&gt; &lt;/a&gt; &lt;/object&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=149969" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category><category domain="http://geeks.ms/blogs/unai/archive/tags/Stubs/default.aspx">Stubs</category><category domain="http://geeks.ms/blogs/unai/archive/tags/Unit+Testing/default.aspx">Unit Testing</category><category domain="http://geeks.ms/blogs/unai/archive/tags/Pex/default.aspx">Pex</category></item><item><title>Routing Service: Novedades en WCF 4.0</title><link>http://geeks.ms/blogs/unai/archive/2009/05/29/routing-service-novedades-en-wcf-4-0.aspx</link><pubDate>Fri, 29 May 2009 21:52:21 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:149589</guid><dc:creator>Unai</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=149589</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/05/29/routing-service-novedades-en-wcf-4-0.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Routering.zip"&gt;Código del ejemplo en VS2010 Beta 1&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;En una &lt;a href="http://geeks.ms/blogs/unai/archive/2009/05/28/routers-en-wcf-3-x.aspx%20"&gt;entrada anterior&lt;/a&gt;, hicimos una introducción acerca de la creación de un sistema de Router o Forwarding en &lt;strong&gt;WCF 3.X&lt;/strong&gt;, fíjese que comenzamos diciendo que podría ser algo habitual en arquitecturas orientadas a servicios, note el patrón &lt;a href="http://www.soapatterns.org/intermediate_routing.asp"&gt;“Intermediate Routing”&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;La siguiente versión de WCF, conocida como &lt;b&gt;WCF 4.0 &lt;/b&gt;de entre las novedades que trae consigo, algunas de las cuales ya las hemos visto &lt;a href="http://geeks.ms/blogs/unai/archive/2009/05/26/ws-discovery-ii-novedades-en-wcf-4-0.aspx"&gt;aquí&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/unai/archive/2009/05/26/ws-discovery-i-novedades-en-wcf-4-0.aspx"&gt;aquí&lt;/a&gt;, puede encontrarse la implementación de un servicio de router ‘out of box’ capaz de resolvernos este patrón sin necesidad de implementar ni una sola línea de código y soportando muchos de los esquemas de mensajes habituales, Request Replay, Fire And Forget, Duplex.&lt;/p&gt;  &lt;p&gt;A lo largo de esta entrada trataremos de implementar el mismo ejemplo que teníamos en la entrada anterior&amp;#160; con el nuevo sistema de routing. Empezemos por el principio, que consiste en definir el servicio que será alojado en distintos procesos HOST (presumiblemente en distintas máquinas) y que desamos balancear.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;   &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;[ServiceContract(Namespace=&lt;span style="color:#006080;"&gt;&amp;quot;http://www.plainconcepts.com&amp;quot;&lt;/span&gt;)]
 &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IGeekService{
        [OperationContract()]
        &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; GetGeekBlog(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; username);
  }&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Una vez alojados estos servicios, cosa que no vamos a comentar y que damos por sabida, por ejemplo en las direcciones &lt;a href="http://localhost:2020/GeekService/"&gt;http://localhost:2020/GeekService/&lt;/a&gt; y &lt;a href="http://localhost:2030/GeekService/IGeekService"&gt;http://localhost:2030/GeekService/IGeekService&lt;/a&gt; llega la hora de hacer la implementación de nuestro router. El nuevo espacio de nombres &lt;strong&gt;System.ServiceModel.Routing&lt;/strong&gt; pone a nuestra disposición un servicio por defecto denominado &lt;strong&gt;RoutingService&lt;/strong&gt; el cual realizará por nosotros las tareas de enrutado sin necesidad de que tengamos tanto conocimiento de las cabeceras de los sobres &lt;strong&gt;SOAP&lt;/strong&gt; &lt;strong&gt;To&lt;/strong&gt; y &lt;strong&gt;Action&lt;/strong&gt; como necesitábamos para la versión anterior.&lt;/p&gt;

&lt;p&gt;Las siguientes líneas de código reflejan lo necesario para alojar nuestro servicio de Router, en nuestro ejemplo en una aplicación de consola.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (ServiceHost host = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ServiceHost(&lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(System.ServiceModel.Routing.RoutingService))){
    host.Open();
    Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;Router a la escucha!&amp;quot;&lt;/span&gt;);
    Console.ReadLine();
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;A la hora de configurar este servicio de router nos tendremos que fijar en distintos aspectos. Por un lado el enlace que vamos a seleccionar, que por supuesto tendrá que ser perfectamente compatible con los de los servicios y cliente, es decir, si el cliente y los servicios se comunican con el enlace ws2007HttpBinding y con un determinado mecanismo de seguridad, el router tendrá que tener este mismo enlace con la configuración adecuada.&lt;/p&gt;

&lt;p&gt; Con respecto al contrato que implementa este Routing Service, tendremos distintas opciones a elegir, dependiendo del tipo de esquema de mensajería que se utilice. Otra vez el espacio de nombres &lt;strong&gt;System.ServiceModel.Routing&lt;/strong&gt; pone a nuestra disposición cinco posibles contratos de servicio para nuestro router para que seleccionemos el adecuado para nuestras necesidades:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;· System.ServiceModel.Routing.IDuplexRouterCallback&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;· System.ServiceModel.Routing.IDuplexSessionRouter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;· System.ServiceModel.Routing.IRequestReplyRouter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;· System.ServiceModel.Routing.ISimplexDatagramRouter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;· System.ServiceModel.Routing.ISimplexSessionRouter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Como en nuestro ejemplo, teníamos un sistema de envío y respuesta tradicional, seleccionaremos &lt;strong&gt;IRequestReplyRouter&lt;/strong&gt;. En este punto ya tendremos la configuración de nuestro router como sigue:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;services&amp;gt;
    &amp;lt;service behaviorConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;RouterBehavior&amp;quot;&lt;/span&gt; name=&lt;span style="color:#006080;"&gt;&amp;quot;System.ServiceModel.Routing.RoutingService&amp;quot;&lt;/span&gt;&amp;gt;
        &amp;lt;endpoint address=&lt;span style="color:#006080;"&gt;&amp;quot;&amp;quot;&lt;/span&gt; binding=&lt;span style="color:#006080;"&gt;&amp;quot;ws2007HttpBinding&amp;quot;&lt;/span&gt; bindingConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;ws2007NoSecurity&amp;quot;&lt;/span&gt;
                    contract=&lt;span style="color:#006080;"&gt;&amp;quot;System.ServiceModel.Routing.IRequestReplyRouter&amp;quot;&lt;/span&gt; /&amp;gt;
            &amp;lt;host&amp;gt;
                &amp;lt;baseAddresses&amp;gt;
                    &amp;lt;add baseAddress=&lt;span style="color:#006080;"&gt;&amp;quot;http://localhost/RouterService&amp;quot;&lt;/span&gt; /&amp;gt;
                &amp;lt;/baseAddresses&amp;gt;
           &amp;lt;/host&amp;gt;
    &amp;lt;/service&amp;gt;
&amp;lt;/services&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Llegados a este momento solamente falta ver como especificamos los filtros que permitan indicarle al router como redirigir los mensajes entrantes hacia los distintos procesos de alojamiento de los servicios. Para ello, lo primero que haremos será agregar un nuevo comportamiento&amp;#160; llamado &lt;strong&gt;routing&lt;/strong&gt;, mediante el cual podremos indicar la tabla de filtros de enrutado.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;serviceBehaviors&amp;gt;
    &amp;lt;behavior name=&lt;span style="color:#006080;"&gt;&amp;quot;RouterBehavior&amp;quot;&lt;/span&gt;&amp;gt;
        &amp;lt;routing filterOnHeadersOnly=&lt;span style="color:#006080;"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; routingTableName=&lt;span style="color:#006080;"&gt;&amp;quot;RoutingTableA&amp;quot;&lt;/span&gt; /&amp;gt;
    &amp;lt;/behavior&amp;gt;
&amp;lt;/serviceBehaviors&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; El comportamiento de routing permite indicar si solamente se realizaran filtros por las cabeceras ( &lt;strong&gt;filtersOnHeadersOnly&lt;/strong&gt; ), algo muy rápido, o bien examinando el cuerpo de los mensajes.&lt;/p&gt;

&lt;p&gt;Estamos ya en la parte más interesante del sistema, la parte con la que podemos especificar los filtros que nos permitan balancear las peticiones. En realidad, un filtro, para un router nos es nada más que una clase heradada de &lt;strong&gt;MessageFilter&lt;/strong&gt;, por lo tanto la creación de filtros personalizados es relativamente sencillo. Por defecto, dentro de WCF 4.0 ya tendremos una serie de filtros OOB, los cuales nos permitirán balancear en función del Action, Address, Endpoint y/o un filtro XPath sobre el contenido del mensaje.&lt;/p&gt;

&lt;p&gt; La sección de filtros para enrutado es un nueva subsección de &lt;strong&gt;&amp;lt;system.serviceModel&amp;gt;&lt;/strong&gt; y que tendrá un aspecto similar a la siguiente, que pasaremos a desgranar seguidamente.&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;routing&amp;gt;
        &amp;lt;namespaceTable&amp;gt;
          &amp;lt;add prefix=&lt;span style="color:#006080;"&gt;&amp;quot;P_C&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt;=&lt;span style="color:#006080;"&gt;&amp;quot;http://www.plainconcepts.com&amp;quot;&lt;/span&gt;/&amp;gt;
        &amp;lt;/namespaceTable&amp;gt;
        &amp;lt;filters&amp;gt;
          &amp;lt;filter name=&lt;span style="color:#006080;"&gt;&amp;quot;FilterHostA&amp;quot;&lt;/span&gt; filterType=&lt;span style="color:#006080;"&gt;&amp;quot;XPath&amp;quot;&lt;/span&gt; filterData=&lt;span style="color:#006080;"&gt;&amp;quot;s12:Envelope/s12:Header/P_C:Host=&amp;#39;HostA&amp;#39;&amp;quot;&lt;/span&gt;/&amp;gt;
          &amp;lt;filter name=&lt;span style="color:#006080;"&gt;&amp;quot;FilterHostB&amp;quot;&lt;/span&gt; filterType=&lt;span style="color:#006080;"&gt;&amp;quot;XPath&amp;quot;&lt;/span&gt; filterData=&lt;span style="color:#006080;"&gt;&amp;quot;s12:Envelope/s12:Header/P_C:Host=&amp;#39;HostB&amp;#39;&amp;quot;&lt;/span&gt;/&amp;gt;
        &amp;lt;/filters&amp;gt;
        &amp;lt;routingTables&amp;gt;
          &amp;lt;table name=&lt;span style="color:#006080;"&gt;&amp;quot;RoutingTableA&amp;quot;&lt;/span&gt;&amp;gt;
            &amp;lt;entries&amp;gt;
              &amp;lt;add filterName=&lt;span style="color:#006080;"&gt;&amp;quot;FilterHostA&amp;quot;&lt;/span&gt; priority=&lt;span style="color:#006080;"&gt;&amp;quot;1&amp;quot;&lt;/span&gt; endpointName=&lt;span style="color:#006080;"&gt;&amp;quot;HostA&amp;quot;&lt;/span&gt;/&amp;gt;
              &amp;lt;add filterName=&lt;span style="color:#006080;"&gt;&amp;quot;FilterHostB&amp;quot;&lt;/span&gt; priority=&lt;span style="color:#006080;"&gt;&amp;quot;2&amp;quot;&lt;/span&gt; endpointName=&lt;span style="color:#006080;"&gt;&amp;quot;HostB&amp;quot;&lt;/span&gt;/&amp;gt;
            &amp;lt;/entries&amp;gt;
          &amp;lt;/table&amp;gt;
        &amp;lt;/routingTables&amp;gt;
&amp;lt;/routing&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;La primera parte de la nueva sección , &lt;strong&gt;namespaceTable&lt;/strong&gt;, nos permite establecer prefijos para los distintos namespaces que pueda tener un sobre SOAP, como en nuestro caso, al igual que en la entrada para routers en WCF 3.X, establecíamos una cabecera con un determinado namespace, pasamos a establecer este nuevo prefijo. Por supuesto, algunos prefijos son por defecto ya conocidos como s12 para Soap 1.2 o s11 para Soap 1.1.&lt;/p&gt;

&lt;p&gt;Una vez especificados los prefijos, llega la hora de establecer la lista de filtros que podrán usarse dentro de las tablas. En el caso de nuestra sección incluímos dos filtros basados en una consulta XPath sobre el mensaje. Cómo podrá observar el primer filtro se corresponderá con los mensajes que contengan una Header llamada Host y con valor HostA, el segundo filtro será equivalente pero en este caso para el valor HostB. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Por supuesto, dentro de esta colección se podrá hacer uso tanto de los filtros por defecto como de los filtros personalizados que deseemos crearnos.&lt;/p&gt;

&lt;p&gt;Ya completadas las secciones de prefijos y filtros solamente falta la creación de las tablas, para nuestro ejemplo disponemos de una tabla con nombre ‘RoutingTableA’, previamente configurada en el comportamiento de servicio, la cual hace uso de los filtros con nombre FilterHostA y FilterHostB.&lt;/p&gt;

&lt;p&gt;Ya está todo amigos, no ha hecho falta escribir una sola línea de código para completar el ejemplo, solamente configuración de un servicio que tenemos por defecto en &lt;strong&gt;WCF 4&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Ahora, solamente haría falta comunicarle al cliente la dirección del router para que la establezca como dirección de los servicios, sin preocuparnos de que el header Address no coincida, sin aplicar un ViaBehavior etc....&lt;/p&gt;

&lt;p&gt;Espero que esta nueva entrada sobre las novedades de WCF os haya parecido interesante, si os interesa investigar o leer más sobre este tema a continuación os dejo algunos enlaces interesantes.&lt;/p&gt;

&lt;p&gt;&lt;a title="http://blogs.msdn.com/endpoint/archive/2009/05/07/the-road-to-4-wcf-changes-between-beta-1-and-ctp.aspx" href="http://blogs.msdn.com/endpoint/archive/2009/05/07/the-road-to-4-wcf-changes-between-beta-1-and-ctp.aspx"&gt;http://blogs.msdn.com/endpoint/archive/2009/05/07/the-road-to-4-wcf-changes-between-beta-1-and-ctp.aspx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a title="http://blogs.thinktecture.com/cweyer/archive/2009/05/08/415335.aspx" href="http://blogs.thinktecture.com/cweyer/archive/2009/05/08/415335.aspx"&gt;http://blogs.thinktecture.com/cweyer/archive/2009/05/08/415335.aspx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a title="http://www.aspnetpro.com/articles/2009/05/asp200905mb_f/asp200905mb_f.asp" href="http://www.aspnetpro.com/articles/2009/05/asp200905mb_f/asp200905mb_f.asp"&gt;http://www.aspnetpro.com/articles/2009/05/asp200905mb_f/asp200905mb_f.asp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Saludos&lt;/p&gt;

&lt;p&gt;Unai Zorrilla&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=149589" width="1" height="1"&gt;</description></item><item><title>Routers en WCF 3.X</title><link>http://geeks.ms/blogs/unai/archive/2009/05/28/routers-en-wcf-3-x.aspx</link><pubDate>Thu, 28 May 2009 14:38:33 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:149488</guid><dc:creator>Unai</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=149488</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/05/28/routers-en-wcf-3-x.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/RouterWCF3x.zip"&gt;Codigo del ejemplo&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Aunque suene en principio algo extraño, la posibilidad de crear un servicio de routers o forwarding es un elemento no tan raro dentro de nuestros desarrollos de aplicaciones distribuídas. Si bien, hoy tenemos sistemas de balanceo de carga por software, NLB, o por hardware como F5 por citar algunos, estos sistemas podrían no cubrir ciertas necesidades. Piense por ejemplo en enrutar o balancear determinados mensajes de servicio en función del valor de una cabecera o bien en función de la operación que se desea realizar. Como se imaginará, los sistemas citados anteriormente puede que no sean suficientes para estos propósitos. &lt;/p&gt;  &lt;p&gt;El enrutamiento de mensajes ya era posible para los que tuvimos la suerte desgracia de trabajar con &lt;b&gt;WSS 3.0,&lt;/b&gt; y por supuesto, es posible desde las primeras versiones de WCF, que a partir de ahora conoceremos o llamaremos como &lt;b&gt;WCF 3.X&lt;/b&gt;. &lt;/p&gt;  &lt;p&gt;A lo largo del siguiente post trataremos de ver un ejemplo de una posible implementación de un sistema de routers tal y como podemos hacer hoy en día con WCF 3.X, en otro post siguiente veremos cómo hacerlo en &lt;b&gt;.NET 4.0&lt;/b&gt; con su nuevo servicio dedicado explícitamente a esta funcionalidad, pero paso a paso..&lt;/p&gt;  &lt;p&gt;&lt;b&gt;NOTA:&lt;/b&gt; Dentro de la implementación de routers podrían distinguirse varios tipos además de implementaciones para resolver los distintos estilos de mensajes, simplex, dúplex, con sesión, seguridad etc.. para no complicar el tema trataremos de realizar un ejemplo simple sin pararnos a manejar temas como sesión o seguridad.&lt;/p&gt;  &lt;p&gt;La primera pregunta que uno se hace, o por lo menos esta es la que yo me hice en su dia, cuando se pone a pensar en una posible implementación, es cómo manejar la cabecera &lt;b&gt;Action&lt;/b&gt;, cabecera que todos los sobres &lt;b&gt;SOAP&lt;/b&gt; contienen.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;NOTA:&lt;/b&gt; La cabecera Action permite a la infraestructura o &lt;b&gt;dispatcher&lt;/b&gt; de mensajes decidir que método del contrato de servicio se va a ejecutar. Si un contrato de servicio dispone de un método, llamemos A, cuando se invoca a esta operación el sobre SOAP contendrá una cabecera Action con un valor equivalente a la siguiente expresión: [Service Namespace]/[Contract Name]/OperationName, a lo menos que se especifique el atributo Action del decorador OperationContract. Por dar una nota explicativa más sobre este tema, para la implementación de REST en WCF precisamente uno de los cambios consistió en establecer la versión del sobre SOAP a None y cambiar el procesamiento de los mensajes para que la invocación del método del contrato de servicio no se basara en la cabecera Action sino en la &lt;b&gt;Uri&lt;/b&gt; de invocación.&lt;/p&gt;  &lt;p&gt;El porqué de esta pregunta es muy sencillo, si ponemos un intermediario entre el cliente y el servicio, esto es, básicamente un router o forwarder, un método del intermediario solamente sería llamado si su valor de Action se corresponde con la cabecera Action del sobre SOAP que se reciba. Por lo tanto, ¿Cómo hacemos para que un método de un intermediario pudiera procesar un sobre con un Action distinto al suyo?.&lt;/p&gt;  &lt;p&gt;La respuesta a esta pregunta son ‘los métodos ociosos’, es decir, los métodos de contrato de servicio que tienen establecido su Action igual a &lt;b&gt;*&lt;/b&gt;. Este valor de Action permite indicarle a la infraestructura que cuando llegue un mensaje al servicio cuyo valor de cabecera Action no se corresponda con ninguno de los elementos del contrato de servicio ejecute este método. &lt;/p&gt;  &lt;p&gt;Llegados a este punto ya sabemos que podríamos tener por ejemplo un método ForwardMessage decorado con OperationContract y su valor de Action=* capaz de procesar cualquier mensaje que recibiera. Pero, los mensajes a procesar son distintos y variados, unos toman un parámetro de entrada otros varios, unos no devuelven resultados, otros un tipo simple y otros algún tipo complejo. En WCF 3.X siempre hemos tenido la posibilidad de trabajar de forma no tipada con nuestros servicios, asumiendo como un &lt;b&gt;Message&lt;/b&gt; cualquier elemento de entrada y cualquier resultado de operación de servicio, aunque esta sea no devolver ningún resultado, por lo tanto, llegados ya ha este punto podríamos deducir que un contrato válido para un router de servicio podría ser algo similar a lo siguiente.&lt;/p&gt;  &lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;   &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;[ServiceContract(Namespace = &lt;span style="color:#006080;"&gt;&amp;quot;http://www.plainconcepts.com&amp;quot;&lt;/span&gt;)]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IRouter
{&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [OperationContract(ReplyAction=&lt;span style="color:#006080;"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;,Action=&lt;span style="color:#006080;"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;)]
       Message ForwardMessage(Message message);
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Con este sencillo contrato ya tenemos decidido cómo será nuestro intermediario o router, ahora, solamente queda ver cómo realizar una implementación. Para ello, empezaremos por definir el servicio que enrutaremos entre diferentes equipos, con el fin de no complicar el ejemplo con elementos innecesarios partiremos de un contrato de servicio tan simple como el siguiente:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;[ServiceContract(Name=&lt;span style="color:#006080;"&gt;&amp;quot;IGeekService&amp;quot;&lt;/span&gt;,Namespace=&lt;span style="color:#006080;"&gt;&amp;quot;http://www.plainconcepts.com&amp;quot;&lt;/span&gt;)]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt;  IGeekService
{&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [OperationContract(Name=&lt;span style="color:#006080;"&gt;&amp;quot;GetGeekBlog&amp;quot;&lt;/span&gt;)]
       &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; GetGeekBlog(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; username);
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Una vez decidido el contrato de nuestro servicio pasaremos a realizar una implementación del mismo y&amp;#160; alojarlo en diferentes procesos Host, que podrían estar en diferentes máquinas, para nuestro ejemplo tendremos estos servicios alojados en las siguientes direcciones &lt;a href="http://localhost:2020/GeekService"&gt;http://localhost:2020/GeekService&lt;/a&gt; y &lt;a href="http://localhost:2030/GeekService"&gt;http://localhost:2030/GeekService&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Fíjese como llegados hasta aquí puede surgir otra pregunta similar a la que nos hacíamos con respecto a la cabecera Action, pero esta vez con respecto a la cabecera &lt;b&gt;To&lt;/b&gt;. WCF tiene para cada uno de los extremos, endpoints, asociadas dos direcciones, una lógica y otra física, cuyo sentido es el mismo que en WSS con los valores de las cabeceras To y &lt;b&gt;Via&lt;/b&gt;. To se corresponde con la dirección lógica a la que se envían los mensajes miestras que Via se corresponde con la dirección física de red dónde se está realizando la escucha de los mismos. En WCF 3.X la dirección lógica se establece con el parámetro &lt;b&gt;Address&lt;/b&gt; y la dirección física con ListenUri, aunque por regla general solamente se suele establecer el valor de Address la dirección física se infiere automáticamente de esta.&lt;/p&gt;

&lt;p&gt;Si en nuestro ejemplo anterior configuramos nuestro servicio GeekService con dos direcciones distintas, los valores que la cabecera To tendrá en los mensajes a uno y otro serán diferentes, y por lo tanto los mensajes se podrán rechazar si llegan a un servicio de escucha con un valor de dirección lógica distinto al que el mensaje contiene en sus cabeceras. ¿Cómo resolvemos ahora este problema?&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;NOTA:&lt;/b&gt; Puede obtener más información acerca del direccionamiento de WCF &lt;a href="http://msdn.microsoft.com/es-es/magazine/cc163412.aspx"&gt;en este gran artículo&lt;/a&gt; de Aaron Skonnard.&lt;/p&gt;

&lt;p&gt;En realidad, tenemos varias alternativas, aunque todas ellas pasan de una forma u otra por configurar los valores de &lt;b&gt;ListenUri&lt;/b&gt; o establecer un behavior de tipo &lt;b&gt;clientVia &lt;/b&gt;que como puede imaginarse se corresponde con el valor de &lt;b&gt;Via&lt;/b&gt; o dirección física a las que nos comuniquemos.&lt;/p&gt;

&lt;p&gt;Para nuestro ejemplo, creamos dos proyectos de host a los cuales agregamos la referencia a nuestro contrato de servicio y los configuramos tal y como se muestra a continuación:&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;?xml version=&lt;span style="color:#006080;"&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; encoding=&lt;span style="color:#006080;"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt; ?&amp;gt;
&amp;lt;configuration&amp;gt;
    &amp;lt;system.serviceModel&amp;gt;
        &amp;lt;bindings&amp;gt;
   &amp;lt;ws2007HttpBinding&amp;gt;
    &amp;lt;binding name=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt;&amp;gt;
     &amp;lt;security mode=&lt;span style="color:#006080;"&gt;&amp;quot;None&amp;quot;&lt;/span&gt; /&amp;gt;
    &amp;lt;/binding&amp;gt;
   &amp;lt;/ws2007HttpBinding&amp;gt;
  &amp;lt;/bindings&amp;gt;
  &amp;lt;behaviors&amp;gt;
   &amp;lt;serviceBehaviors&amp;gt;
    &amp;lt;behavior name=&lt;span style="color:#006080;"&gt;&amp;quot;GeekService.GeekServiceBehavior&amp;quot;&lt;/span&gt;&amp;gt;
     &amp;lt;serviceMetadata httpGetEnabled=&lt;span style="color:#006080;"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; httpGetUrl=&lt;span style="color:#006080;"&gt;&amp;quot;http://localhost:2030/GeekService&amp;quot;&lt;/span&gt; /&amp;gt;
    &amp;lt;/behavior&amp;gt;
   &amp;lt;/serviceBehaviors&amp;gt;
  &amp;lt;/behaviors&amp;gt;
        &amp;lt;services&amp;gt;
   &amp;lt;service behaviorConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;GeekService.GeekServiceBehavior&amp;quot;&lt;/span&gt;
    name=&lt;span style="color:#006080;"&gt;&amp;quot;GeekService.GeekService&amp;quot;&lt;/span&gt;&amp;gt;
    &amp;lt;endpoint address=&lt;span style="color:#006080;"&gt;&amp;quot;urn:GeekService&amp;quot;&lt;/span&gt; binding=&lt;span style="color:#006080;"&gt;&amp;quot;ws2007HttpBinding&amp;quot;&lt;/span&gt;
     bindingConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt; name=&lt;span style="color:#006080;"&gt;&amp;quot;wsBinding&amp;quot;&lt;/span&gt; contract=&lt;span style="color:#006080;"&gt;&amp;quot;GeekService.IGeekService&amp;quot;&lt;/span&gt;
     listenUri=&lt;span style="color:#006080;"&gt;&amp;quot;http://localhost:2030/GeekService&amp;quot;&lt;/span&gt; /&amp;gt;
   &amp;lt;/service&amp;gt;
  &amp;lt;/services&amp;gt;
    &amp;lt;/system.serviceModel&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;

  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;configuration&amp;gt;
    &amp;lt;system.serviceModel&amp;gt;
        &amp;lt;bindings&amp;gt;
   &amp;lt;ws2007HttpBinding&amp;gt;
    &amp;lt;binding name=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt;&amp;gt;
     &amp;lt;security mode=&lt;span style="color:#006080;"&gt;&amp;quot;None&amp;quot;&lt;/span&gt; /&amp;gt;
    &amp;lt;/binding&amp;gt;
   &amp;lt;/ws2007HttpBinding&amp;gt;
  &amp;lt;/bindings&amp;gt;
  &amp;lt;behaviors&amp;gt;
   &amp;lt;serviceBehaviors&amp;gt;
    &amp;lt;behavior name=&lt;span style="color:#006080;"&gt;&amp;quot;GeekService.GeekServiceBehavior&amp;quot;&lt;/span&gt;&amp;gt;
     &amp;lt;serviceMetadata httpGetEnabled=&lt;span style="color:#006080;"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; httpGetUrl=&lt;span style="color:#006080;"&gt;&amp;quot;http://localhost:2030/GeekService&amp;quot;&lt;/span&gt; /&amp;gt;
    &amp;lt;/behavior&amp;gt;
   &amp;lt;/serviceBehaviors&amp;gt;
  &amp;lt;/behaviors&amp;gt;
        &amp;lt;services&amp;gt;
   &amp;lt;service behaviorConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;GeekService.GeekServiceBehavior&amp;quot;&lt;/span&gt;
    name=&lt;span style="color:#006080;"&gt;&amp;quot;GeekService.GeekService&amp;quot;&lt;/span&gt;&amp;gt;
    &amp;lt;endpoint address=&lt;span style="color:#006080;"&gt;&amp;quot;urn:GeekService&amp;quot;&lt;/span&gt; binding=&lt;span style="color:#006080;"&gt;&amp;quot;ws2007HttpBinding&amp;quot;&lt;/span&gt;
     bindingConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt; name=&lt;span style="color:#006080;"&gt;&amp;quot;wsBinding&amp;quot;&lt;/span&gt; contract=&lt;span style="color:#006080;"&gt;&amp;quot;GeekService.IGeekService&amp;quot;&lt;/span&gt;
     listenUri=&lt;span style="color:#006080;"&gt;&amp;quot;http://localhost:2030/GeekService&amp;quot;&lt;/span&gt; /&amp;gt;
   &amp;lt;/service&amp;gt;
  &amp;lt;/services&amp;gt;
    &amp;lt;/system.serviceModel&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Fíjese como, para la configuración anterior hemos establecido su dirección lógica a urn:GeekService y hemos establecido su dirección física en &lt;a href="http://localhost:2030/GeekService"&gt;http://localhost:2030/GeekService&lt;/a&gt;, para el otro host hacemos una configuración similar, aunque como indicamos antes, escuchando en la dirección física &lt;a href="http://localhost/2020/GeekService"&gt;http://localhost/2020/GeekService&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Realizaremos ahora la implementación de nuestro router, tal y como se ve en el siguiente fragmento:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; RouterService
        :IRouter
{
       &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; IRouter Members

      &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Message ForwardMessage(Message message)
      {
            &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; headerIndex = message.Headers.FindHeader(&lt;span style="color:#006080;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;, &lt;span style="color:#006080;"&gt;&amp;quot;http://www.plainconcepts.com&amp;quot;&lt;/span&gt;);
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (headerIndex != -1)
            {
                &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; host = message.Headers.GetHeader&amp;lt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;&amp;gt;(headerIndex);
                ChannelFactory&amp;lt;IRouter&amp;gt; client = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ChannelFactory&amp;lt;IRouter&amp;gt;(host);
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; (client.CreateChannel()).ForwardMessage(message);
            }

            &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span style="color:#006080;"&gt;&amp;quot;No se puede encontrar la cabecera &amp;#39;Key&amp;#39;&amp;quot;&lt;/span&gt;);
        }

        &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;En esta implementación, lo único que se realiza es la verificación del mensaje para obtener una cabecer que nos permita enrutar las llamadas de servicio. Una vez obtenida esa cabecera creamos un cliente apropiado del host al que nos dirigimos, por supuesto, esto forma parte de la configuración de nuestro router y la podemos ver en la siguiente figura:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;?xml version=&lt;span style="color:#006080;"&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; encoding=&lt;span style="color:#006080;"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt; ?&amp;gt;
&amp;lt;configuration&amp;gt;
    &amp;lt;system.serviceModel&amp;gt;
        &amp;lt;client&amp;gt;
            &amp;lt;endpoint address=&lt;span style="color:#006080;"&gt;&amp;quot;urn:GeekService&amp;quot;&lt;/span&gt; behaviorConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;ViaHostA&amp;quot;&lt;/span&gt;
                binding=&lt;span style="color:#006080;"&gt;&amp;quot;ws2007HttpBinding&amp;quot;&lt;/span&gt; bindingConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt;
                contract=&lt;span style="color:#006080;"&gt;&amp;quot;Router.IRouter&amp;quot;&lt;/span&gt; name=&lt;span style="color:#006080;"&gt;&amp;quot;HostA&amp;quot;&lt;/span&gt; /&amp;gt;
            &amp;lt;endpoint address=&lt;span style="color:#006080;"&gt;&amp;quot;urn:GeekService&amp;quot;&lt;/span&gt; behaviorConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;ViaHostB&amp;quot;&lt;/span&gt;
                binding=&lt;span style="color:#006080;"&gt;&amp;quot;ws2007HttpBinding&amp;quot;&lt;/span&gt; bindingConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt;
                contract=&lt;span style="color:#006080;"&gt;&amp;quot;Router.IRouter&amp;quot;&lt;/span&gt; name=&lt;span style="color:#006080;"&gt;&amp;quot;HostB&amp;quot;&lt;/span&gt; /&amp;gt;
        &amp;lt;/client&amp;gt;
        &amp;lt;behaviors&amp;gt;
            &amp;lt;endpointBehaviors&amp;gt;
                &amp;lt;behavior name=&lt;span style="color:#006080;"&gt;&amp;quot;ViaHostA&amp;quot;&lt;/span&gt;&amp;gt;
                    &amp;lt;clientVia viaUri=&lt;span style="color:#006080;"&gt;&amp;quot;http://localhost:2020/GeekService&amp;quot;&lt;/span&gt; /&amp;gt;
                &amp;lt;/behavior&amp;gt;
                &amp;lt;behavior name=&lt;span style="color:#006080;"&gt;&amp;quot;ViaHostB&amp;quot;&lt;/span&gt;&amp;gt;
                    &amp;lt;clientVia viaUri=&lt;span style="color:#006080;"&gt;&amp;quot;http://localhost:2030/GeekService&amp;quot;&lt;/span&gt; /&amp;gt;
                &amp;lt;/behavior&amp;gt;
            &amp;lt;/endpointBehaviors&amp;gt;
        &amp;lt;/behaviors&amp;gt;
        &amp;lt;bindings&amp;gt;
            &amp;lt;ws2007HttpBinding&amp;gt;
                &amp;lt;binding name=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt;&amp;gt;
                    &amp;lt;security mode=&lt;span style="color:#006080;"&gt;&amp;quot;None&amp;quot;&lt;/span&gt; /&amp;gt;
                &amp;lt;/binding&amp;gt;
            &amp;lt;/ws2007HttpBinding&amp;gt;
        &amp;lt;/bindings&amp;gt;
        &amp;lt;services&amp;gt;
            &amp;lt;service name=&lt;span style="color:#006080;"&gt;&amp;quot;Router.RouterService&amp;quot;&lt;/span&gt;&amp;gt;
                &amp;lt;endpoint address=&lt;span style="color:#006080;"&gt;&amp;quot;urn:GeekService&amp;quot;&lt;/span&gt; binding=&lt;span style="color:#006080;"&gt;&amp;quot;ws2007HttpBinding&amp;quot;&lt;/span&gt;
                    bindingConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt; name=&lt;span style="color:#006080;"&gt;&amp;quot;wsBinding&amp;quot;&lt;/span&gt; contract=&lt;span style="color:#006080;"&gt;&amp;quot;Router.IRouter&amp;quot;&lt;/span&gt; listenUri=&lt;span style="color:#006080;"&gt;&amp;quot;http://localhost/RouterService&amp;quot;&lt;/span&gt; /&amp;gt;
            &amp;lt;/service&amp;gt;
        &amp;lt;/services&amp;gt;
    &amp;lt;/system.serviceModel&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Preste atención a la configuración de los clientes del router y como a estos se les ha agregado el comportamiento &lt;b&gt;clientVia&lt;/b&gt;, esto es necesario para que el valor de la cabecera &lt;b&gt;To&lt;/b&gt; en respuesta a las peticiones del cliente no se viera modificada.&lt;/p&gt;

&lt;p&gt;Ahora, ya solamente nos queda realizar la implementación del cliente, para ello simplemente agregamos el siguiente código de llamada, dónde además se agrega una cabecera personalizada, la que necesita el router para enrutar.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;NOTA: &lt;/b&gt;El envío de esta cabecera se podría realizar automáticamente mediante la implementación de &lt;b&gt;IClientMessageInspector&lt;/b&gt;, pero, esto formaría parte de otra entrada.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;Proxy.GeekServiceClient client = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Client.Proxy.GeekServiceClient();
&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; OperationContextScope(client.InnerChannel))
{
MessageHeader header = MessageHeader.CreateHeader(&lt;span style="color:#006080;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;,                 &lt;span style="color:#006080;"&gt;&amp;quot;http://www.plainconcepts.com&amp;quot;&lt;/span&gt;, &lt;span style="color:#006080;"&gt;&amp;quot;HostA&amp;quot;&lt;/span&gt;);
                OperationContext.Current.OutgoingMessageHeaders.Add(header);
Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;Unai blog:{0}&amp;quot;&lt;/span&gt;, client.GetGeekBlog(&lt;span style="color:#006080;"&gt;&amp;quot;unai&amp;quot;&lt;/span&gt;));
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;La configuración del cliente, es similar a la del router, y la podemos ver a continuación:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;system.serviceModel&amp;gt;
        &amp;lt;behaviors&amp;gt;
            &amp;lt;endpointBehaviors&amp;gt;
                &amp;lt;behavior name=&lt;span style="color:#006080;"&gt;&amp;quot;ViaBehavior&amp;quot;&lt;/span&gt;&amp;gt;
                    &amp;lt;clientVia viaUri=&lt;span style="color:#006080;"&gt;&amp;quot;http://localhost/RouterService&amp;quot;&lt;/span&gt; /&amp;gt;
                &amp;lt;/behavior&amp;gt;
            &amp;lt;/endpointBehaviors&amp;gt;
        &amp;lt;/behaviors&amp;gt;
        &amp;lt;bindings&amp;gt;
            &amp;lt;ws2007HttpBinding&amp;gt;
                &amp;lt;binding name=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt;&amp;gt;
                    &amp;lt;security mode=&lt;span style="color:#006080;"&gt;&amp;quot;None&amp;quot;&lt;/span&gt; /&amp;gt;
                &amp;lt;/binding&amp;gt;
            &amp;lt;/ws2007HttpBinding&amp;gt;
        &amp;lt;/bindings&amp;gt;
        &amp;lt;client&amp;gt;
            &amp;lt;endpoint address=&lt;span style="color:#006080;"&gt;&amp;quot;urn:GeekService&amp;quot;&lt;/span&gt; behaviorConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;ViaBehavior&amp;quot;&lt;/span&gt;
                binding=&lt;span style="color:#006080;"&gt;&amp;quot;ws2007HttpBinding&amp;quot;&lt;/span&gt; bindingConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;NoSecurity&amp;quot;&lt;/span&gt;
                contract=&lt;span style="color:#006080;"&gt;&amp;quot;Proxy.IGeekService&amp;quot;&lt;/span&gt; name=&lt;span style="color:#006080;"&gt;&amp;quot;wsBinding&amp;quot;&lt;/span&gt; /&amp;gt;
        &amp;lt;/client&amp;gt;
    &amp;lt;/system.serviceModel&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Por supuesto, este es un ejemplo muy sencillo, y no es la única forma de realizar esta tarea, pero espero que os anime a saber más sobre las posibilidades de enrutado en WCF y las posibilidades que se abren para hacer sistemas de balanceo en función de los parametros de los mensajes o cualquier otro elemento que podamos programar. En un futuro post, no demasiado lejano, veremos cómo esta tarea, que lleva una buena cantidad de código se simplifica con ciertas novedades introducidas en WCF 4.0.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=149488" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category><category domain="http://geeks.ms/blogs/unai/archive/tags/WCF/default.aspx">WCF</category></item><item><title>WS-Discovery (II):Novedades en WCF 4.0</title><link>http://geeks.ms/blogs/unai/archive/2009/05/26/ws-discovery-ii-novedades-en-wcf-4-0.aspx</link><pubDate>Tue, 26 May 2009 15:37:46 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:149364</guid><dc:creator>Unai</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=149364</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/05/26/ws-discovery-ii-novedades-en-wcf-4-0.aspx#comments</comments><description>&lt;p&gt;En el &lt;a href="http://geeks.ms/blogs/unai/archive/2009/05/26/ws-discovery-i-novedades-en-wcf-4-0.aspx"&gt;post anterior&lt;/a&gt; empezamos a ver la especificación de WS-Discovery por medio de los mensajes &lt;b&gt;PROBE&lt;/b&gt; y &lt;b&gt;PROBE MATCH.&lt;/b&gt; A lo largo de esta entrada trataremos de ver los anunciós &lt;strong&gt;HELLO&lt;/strong&gt; y &lt;strong&gt;BYE&lt;/strong&gt; y como hacer que nuestros servicios los realicen de forma automática cada vez que los mismos se abren o cierran los canales de escucha.&lt;/p&gt;  &lt;p&gt;Si para el descubrimiento de los servicios a los extremos de nuestro servicio agregábamos un elemento de tipo &lt;strong&gt;udpDiscoveryEndpoint&lt;/strong&gt; para facilitar su descubrimiento junto al comportamiento &lt;strong&gt;discoveryBehavior&lt;/strong&gt;. Para los anuncios solamente tendremos que incluir un nuevo extremo, &lt;strong&gt;udpAnnouncementEndpoint&lt;/strong&gt;, esta vez, dentro de la sección de anuncios del comportamiento &lt;strong&gt;discoveryBehavior&lt;/strong&gt; tal y como se muestra a continuación.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;   &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;behaviors&amp;gt;
            &amp;lt;serviceBehaviors&amp;gt;
                &amp;lt;behavior name=&lt;span style="color:#006080;"&gt;&amp;quot;SampleServiceBehavior&amp;quot;&lt;/span&gt;&amp;gt;
                    &amp;lt;serviceDiscovery&amp;gt;
                        &amp;lt;announcementEndpoints&amp;gt;
                            &amp;lt;endpoint name=&lt;span style="color:#006080;"&gt;&amp;quot;udpAnnouncementEndpoint&amp;quot;&lt;/span&gt; kind=&lt;span style="color:#006080;"&gt;&amp;quot;udpAnnouncementEndpoint&amp;quot;&lt;/span&gt;
                                endpointConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;&amp;quot;&lt;/span&gt; /&amp;gt;
                        &amp;lt;/announcementEndpoints&amp;gt;
                    &amp;lt;/serviceDiscovery&amp;gt;
                &amp;lt;/behavior&amp;gt;
            &amp;lt;/serviceBehaviors&amp;gt;
        &amp;lt;/behaviors&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Con este sencillo paso, automáticamente nuestro servicio es capaz de realizar los envíos de los anuncios. La pregunta que os estaréis haciendo ahora es ¿Cómo se subscribe uno a estos anuncios? En definitiva, estos anuncios no son más que mensajes enviados a una dirección de multicast, ya comentada en el artículo anterior, que un determinado servicios puede estar escuchando. La implementación de este servicio de escucha es muy sencilla basándose en una clase ya incluída en &lt;strong&gt;WCF 4.0&lt;/strong&gt; que se llama &lt;strong&gt;AnnouncementService&lt;/strong&gt; y cuyo ejemplo de uso podemos ver a continuación.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Main(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] args)
        {
            AnnouncementService announcementService = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; AnnouncementService();
            announcementService.OfflineAnnouncementReceived += &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; EventHandler&amp;lt;AnnouncementEventArgs&amp;gt;(announcementService_OfflineAnnouncementReceived);
            announcementService.OnlineAnnouncementReceived += &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; EventHandler&amp;lt;AnnouncementEventArgs&amp;gt;(announcementService_OnlineAnnouncementReceived);
            &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; (ServiceHost host = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ServiceHost(announcementService))
            {
                host.AddServiceEndpoint(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; UdpAnnouncementEndpoint());
                host.Open();

                Console.ReadLine();
            }
        }

        &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; announcementService_OnlineAnnouncementReceived(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, AnnouncementEventArgs e)
        {
            Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;El servicio {0} anuncia HELLO&amp;quot;&lt;/span&gt;,e.AnnouncementMessage.EndpointDiscoveryMetadata.Address);
        }

        &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; announcementService_OfflineAnnouncementReceived(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, AnnouncementEventArgs e)
        {
            Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;El servicio {0} anuncia BYE&amp;quot;&lt;/span&gt;,e.AnnouncementMessage.EndpointDiscoveryMetadata.Address);
        }&lt;/pre&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=149364" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category><category domain="http://geeks.ms/blogs/unai/archive/tags/WCF+4.0/default.aspx">WCF 4.0</category><category domain="http://geeks.ms/blogs/unai/archive/tags/WS+Discovery/default.aspx">WS Discovery</category></item><item><title>WS-Discovery (I): Novedades en WCF 4.0</title><link>http://geeks.ms/blogs/unai/archive/2009/05/26/ws-discovery-i-novedades-en-wcf-4-0.aspx</link><pubDate>Tue, 26 May 2009 15:34:20 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:149363</guid><dc:creator>Unai</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=149363</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/05/26/ws-discovery-i-novedades-en-wcf-4-0.aspx#comments</comments><description>&lt;p&gt;&lt;b&gt;NOTA: En esta entrada solamente se tratará el modo AdHoc, es decir, basándose en descubrimiento de servicios bajo una misma subred. Se deja para otros futuros post la creación de un proxy de descubrimiento.&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;WS-Discovery&lt;/strong&gt; es una de las ‘pocas’ novedades que trae &lt;strong&gt;WCF 4.0&lt;/strong&gt;, es decir, la versión de Windows Communication Foundation en &lt;strong&gt;Visual Studio 2010&lt;/strong&gt;. Aunque &lt;a href="http://specs.xmlsoap.org/ws/2005/04/discovery/ws-discovery.pdf"&gt;es ya un estandard de OASIS&lt;/a&gt;&amp;#160; que tiene su tiempo, hasta esta nueva versión no teníamos implementación directa.&lt;/p&gt;  &lt;p&gt;Antes de empezar a mostrar ejemplos sobre su uso en &lt;strong&gt;Visual Studio 2010&lt;/strong&gt; haremos un breve repaso del porqué y cómo funciona &lt;strong&gt;WS-Discovery&lt;/strong&gt;. La idea es muy simple, y se basa en el descubrimiento automático de extremos de servicio dentro de una red, algo muy demandado y necesario en Bus de Servicios Empresariales ( ESB ), dónde el direccionamiento puede modificarse con relativa frecuencia. La especificación de este estándar es relativamente pequeña y fácil de entender tal y como se puede ver resumida en los siguientes puntos.&lt;/p&gt;  &lt;p&gt;· Cuando un servicio se une a una red, es decir, cuando se pone a escuchar en una determinada dirección este envía un &lt;b&gt;anuncio &lt;/b&gt;denominado &lt;b&gt;HELLO &lt;/b&gt;para notificar su entrada a la misma.&lt;/p&gt;  &lt;p&gt;· Cuando un servicio se quita de una red, es decir, cuando se cierra y deja de escuchar en una dirección este envía un anuncio denominado &lt;b&gt;BYE &lt;/b&gt;para notificar su salida.&lt;/p&gt;  &lt;p&gt;· Un cliente puede &lt;b&gt;descubrir &lt;/b&gt;servicios existentes en un red bajo un criterio determinado enviando un mensaje denominado &lt;b&gt;PROBE, &lt;/b&gt;si existe algún servicio este responde con otro mensaje denominado &lt;b&gt;PROBE MATCH &lt;/b&gt;el cual contiene la información de su ServiceEndPoint.&lt;/p&gt;  &lt;p&gt;· Un cliente puede descubrir servicios existentes en la red mediante su nombre, para ello puede enviar un mensaje denominado&lt;b&gt; RESOLVE, &lt;/b&gt;si el servicio está en la red responde con otro mensaje denominado &lt;b&gt;RESOLVE MATCH&lt;/b&gt; con la información del mismo.&lt;/p&gt;  &lt;p&gt;Sencillo verdad? Le suena esté mecanismo? En realidad es el mismo que &lt;strong&gt;Windows&lt;/strong&gt; utiliza para el descubrimiento de dispositivos hardware puesto que también se basa en una implementación de &lt;strong&gt;WS Discovery&lt;/strong&gt;. &lt;/p&gt;  &lt;p&gt;Sobre este pequeño resumen de especificación caben unas cuantas preguntas, la primera es ¿dónde se envían estos mensajes y/o anuncios? La respuesta es mediante multicast a una dirección determinada, que por regla general y en el caso de &lt;strong&gt;WCF 4.0&lt;/strong&gt; es &lt;strong&gt;soap.udp://239.255.255.250:3702&lt;/strong&gt;, valores que podremos modificar dentro de la nueva sección de configuración “Standard Endpoints” que &lt;strong&gt;WCF Configuration Editor&lt;/strong&gt; pone a nuestra disposición. Al final, como podrá comprobar, &lt;strong&gt;WS-Discovery&lt;/strong&gt; no es más que la implementación de un determinado contrato de servicio, que en caso de &lt;strong&gt;WCF 4.0&lt;/strong&gt; se corresponde con la versión de Abril 2005 y que tiene la siguiente firma.&lt;/p&gt;  &lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;   &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;[ServiceContract(Namespace=&lt;span style="color:#006080;"&gt;&amp;quot;http://schemas.xmlsoap.org/ws/2005/04/discovery&amp;quot;&lt;/span&gt;, CallbackContract=&lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(IDiscoveryResponseContractApril2005))]
&lt;span style="color:#0000ff;"&gt;internal&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IDiscoveryContractApril2005
{
    &lt;span style="color:#008000;"&gt;// Methods&lt;/span&gt;
    [OperationContract(Action=&lt;span style="color:#006080;"&gt;&amp;quot;http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe&amp;quot;&lt;/span&gt;, IsOneWay=&lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;, AsyncPattern=&lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;)]
    IAsyncResult BeginProbeOperation(ProbeMessageApril2005 request, AsyncCallback callback, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; state);
    [OperationContract(Action=&lt;span style="color:#006080;"&gt;&amp;quot;http://schemas.xmlsoap.org/ws/2005/04/discovery/Resolve&amp;quot;&lt;/span&gt;, IsOneWay=&lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;, AsyncPattern=&lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;)]
    IAsyncResult BeginResolveOperation(ResolveMessageApril2005 request, AsyncCallback callback, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; state);
    &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; EndProbeOperation(IAsyncResult result);
    &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; EndResolveOperation(IAsyncResult result);
    [OperationContract(Action=&lt;span style="color:#006080;"&gt;&amp;quot;http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe&amp;quot;&lt;/span&gt;, IsOneWay=&lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;)]
    &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ProbeOperation(ProbeMessageApril2005 request);
    [OperationContract(Action=&lt;span style="color:#006080;"&gt;&amp;quot;http://schemas.xmlsoap.org/ws/2005/04/discovery/Resolve&amp;quot;&lt;/span&gt;, IsOneWay=&lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;)]
    &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ResolveOperation(ResolveMessageApril2005 request);
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Ahora que más o menos entendemos WS-Discovery, veámos como configurar un servicio para que acepte la petición &lt;strong&gt;Probe&lt;/strong&gt; y por lo tanto pueda ser descubierto por los clientes del mismo ( entendiéndose como clientes también a otros servicios).&lt;/p&gt;

&lt;p&gt;El primer paso es agregar a nuestros servicios un &lt;strong&gt;Endpoint&lt;/strong&gt; especial, llamado &lt;strong&gt;updDiscoveryEndpoint&lt;/strong&gt;, de forma similar a como agregamos extremos de servicio hasta la fecha.&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;endpoint name=&lt;span style="color:#006080;"&gt;&amp;quot;udpDiscoveryEndpoint&amp;quot;&lt;/span&gt; kind=&lt;span style="color:#006080;"&gt;&amp;quot;udpDiscoveryEndpoint&amp;quot;&lt;/span&gt; endpointConfiguration=&lt;span style="color:#006080;"&gt;&amp;quot;&amp;quot;&lt;/span&gt; /&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;NOTA: &lt;/b&gt;El atributo Kind es nuevo dentro de la configuración de Windows Communication Foundation y nos permite especificar que este extremo se corresponde con alguno de los extremos ‘estándar’ que tenemos configurados. Algunos ejemplos adicionales de estos extremos son &lt;i&gt;timerServiceNotificationExpiredEndpoint&lt;/i&gt;,&lt;i&gt;timerServiceEndpoint&lt;/i&gt; o &lt;i&gt;announcementEndpoint.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Una vez que hemos agregado nuestro nuevo extremo al servicio solamente tendremos que agregar al mismo un nuevo comportamiento, denominado &lt;i&gt;ServiceDiscovery. &lt;/i&gt;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;serviceBehaviors&amp;gt;
                &amp;lt;behavior name=&lt;span style="color:#006080;"&gt;&amp;quot;SampleServiceBehavior&amp;quot;&lt;/span&gt;&amp;gt;
                    &amp;lt;serviceDiscovery /&amp;gt;
                &amp;lt;/behavior&amp;gt;
&amp;lt;/serviceBehaviors&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Con estos dos sencillos pasos nuestro servicio ya será capaz de aceptar mensajes de tipo &lt;b&gt;PROBE&lt;/b&gt; y responder con la información de los extremos en los que está escuchando.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;NOTA&lt;/b&gt;: El documento de especificación de WS-Discovery contiene una completa documentación acerca de los formatos de mensajes &lt;b&gt;PROBE&lt;/b&gt; y &lt;b&gt;PROBE MATCH&lt;/b&gt; que le recomiendo revisar.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Llegados a este momento en el que ya tenemos configurado nuestro servicio para aceptar peticiones &lt;b&gt;PROBE&lt;/b&gt; veremos cómo obtener y/o descubrir la información de los mismos de forma AdHoc. Para ello nos serviremos de la clase &lt;b&gt;DiscoveryClient &lt;/b&gt;situada en el espacio de nombres &lt;b&gt;System.ServiceModel.Discovery, &lt;/b&gt;tal y como vemos en el siguiente ejemplo de código:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Discovery()
        {
            DiscoveryClient discoveryClient = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; DiscoveryClient(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; UdpDiscoveryEndpoint());
            discoveryClient.FindCompleted +=&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; EventHandler&amp;lt;FindCompletedEventArgs&amp;gt;(clientDiscovery_FindCompleted);
            discoveryClient.FindProgressChanged +=&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; EventHandler&amp;lt;FindProgressChangedEventArgs&amp;gt;(clientDiscovery_FindProgressChanged);

            discoveryClient.FindAsync(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; FindCriteria(&lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(ISampleService)));
        }
&lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; clientDiscovery_FindCompleted(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, FindCompletedEventArgs e)
        {
            Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;Busqueda completada!&amp;quot;&lt;/span&gt;);
            &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (var item &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; e.Result.Endpoints)
            {
                Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;Endpoint listening At:{0}&amp;quot;&lt;/span&gt;,item.Address);
            }
        }

        &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; clientDiscovery_FindProgressChanged(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, FindProgressChangedEventArgs e)
        {
            Console.WriteLine(&lt;span style="color:#006080;"&gt;&amp;quot;Buscando :{0}%&amp;quot;&lt;/span&gt;,e.ProgressPercentage);
        }&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Fíjese que en la especificación de la clase &lt;b&gt;FindCriteria&lt;/b&gt; podemos establecer el contrato que los servicios que queremos buscar tienen que cumplir. Como elementos adicionales, FindCriteria también nos permite establecer un máximo de duración en la búsqueda o los Scopes de servicio que se tienen que cumplir.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=149363" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category><category domain="http://geeks.ms/blogs/unai/archive/tags/WCF+4.0/default.aspx">WCF 4.0</category><category domain="http://geeks.ms/blogs/unai/archive/tags/WS+Discovery/default.aspx">WS Discovery</category></item><item><title>WCF REST /Conditional GET: Save Bandwidth</title><link>http://geeks.ms/blogs/unai/archive/2009/04/21/wcf-rest-conditional-get-save-bandwidth.aspx</link><pubDate>Tue, 21 Apr 2009 15:27:16 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:147169</guid><dc:creator>Unai</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=147169</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/04/21/wcf-rest-conditional-get-save-bandwidth.aspx#comments</comments><description>&lt;p&gt;Aunque para muchos es desconocido, el estilo REST es cada vez más usado dentro de muchas aplicaciones, numerosos son los ejemplos, Data Services, muchas de las API’s de AZURE y por su puesto en otras plataformas como Google, Amazon etc….&lt;/p&gt;  &lt;p&gt;La llegada de .NET 3.5 nos permitió crear servicios &lt;b&gt;REST&lt;/b&gt; de una forma simétrica a como hacíamos nuestros servicios &lt;b&gt;SOAP&lt;/b&gt;, es lo que tiene tener una arquitectura extensible y plugable, gracias a unos pequeños cambios en los protocolos de mensajería y dispatcher ( básicamente establecer &lt;b&gt;SoapVersion&lt;/b&gt; a &lt;b&gt;None&lt;/b&gt; y asignación de métodos a ejecutar por medio de identificadores de recursos y no por la cabecera &lt;b&gt;Action&lt;/b&gt;&amp;#160; de los sobres). Una de las cosas que no se suelen comentar dentro de los servicios REST es la posibilidad de tocar las cabeceras HTTP para obtener muchas de las posiblidades que los programadores Web ya conocen y utilizan habitualmente. A lo largo de este artículo hablaremos de un par de cabeceras interesantes que tiene que ver con el manejo de la cache como son &lt;b&gt;Is-Modified-Since &lt;/b&gt;y &lt;b&gt;If-None-Match&lt;/b&gt;. Estas dos cabeceras vienen a resolver ciertos problemas de cache cómo son la imposibilidad de los clientes de de tolerar ciertos estados (&lt;b&gt;Cache-Control&lt;/b&gt;,&lt;b&gt;Pragma&lt;/b&gt; ) o expiraciones de &lt;i&gt;‘caching hints’&lt;/i&gt; como Expires. &lt;/p&gt;  &lt;p&gt;Como bien dice la especificación de HTTP sobre temas de cache, la mejora de disponer de cache no solamente viene por la eliminación de peticiones al servidor sino también por eliminar las respuestas completas que estos nos den. Las cabeceras mencionadas anteriormente tiene este último propósito, eliminar respuestas completas, por medio del uso de un código de estado 304, también conocido como &lt;b&gt;Not-Modified&lt;/b&gt;. Los que me conocéis sabéis que me resulta mucho más sencillo explicar las cosas con algún ejemplo de código por lo que vamos al trabajoJ.&lt;/p&gt;  &lt;p&gt;Vamos a suponer que disponemos de una interfaz de servicio REST muy simple, como la mostrada a continuación:&lt;/p&gt;  &lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;   &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;[ServiceContract()]
&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IUserService
{
    [OperationContract()]
    [WebGet(UriTemplate=&lt;span style="color:#006080;"&gt;&amp;quot;Users/{userId}&amp;quot;&lt;/span&gt;)]
    User GetUser(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; userId);
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Si alojamos este servicio convenientemente y hacemos repetidas peticiones a ‘http://dominio/servicio/Users/13’ podremos ver, mediante alguna herramienta de inspección del tráfico HTTP como Fiddler, como esta petición es procesada en el servidor y este devuelve siempre respuestas completas.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/REST_5F00_Figure1_5F00_6636C7F0.jpg"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="REST_Figure1" border="0" alt="REST_Figure1" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/REST_5F00_Figure1_5F00_thumb_5F00_438263A8.jpg" width="530" height="406" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Nuestra idea de uso de las cabeceras anteriormente mencionadas es la de disponer de un mecanismo para averiguar si lo que el cliente de nuestros servicios REST está pidiendo es un elemento previamente consultado y no modificado en el servidor. &lt;/p&gt;

&lt;p&gt;Empezaremos viendo como incorporar &lt;b&gt;Is-Modified-Since &lt;/b&gt;dentro del código de nuestro método de servicio, ver código siguiente:&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; User GetUser(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; userId)
{
      &lt;span style="color:#008000;"&gt;//obtenemos los contextos de peticion y respuesta HTTP&lt;/span&gt;
      IncomingWebRequestContext incomingContext = WebOperationContext.Current.IncomingRequest;

      OutgoingWebResponseContext outgoingContext = WebOperationContext.Current.OutgoingResponse;

      &lt;span style="color:#008000;"&gt;//Obtenemos el usuario pedido&lt;/span&gt;
      User user = FindUser(userId);

blecemos los valores de las cabeceras Is-Modified-            &lt;span style="color:#008000;"&gt;//Since y If-None-Match&lt;/span&gt;

      outgoingContext.LastModified = user.LastModified;
      &lt;span style="color:#008000;"&gt;//outgoingContext.ETag = user.ETag.ToString();&lt;/span&gt;

      user = CheckIfModfiedSince(user, incomingContext, outgoingContext);
      &lt;span style="color:#008000;"&gt;//user = CheckIfNoneMatch(user, incomingContext, outgoingContext);&lt;/span&gt;

      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; user;
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Tal y como podrá observar en el fragmento de código anterior una vez obtenido el usuario solicitado establecemos dentro del contexto de respuesta al cliente el elemento &lt;b&gt;LastModified&lt;/b&gt;, valor de la cabecera &lt;b&gt;Is-Modified-Since&lt;/b&gt;. Con esta simple opción conseguimos que el cliente reciba el valor de esta &lt;i&gt;header&lt;/i&gt; y pueda entregárnosla en futuras peticiones para verificar si le damos una respuesta completa o bien un código de estado 304 y obtenga el resultado de la petición de la caché del navegador, por ejemplo. &lt;/p&gt;

&lt;p&gt;Volvamos a realizar un par de peticiones ahora con este pequeño cambio y veremos como la respuesta del servidor incluye nuestra nueva cabecera.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/REST_5F00_Figure2_5F00_5A510F57.jpg"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="REST_Figure2" border="0" alt="REST_Figure2" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/REST_5F00_Figure2_5F00_thumb_5F00_1FE573A9.jpg" width="474" height="444" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Una vez que ya sabemos cómo enviar nuestra cabecera solamente nos queda verificar el valor de la misma dentro del código de nuestro servicio con el fin de determinar si al cliente le enviamos la respuesta completa o el valor de ‘No hay cambios en la petición’. Esto lo conseguimos dentro del método de nuestro código anterior &lt;i&gt;ChechIfModifiedSince&lt;/i&gt; que presentamos a continuación.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; User CheckIfModfiedSince(User user, IncomingWebRequestContext incomingContext, OutgoingWebResponseContext outgoingContext)
{
            &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; lastModified = incomingContext.Headers[HttpRequestHeader.IfModifiedSince];

            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (lastModified != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
            {
                &lt;span style="color:#008000;"&gt;//Si no se ha modificado establecemos el estado NotModified en el protocolo HTTP&lt;/span&gt;
                &lt;span style="color:#008000;"&gt;//Comprobamos si el usuario ha cambiado&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (IsNotModified(user.LastModified, DateTime.Parse(lastModified)))
                {
                    &lt;span style="color:#008000;"&gt;//Establecemos que no hay modificaciones&lt;/span&gt;
                    outgoingContext.SuppressEntityBody = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;; &lt;span style="color:#008000;"&gt;// la peticion no devolverá nada&lt;/span&gt;
                    outgoingContext.StatusCode = HttpStatusCode.NotModified;
                    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
                }
            }

            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; user;
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Fíjese como este método lo único que realiza es la comparación de la header con un valor, en nuestro caso por sencillez dentro del elemento &lt;i&gt;User&lt;/i&gt;, que nos permita evaluar si el elemento ha cambiado comparando para ello un par de elementos de tipo &lt;b&gt;DateTime&lt;/b&gt; y estableciendo como código de salida el valor 304, &lt;b&gt;NotModified&lt;/b&gt;, en caso afirmativo. Hecho este trabajo puede probar a realizar distintas peticiones al servidor y verá como este mecanismo reduce el ancho de banda necesario para nuestros servicios puesto que las respuestas no serán completas sino un simple código &lt;b&gt;304&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;El funcionamiento de la cabecera &lt;b&gt;If-None-Match&lt;/b&gt; es realmente similar a &lt;b&gt;If-Modified-Since&lt;/b&gt;, la principal diferencia es que la comparación de cambio no se realiza sobre un campo fecha sino sobre un elemento conocido como &lt;b&gt;etag &lt;/b&gt;o entity tag, el cual no es más que la expresión de una entidad en un punto en el tiempo, pudiendo establecerse como un hash un guid o lo que nosotros deseemos. Este valor de &lt;b&gt;etag &lt;/b&gt;es el que utilizaremos para saber si una entidad ha cambiado y proceder a dar una respuesta completa al servidor o bien devolver un 304 como anteriormente realizamos.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; User CheckIfNoneMatch(User user, IncomingWebRequestContext incomingContext, OutgoingWebResponseContext outgoingContext)
{
    &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; etag = incomingContext.Headers[HttpRequestHeader.IfNoneMatch];
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (etag != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
    {
         &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (IsNotModified(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Guid(etag), user.ETag)){
             &lt;span style="color:#008000;"&gt;//Establecemos que no hay modificaciones&lt;/span&gt;
             outgoingContext.SuppressEntityBody = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
             &lt;span style="color:#008000;"&gt;// la peticion no devolverá nada&lt;/span&gt;
             outgoingContext.StatusCode = HttpStatusCode.NotModified;
             &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
         }
    }
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; user;
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;P.D: Entity Tag también es utilizado en ADO.NET Data Services para manejar la concurrencia optimista, podéis ver una referencia &lt;a href="http://msdn.microsoft.com/en-us/library/cc668770.aspx"&gt;aqui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Espero que os resulte de utilidad,&lt;/p&gt;

&lt;p&gt;Unai Zorrilla&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=147169" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category></item><item><title>Channel9@Spain:ADO .NET Data Services II</title><link>http://geeks.ms/blogs/unai/archive/2009/03/17/channel9-spain-ado-net-data-services-ii.aspx</link><pubDate>Tue, 17 Mar 2009 11:37:05 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:145080</guid><dc:creator>Unai</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=145080</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/03/17/channel9-spain-ado-net-data-services-ii.aspx#comments</comments><description>&lt;p&gt;&lt;object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="320" height="240"&gt; &lt;param name="source" value="http://channel9.msdn.com/App_Themes/default/VideoPlayer2009_02_11.xap" /&gt; &lt;param name="initParams" value="m=http://mschnlnine.vo.llnwd.net/d1/ch9/5/9/4/6/5/4/ADONETDataServicesII_2MB_ch9.wmv,autostart=false,autohide=true,showembed=true, thumbnail=http://mschnlnine.vo.llnwd.net/d1/ch9/5/9/4/6/5/4/ADONETDataServicesII_large_ch9.png, postid=456495" /&gt; &lt;param name="background" value="#00FFFFFF" /&gt; &lt;a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration:none;"&gt; &lt;img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none;" /&gt; &lt;/a&gt; &lt;/object&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=145080" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category><category domain="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework/default.aspx">Entity Framework</category></item><item><title>Channel9@Spain: ADO.NET Data Services I</title><link>http://geeks.ms/blogs/unai/archive/2009/03/17/channel9-spain-ado-net-data-services-i.aspx</link><pubDate>Tue, 17 Mar 2009 11:35:40 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:145079</guid><dc:creator>Unai</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=145079</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/03/17/channel9-spain-ado-net-data-services-i.aspx#comments</comments><description>&lt;p&gt;&lt;object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="320" height="240"&gt; &lt;param name="source" value="http://channel9.msdn.com/App_Themes/default/VideoPlayer2009_02_11.xap" /&gt; &lt;param name="initParams" value="m=http://mschnlnine.vo.llnwd.net/d1/ch9/4/9/4/6/5/4/ADONETDataServicesI_2MB_ch9.wmv,autostart=false,autohide=true,showembed=true, thumbnail=http://mschnlnine.vo.llnwd.net/d1/ch9/4/9/4/6/5/4/ADONETDataServicesI_large_ch9.png, postid=456494" /&gt; &lt;param name="background" value="#00FFFFFF" /&gt; &lt;a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration:none;"&gt; &lt;img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none;" /&gt; &lt;/a&gt; &lt;/object&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=145079" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx">.NET General</category><category domain="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework/default.aspx">Entity Framework</category></item><item><title>MVP Summit 09, Don Box, Danny Simmons, Diego vega…</title><link>http://geeks.ms/blogs/unai/archive/2009/03/08/mvp-summit-09-don-box-danny-simmons-diego-vega.aspx</link><pubDate>Sun, 08 Mar 2009 00:22:58 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:144336</guid><dc:creator>Unai</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/unai/rsscomments.aspx?PostID=144336</wfw:commentRss><comments>http://geeks.ms/blogs/unai/archive/2009/03/08/mvp-summit-09-don-box-danny-simmons-diego-vega.aspx#comments</comments><description>&lt;p&gt;Tal y como &lt;a href="http://geeks.ms/blogs/rcorral/archive/2009/03/07/de-vuelta-del-mvp-summit-2009-fue-en-oslo-no-en-redmond.aspx"&gt;comentaba&lt;/a&gt; Rodrigo, ya estamos de vuelta del MVP Summit 09, del que personalmente he disfrutado mucho, no solamente por la gran cantidad de charlas y reuniones que me meti en el cuerpo, y de las cuales disfruté enormemente sino también por ver como amigos como &lt;a href="http://geeks.ms/blogs/mllopis/"&gt;Miguel Llopis&lt;/a&gt; movían todos sus hilos para poder ofrecernos a todos los MVP de habla castellana una excelentísima sesión sobre OSLO del cual el es un enorme conocedor, como se puede reflejar el hecho de que el lenguaje de Oslo, M, toma por nombre la primera de sus letras.&lt;/p&gt;  &lt;p&gt;Además de todo el trabajo, también hubo tiempo para el placer, y&amp;#160; este, vino de la mano de diversas excelentes entrevistas que pudimos hacer para &lt;a href="http://www.dotnetmania.com"&gt;DotNetMania&lt;/a&gt;, junto con mi buen amigo &lt;a href="http://geeks.ms/blogs/ohernandez"&gt;Octavio&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/WithDannyAndDiego_5F00_580F970F.jpg"&gt;&lt;img title="WithDannyAndDiego" style="border-right:0px;border-top:0px;display:inline;margin-left:0px;border-left:0px;margin-right:0px;border-bottom:0px;" height="152" alt="WithDannyAndDiego" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/WithDannyAndDiego_5F00_thumb_5F00_0488A129.jpg" width="244" align="right" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt; Empezando las mismas con Danny Simmons y Diego Vega, de sobra conocidos para los amantes de EF, de hecho Diego fué uno de los revisores de nuestro &lt;a href="http://shop.campusmvp.com/Product-ADO.NET-Entity-Framework_64.aspx"&gt;libro&lt;/a&gt; sobre el tema, con los que tuvimos la oportunidad de charlar profundamente del presente y el futuro de la tecnología, amén de todas las ponencias impartidas :-), y cuyos consejos y noticias podréis ver en el número de Abril de Dotnetmania.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Las dos siguientes entrevistas realizadas,&amp;#160; tampoco tienen su des&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/WithDon_5F00_696FD21A.jpg"&gt;&lt;img title="WithDon" style="border-right:0px;border-top:0px;display:inline;margin-left:0px;border-left:0px;margin-right:0px;border-bottom:0px;" height="152" alt="WithDon" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/WithDon_5F00_thumb_5F00_4DEAD017.jpg" width="244" align="left" border="0" /&gt;&lt;/a&gt;perdicio, por un lado un personaje poco conocido en este mundo como es un tal Don Box, entrevista para el més de Mayo y otro elemento desconocido como Paul Vick ( entrevista de Junio). A los que no estáis subscritos a DotnetMania no se que estáis esperando :-) &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/WithPaul_5F00_1DE07E96.jpg"&gt;&lt;img title="WithPaul" style="border-right:0px;border-top:0px;display:inline;border-left:0px;border-bottom:0px;" height="152" alt="WithPaul" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/WithPaul_5F00_thumb_5F00_32361E54.jpg" width="244" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Saludos con Jet-Lag !!&lt;/p&gt;  &lt;p&gt;Unai&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=144336" width="1" height="1"&gt;</description></item></channel></rss>