<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">O bruxo mobile</title><subtitle type="html">Grandes historias sobre pequeños dispositivos</subtitle><id>http://geeks.ms/blogs/unai/atom.aspx</id><link rel="alternate" type="text/html" href="http://geeks.ms/blogs/unai/default.aspx" /><link rel="self" type="application/atom+xml" href="http://geeks.ms/blogs/unai/atom.aspx" /><generator uri="http://communityserver.org" version="4.1.31106.3070">Community Server</generator><updated>2012-10-09T22:26:00Z</updated><entry><title>EF 6: Operaciones de migraciones personalizadas</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/05/15/ef-6-operaciones-de-migraciones-personalizadas.aspx" /><id>/blogs/unai/archive/2013/05/15/ef-6-operaciones-de-migraciones-personalizadas.aspx</id><published>2013-05-15T17:57:12Z</published><updated>2013-05-15T17:57:12Z</updated><content type="html">&lt;p&gt;Hace ya un tiempo, el buen amigo &lt;a href="https://twitter.com/iceoverflow"&gt;@iceoverflow&lt;/a&gt; ,hizo un pequeño pero muy interesante &lt;a href="http://entityframework.codeplex.com/SourceControl/network/forks/iceclow/efmigrationsextensions2/contribution/4064#!/tab/changes"&gt;pull request&lt;/a&gt; que nos habilita la posibilidad de crear y enchufar nuevas operaciones de migración que no tengamos por defecto en&lt;strong&gt; Entity Framework&lt;/strong&gt;. Aunque el proceso es un poco mecánico, abre un montón de posibilidades para hacer nuevas contribuciones, incluso aunque no sea directamente en el código de EF y si en alguna contribución ( tengo una pequeña sorpresa con esto pero ya os la contaré cuando esté más avanzada ). A continuación me gustaría enseñaros un pequeño ejemplo de lo que podemos hacer y, por supuesto, todo aquello que os gustaría tener me encantaría escucharlo e incluso hacerlo…&lt;/p&gt;  &lt;p&gt;Bien, empezamos, trataremos de hacer una operación de migración para crear una vista, lo primero por lo tanto es definir la operación, para ello, solamente tenemos que heredar de &lt;strong&gt;MigrationOperation&lt;/strong&gt;, como por ejemplo vemos a continuación:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; System.Data.Entity.Migrations.Model
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Data.Entity.Utilities;

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Represent a create view in database&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; CreateViewOperation
        :MigrationOperation
    {
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// The view name&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;string&lt;/span&gt; ViewName { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// The view body sql&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;string&lt;/span&gt; BodySql { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }


        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Create a new instance&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;viewName&amp;quot;&amp;gt;the view name to create&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;bodySql&amp;quot;&amp;gt;the view body sql &amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; CreateViewOperation(&lt;span class="kwrd"&gt;string&lt;/span&gt; viewName, &lt;span class="kwrd"&gt;string&lt;/span&gt; bodySql)
            :&lt;span class="kwrd"&gt;base&lt;/span&gt;(&lt;span class="kwrd"&gt;null&lt;/span&gt;)
        {
            Check.NotEmpty(viewName,&lt;span class="str"&gt;&amp;quot;viewName&amp;quot;&lt;/span&gt;);
            Check.NotEmpty(bodySql,&lt;span class="str"&gt;&amp;quot;bodySql&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;this&lt;/span&gt;.ViewName = viewName;
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.BodySql = bodySql;
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsDestructiveChange
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; MigrationOperation Inverse
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; DropViewOperation(ViewName);
            }
        }
    }
}&lt;/pre&gt;

&lt;p&gt;Bien, ahora que ya tenemos definida nuestra operación, ya la podemos incluir dentro de nuestras migraciones, para que quede de una forma consistente con las operaciones actuales, podríamos crear un método extensor de de &lt;strong&gt;DbMigration&lt;/strong&gt; como el siguiente:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&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;/// Create a new view&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;migration&amp;quot;&amp;gt;The DBMigration&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;viewName&amp;quot;&amp;gt;The name of view to create&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;bodySql&amp;quot;&amp;gt;The sql body of view to create&amp;lt;/param&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;void&lt;/span&gt; CreateView(&lt;span class="kwrd"&gt;this&lt;/span&gt; DbMigration migration, &lt;span class="kwrd"&gt;string&lt;/span&gt; viewName, &lt;span class="kwrd"&gt;string&lt;/span&gt; bodySql)
        {
            ((IDbMigration)migration)
              .AddOperation(&lt;span class="kwrd"&gt;new&lt;/span&gt; CreateViewOperation(viewName, bodySql));
        }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Una vez hecho este trabajo, cuando una operación se ejecute, esta operación se enviará al generador sql que tengamos configurado,recuerde que puede establecerlo ahora con nuestro punto central de configuración DbConfiguration. Por lo tanto, este generador debe de estar preparado para procesar estas operaciones, por lo tanto, lo normal será partir de un generador dado como por ejemplo SqlServerMigrationSqlGenerator para extenderlo con esta nueva operación. Para nuestro ejemplo podríamos hacer algo como lo siguiente:&lt;/p&gt;

&lt;p&gt;&amp;#160;&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;/// Extented Sql Server Migrations Sql Generator with more&lt;/span&gt;
    &lt;span class="rem"&gt;/// operations.&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// For set  this migrations sql generator you need register it in&lt;/span&gt;
    &lt;span class="rem"&gt;/// your DbMigrationsConfiguration{TContext} using the method &lt;/span&gt;
    &lt;span class="rem"&gt;/// SetSqlGenerator&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;example&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// SetSqlGenerator(&amp;quot;System.Data.SqlClient&amp;quot;, new AdvancedSqlServerMigrationSqlGenerator());&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/example&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&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; ExtendedSqlServerMigrationSqlGenerator
        : SqlServerMigrationSqlGenerator
    {
        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Generate(MigrationOperation migrationOperation)
        {
            
        }
     }&lt;/pre&gt;

&lt;p&gt;Ahora, en nuestro &lt;em&gt;Generate&lt;/em&gt; deberíamos ver como procesar cada una de las posibles operaciones personalizadas que podamos querer incluir, para facilitar la tarea y no ver demasiada conversión o switch un truquito rápido sería este:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        /// &amp;lt;inheritdoc/&amp;gt;
        &lt;span class="kwrd"&gt;protected&lt;/span&gt; override void Generate(MigrationOperation migrationOperation)
        {
            this.Generate((dynamic)migrationOperation);
        }

        /// &amp;lt;summary&amp;gt;
        /// Generate a SQL &lt;span class="kwrd"&gt;to&lt;/span&gt; create a &lt;span class="kwrd"&gt;new&lt;/span&gt; view &lt;span class="kwrd"&gt;in&lt;/span&gt; database
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name=&lt;span class="str"&gt;&amp;quot;createViewOperation&amp;quot;&lt;/span&gt;&amp;gt;The operation &lt;span class="kwrd"&gt;to&lt;/span&gt; produce sql &lt;span class="kwrd"&gt;for&lt;/span&gt;.&amp;lt;/param&amp;gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; virtual void Generate(CreateViewOperation createViewOperation)
        {
            using (var writer = Writer())
            {
                writer.Write(&lt;span class="str"&gt;&amp;quot;IF object_id(N&amp;#39;{0}&amp;#39;, &amp;#39;V&amp;#39;) IS NOT NULL &amp;quot;&lt;/span&gt;,createViewOperation.ViewName);
                writer.WriteLine(&lt;span class="str"&gt;&amp;quot;DROP VIEW {0} &amp;quot;&lt;/span&gt;,createViewOperation.ViewName);
                writer.WriteLine(&lt;span class="str"&gt;&amp;quot;GO &amp;quot;&lt;/span&gt;);
                writer.WriteLine(&lt;span class="str"&gt;&amp;quot;CREATE VIEW {0} AS {1}&amp;quot;&lt;/span&gt;,createViewOperation.ViewName,createViewOperation.BodySql);

                this.Statement(writer);
            }
        }&lt;/pre&gt;


&lt;p&gt;Al ponerlo como &lt;em&gt;dynamic&lt;/em&gt; podemos crear un método para cada una de las operaciones personalizadas y por lo tanto simplificar tanto la lectura como el mantenimiento del código.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Espero que os haya gustado esta posibilidad, por supuesto, para los que os habéis fijado en el código esto forma parte de un proyecto que ya contiene muchas más posibles operaciones de migración que pronto compartiré con todos vosotros, de ahí que os preguntará que os gustaría tener!!, animaros…&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=209475" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /><category term="Entity Framework 6" scheme="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework+6/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>Commands y Windows Azure ServiceBus</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/05/13/commands-y-windows-azure-servicebus.aspx" /><id>/blogs/unai/archive/2013/05/13/commands-y-windows-azure-servicebus.aspx</id><published>2013-05-13T17:32:26Z</published><updated>2013-05-13T17:32:26Z</updated><content type="html">&lt;p&gt;Bueno, un post pequeñito pequeñito, más que nada y para ser sincero, para cambiar un poco de tercio, pero que espero que os resulte interesante. Hace ya bastante tiempo, los pocos que leéis mi aburrido blog, escribí acerca de &lt;a href="http://geeks.ms/blogs/unai/archive/2012/06/19/domain-events-y-agregados.aspx"&gt;eventos de dominio y agregados&lt;/a&gt;. En esta ocasión me gustaría hablar de comandos y de alguna pequeña ayuda que el nuevo SDK de Azure nos trae para implementaciones de nuestros manejadores. Si bien, comandos y eventos, en realidad son cuestiones semánticas y poco más, uno en pasado, otro acción, receptores y poco más&amp;#160; la verdad es que su implementación se parece muchísimo, puesto que en ambos tenemos un consumidor ( o N en realidad )&amp;#160; capaz de despachar acciones, la información del evento producido o el comando ejecutado. La implementación de estos despachadores &lt;strike&gt;( que feo.. ) &lt;/strike&gt;suele ser más o menos sencilla cuando estamos modelando nuestro sistema pero en realidad, a la hora de ir a un sistema real el tema se complica y muchas veces se acaba por utilizar algunas buenas piezas ya construidas como puede ser &lt;a href="http://nservicebus.com/"&gt;NServiceBus&lt;/a&gt; de &lt;a href="http://www.udidahan.com/"&gt;Udi Dahan&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Nota: Para los que os interese &lt;strong&gt;NServiceBus&lt;/strong&gt; y todo lo relacionado con este bloque de código os recomiendo el blog de &lt;a href="http://www.serrate.es/"&gt;MarÇel Serrate&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Pues bien, la nueva versión del SDK de Azure, &lt;a href="http://www.windowsazure.com/en-us/downloads/"&gt;SDK 2.0&lt;/a&gt;, incluye una pequeñita mejora en el procesado de mensajes de una cola, habitual para la implementación de un dispatcher de comandos y eventos, de tal forma que el patrón de recepción y vuelta a escuchar de los mensajes en nuestra cola se simplifique muchísimo introduciendo un patrón de eventos. Concrétamente veremos que el API cliente para manejar nuestras colas dispone de un nuevo método &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/microsoft.servicebus.messaging.queueclient.onmessage(v=azure.100).aspx"&gt;OnMessage&lt;/a&gt; con el que podremos especificar&amp;#160; donde haremos el procesado de los mensajes y el establecimiento de diferentes opciones como el auto completado de los mensajes, el número máximo&amp;#160; de llamadas concurrentes y/o el método a utilizar para manejar excepciones que se produzcan en la recepción de los mensajes. Un ejemplo trivial de esto podría ser:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;            var eventDrivenMessagingOptions = &lt;span class="kwrd"&gt;new&lt;/span&gt; OnMessageOptions();

            eventDrivenMessagingOptions.AutoComplete = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            eventDrivenMessagingOptions.ExceptionReceived += OnExceptionReceived;
            eventDrivenMessagingOptions.MaxConcurrentCalls = 5;
        
            &lt;span class="rem"&gt;// Subscribe for messages.&lt;/span&gt;
            var queueClient = QueueClient.Create(&lt;span class="str"&gt;&amp;quot;commands&amp;quot;&lt;/span&gt;);
            queueClient.OnMessage(OnMessageArrived, eventDrivenMessagingOptions);&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Ahora, solamente necesitaríamos nuestro método de manejo, OnMessageArrived, dónde pondríamos la lógica de tratamiento de estos comandos/eventos para asignárselos a sus correspondientes manejadores.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; OnMessageArrived(BrokeredMessage message)
        {
        }&lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Sencillo, ¿verdad?… Bueno, ya os dije que sería una entrada cortita…&lt;/p&gt;

&lt;p&gt;&amp;#160;&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=209461" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="Azure AppFabric" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure+AppFabric/default.aspx" /><category term="Azure" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="Bus" scheme="http://geeks.ms/blogs/unai/archive/tags/Bus/default.aspx" /><category term="C#" scheme="http://geeks.ms/blogs/unai/archive/tags/C_2300_/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>EF 6: Command rewriters - I</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/05/10/ef-6-command-rewriters-i.aspx" /><id>/blogs/unai/archive/2013/05/10/ef-6-command-rewriters-i.aspx</id><published>2013-05-10T11:03:19Z</published><updated>2013-05-10T11:03:19Z</updated><content type="html">&lt;p&gt;En las dos últimas dos entradas he hablado sobre el nuevo bloque introducido en Entity Framework 6 para la realización de intercepciones. Aunque en principio solamente hemos hablado de lo básico, como por ejemplo los diferentes &lt;a href="http://geeks.ms/blogs/unai/archive/2013/05/03/ef-6-sorpresa-interceptors.aspx"&gt;tracers&lt;/a&gt;, más aún con la nueva propiedad &lt;a href="http://geeks.ms/blogs/unai/archive/2013/05/08/ef-6-interceptors-segunda-iteraci-243-n.aspx"&gt;Database.Log&lt;/a&gt;, en realidad este bloque nos permite hacer cosas mucho más interesantes como por ejemplo el re-write de consultas. Si nos fijamos un poco en nuestra nueva clase DbInterceptor esta nos expone dos interfaces fundamentales &lt;strong&gt;IDbCommandInterceptor&lt;/strong&gt; y &lt;strong&gt;IDbCommandTreeInterceptor &lt;/strong&gt;de las que realmente podremos partir si queremos algo mucho más “a bajo nivel” dentro de la infraestructura de Entity Framework.&amp;#160; Con el fin de ver algo diferente a los procesos de instrumentalización de las consultas vamos a intentar crear algún ejemplo de intercepción con reescritura de consulta utilizando estas dos interfaces.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;IDbCommandInterceptor, reescritura de tu SQL&lt;/h3&gt;  &lt;p&gt;Como ya hemos comentado, esta interfaz nos ofrece los procesos de pre y post para las tareas habituales con la base de datos como por ejemplo son la ejecución de consultas y comandos. La idea para nuestra reescritura es poder introducir algún mecanismo que nos permita identificar un comando y proceder a su cambio, para verlo construiremos la siguiente clase CommandRewriter, la cual esta hecha a modo de ejemplo, intentaré poner pronto a vuestra disposición una implementación más apropiada de un sistema de reescritura de consultas.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CommandRewriter
        :IDbCommandInterceptor
    {

        &lt;span class="kwrd"&gt;int&lt;/span&gt; IDbCommandInterceptor.NonQueryExecuted(DbCommand command, &lt;span class="kwrd"&gt;int&lt;/span&gt; result, DbCommandInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        DbDataReader IDbCommandInterceptor.ReaderExecuted(DbCommand command, DbDataReader result, DbCommandInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;object&lt;/span&gt; IDbCommandInterceptor.ScalarExecuted(DbCommand command, &lt;span class="kwrd"&gt;object&lt;/span&gt; result, DbCommandInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;void&lt;/span&gt; IDbCommandInterceptor.NonQueryExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsCandidate(command))
            {
                Rewrite(command);
            }
        }

        &lt;span class="kwrd"&gt;void&lt;/span&gt; IDbCommandInterceptor.ScalarExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) 
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsCandidate(command))
            {
                Rewrite(command);
            }
        }

        &lt;span class="kwrd"&gt;void&lt;/span&gt; IDbCommandInterceptor.ReaderExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsCandidate(command))
            {
                Rewrite(command);
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsCandidate(DbCommand command);

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Rewrite(DbCommand command);
    }&lt;/pre&gt;

&lt;p&gt;Si nos fijamos, en realidad, no hemos hecho absolutamente nada, simplemente hemos puesto una pequeña comprobación antes de la ejecución de los comandos que nos permita identificar si ese comando es candidato a ser reescrito. En caso afirmativo procedemos a la tarea. Un ejemplo evidente de esta reescritura se produce cuando queremos cambiar una consulta exacta por otra, por ejemplo para poder utilizar algún hint, cambiar un parámetro etc. para esto, podríamos hacer algo trivial como sigue:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MatchCommandRewriter
        :CommandRewriter
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; MatchedQuery { get; }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; NewQuery { get; }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsCandidate(System.Data.Common.DbCommand command)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; String.Equals(command.CommandText, MatchedQuery, StringComparison.InvariantCultureIgnoreCase);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Rewrite(System.Data.Common.DbCommand command)
        {
            command.CommandText = NewQuery;
        }
    }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Ahora, que hemos creado estas simples bases, podríamos introducir una reescritura por ejemplo como la siguiente, que es&lt;strong&gt; solamente con fin ilustrativo&lt;/strong&gt;, , en la que introducimos un hint NOLOCK en la consulta:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomerNoLockQueryRewrite
        :MatchCommandRewriter
    {

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; MatchedQuery
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;SELECT \r\n[Extent1].[Id] AS [Id], \r\n[Extent1].[FirstName] AS [FirstName]\r\nFROM [dbo].[Customers] AS [Extent1]&amp;quot;&lt;/span&gt;;
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; NewQuery
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;SELECT [Extent1].[Id] AS [Id], [Extent1].[FirstName] AS [FirstName] FROM [dbo].[Customers] AS [Extent1] WITH (NOLOCK) &amp;quot;&lt;/span&gt;;
            }
        }
    }&lt;/pre&gt;


&lt;p&gt;Una vez creado nuestro rewriter solamente nos queda asignarlo, para lo cual, como ya sabemos de otras entradas tenemos nuestra clase Interception.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Interception.AddInterceptor(&lt;span class="kwrd"&gt;new&lt;/span&gt; CustomerNoLockQueryRewrite());&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;

&lt;p&gt;A lo largo de esta entrada hemos podido&amp;#160; ver como los interceptores sirven para mucho mas que para las trazas de nuestras consultas y podemos tener una ganancia importante con su uso dentro de nuestras aplicaciones. En esta primera edición hemos visto la intercepción de nuestras consultas SQL, para la siguiente intentaremos ver como modificar nuestros arboles de consulta antes de generar el SQL.&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=209439" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="Entity Framework 6" scheme="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework+6/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>EF 6: Interceptors, segunda iteración</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/05/08/ef-6-interceptors-segunda-iteraci-243-n.aspx" /><id>/blogs/unai/archive/2013/05/08/ef-6-interceptors-segunda-iteraci-243-n.aspx</id><published>2013-05-08T16:10:00Z</published><updated>2013-05-08T16:10:00Z</updated><content type="html">&lt;p&gt;Es lo malo de escribir posts con todo en desarrollo, que se quedan desactualizados de un d&amp;iacute;a para otro, de hecho, no tengo mucha idea de cuanto os pueden aportar, a vosotros amigos lectores, estas entradas que hago sobre EF 6 y quiz&amp;aacute;s &lt;span style="text-decoration:line-through;"&gt;seguramente&amp;nbsp; &lt;/span&gt;estoy perdiendo el tiempo, pero me cuesta, a&amp;uacute;n as&amp;iacute;, resistirme a hacerlo.&lt;/p&gt;
&lt;p&gt;En la &lt;a href="http://geeks.ms/blogs/unai/archive/2013/05/03/ef-6-sorpresa-interceptors.aspx"&gt;anterior entrada hemos&lt;/a&gt; visto los primeros pasos con interception y como pod&amp;iacute;amos configurar esta, despu&amp;eacute;s del &amp;uacute;ltimo &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/ba4b72171f3abc185829c92f09a93f3a2ba5efbb"&gt;commit de Arthur&lt;/a&gt; algunas cosas han cambiado y en mi opini&amp;oacute;n creo que han quedado mejor, mas consistentes con el dise&amp;ntilde;o actual.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El primer cambio es la creaci&amp;oacute;n de un DbCommandLogger y un DbCommandLoggerFactory, que nos permitir&amp;aacute;n disponer de una clase para el log de los diferentes comandos con una implementaci&amp;oacute;n por defecto que hace la escritura en un TextWriter que podemos establecer en su constructor.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;delegate&lt;/span&gt; DbCommandLogger DbCommandLoggerFactory(DbContext context, TextWriter writer);&lt;/pre&gt;
&lt;p&gt;Para establecer este DbCommandLogger tenemos una nueva propiedad en nuestro objeto Database que nos permite establecer un TextWriter a utilizar, en realidad aunque lo que hacemos en esta propiedad es establecer el TextWriter internamente se establecer un command logger con ese text writer. F&amp;iacute;jese en nuestro siguiente c&amp;oacute;digo como podemos establecer la consola de salida como logger de los diferentes comandos ejecutados por Entity Framework.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CRMContext
        :DbContext
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; DbSet&amp;lt;Customer&amp;gt; Customers { get; set; }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; CRMContext()
        {
            Database.Log = Console.Out;
        }
    }&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Por supuesto, si queremos cambiar nuestro DbCommandLogger por defecto podremos hacerlo, para ello, como siempre podemos acudir a nuestro DbConfiguration y establecer un Dependency Resolver o bien setearlo con el nuevo m&amp;eacute;todo SetCommandLogger.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Configuration
        :DbConfiguration
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Configuration()
        {
            SetCommandLogger((context, writer) =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; DbCommandLogger(context, writer));
        }
    }&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Bueno, lo dicho, no se si estas pinceladas son interesantes para vosotros amigos lectores, pero espero que si y sobre todo que dej&amp;eacute;is feedback de lo que necesit&amp;aacute;is en el producto.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&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=209422" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /><category term="Entity Framework 6" scheme="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework+6/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>EF 6: Sorpresa, interceptors</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/05/03/ef-6-sorpresa-interceptors.aspx" /><id>/blogs/unai/archive/2013/05/03/ef-6-sorpresa-interceptors.aspx</id><published>2013-05-03T08:49:40Z</published><updated>2013-05-03T08:49:40Z</updated><content type="html">&lt;p&gt;Pues si, digo bien con sorpresa, porque hasta ahora yo no era consciente de que esta fuera a ser una de las nuevas características de &lt;a href="http://entityframework.codeplex.com/"&gt;EF 6&lt;/a&gt;, de hecho si miramos el &lt;a href="http://entityframework.codeplex.com/wikipage?title=Roadmap"&gt;roadmap&lt;/a&gt; veremos que no estaba contemplada. Pero por lo que sea ya tenemos aquí los primeros &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/1adce0b65e3cd3b2e6aecabed56a03f21b094f61"&gt;commits&lt;/a&gt; relacionados con la posibilidad de implementar mecanismos de intercepción en la nueva versión de &lt;a href="http://entityframework.codeplex.com/"&gt;Entity Framework&lt;/a&gt;. Aunque seguramente cambiarán ciertas cosas hasta la versión final,&amp;#160; no me puedo resistir a enseñaros alguna pincelada.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h1&gt;Interception&lt;/h1&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;La clase estática &lt;strong&gt;Interception &lt;/strong&gt;representa por ahora el punto dónde podemos agregar y quitar nuestros interceptores. En realidad, esto me ha chocado un poco porque creía que era un patrón obsoleto como el uso de Database en anteriores versiones, y creo que va a cambiar,&amp;#160; aunque en el &lt;a href="http://entityframework.codeplex.com/discussions/442371"&gt;tablero de preguntas&lt;/a&gt; del proyecto hay una pregunta abierta que espero que respondan. Esta clase es tan simple como vemos a continuación.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&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; Interception
    {
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Registers a new &amp;lt;see cref=&amp;quot;IDbInterceptor&amp;quot; /&amp;gt; to receive notifications. Note that the interceptor&lt;/span&gt;
        &lt;span class="rem"&gt;///     must implement some interface that extends from &amp;lt;see cref=&amp;quot;IDbInterceptor&amp;quot; /&amp;gt; to be useful.&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;interceptor&amp;quot;&amp;gt;The interceptor to add.&amp;lt;/param&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;void&lt;/span&gt; AddInterceptor(IDbInterceptor interceptor)
        {          
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Removes a registered &amp;lt;see cref=&amp;quot;IDbInterceptor&amp;quot; /&amp;gt; so that it will no longer receive notifications.&lt;/span&gt;
        &lt;span class="rem"&gt;///     If the given interceptor is not registered, then this is a no-op.&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;interceptor&amp;quot;&amp;gt;The interceptor to remove.&amp;lt;/param&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;void&lt;/span&gt; RemoveInterceptor(IDbInterceptor interceptor)
        { 
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     This is the entry point for dispatching to interceptors. This is usually only used internally by&lt;/span&gt;
        &lt;span class="rem"&gt;///     Entity Framework but it is provided publicly so that other code can make sure that registered&lt;/span&gt;
        &lt;span class="rem"&gt;///     interceptors are called when operations are performed on behalf of EF. For example, EF providers&lt;/span&gt;
        &lt;span class="rem"&gt;///     a may make use of this when executing commands.&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; Dispatchers Dispatch
        {
        }
    }&lt;/pre&gt;

&lt;p&gt;Como se puede ver, en realidad, lo que nos ofrece es un mecanismo para agregar y quitar interceptores, pensado en enchufar los mismos solamente en ciertas partes del trabajo o momentos determinados. De hecho la nueva característica de scaffolding de los procedimientos almacenados se basa en esta infraestructura. A mayores de esto, vemos como un interceptor no es más que cualquier clase que implemente &lt;strong&gt;IDbInterceptor, &lt;/strong&gt;por suerte, a nosotros ya nos ofrecen una clase base&amp;#160; de la que partir llamada &lt;strong&gt;DbInterceptor&lt;/strong&gt;, que será la que usemos por norma general.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DbInterceptor : IDbCommandInterceptor, IDbCommandTreeInterceptor
    {
        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; DbCommandTree TreeCreated(DbCommandTree commandTree, DbInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; commandTree;
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&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;void&lt;/span&gt; NonQueryExecuting(DbCommand command, DbInterceptionContext interceptionContext)
        {
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&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; NonQueryExecuted(DbCommand command, &lt;span class="kwrd"&gt;int&lt;/span&gt; result, DbInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&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;void&lt;/span&gt; ReaderExecuting(DbCommand command, CommandBehavior behavior, DbInterceptionContext interceptionContext)
        {
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; DbDataReader ReaderExecuted(
            DbCommand command, CommandBehavior behavior, DbDataReader result, DbInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&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;void&lt;/span&gt; ScalarExecuting(DbCommand command, DbInterceptionContext interceptionContext)
        {
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&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;object&lt;/span&gt; ScalarExecuted(DbCommand command, &lt;span class="kwrd"&gt;object&lt;/span&gt; result, DbInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&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;void&lt;/span&gt; AsyncNonQueryExecuting(DbCommand command, DbInterceptionContext interceptionContext)
        {
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; Task&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; AsyncNonQueryExecuted(DbCommand command, Task&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; result, DbInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&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;void&lt;/span&gt; AsyncReaderExecuting(DbCommand command, CommandBehavior behavior, DbInterceptionContext interceptionContext)
        {
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; Task&amp;lt;DbDataReader&amp;gt; AsyncReaderExecuted(
            DbCommand command, CommandBehavior behavior, Task&amp;lt;DbDataReader&amp;gt; result, DbInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&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;void&lt;/span&gt; AsyncScalarExecuting(DbCommand command, DbInterceptionContext interceptionContext)
        {
        }

        &lt;span class="rem"&gt;/// &amp;lt;inheritdoc /&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; Task&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; AsyncScalarExecuted(DbCommand command, Task&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; result, DbInterceptionContext interceptionContext)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }
    }&lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Como podéis ver, hay muchos métodos en los que nos podemos enganchar, tanto para llamadas síncronas como asíncronas, así como a ciertores pre-post procesos, como por ejemplo en la ejecución de comandos. Un hola mundo, podría ser el siguiente, donde sacamos por la consola las consultas de lectura ejecutadas por EF:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TracerInterceptor
        :DbInterceptor
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; DbDataReader ReaderExecuted(DbCommand command, System.Data.CommandBehavior behavior, DbDataReader result, DbInterceptionContext interceptionContext)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;CommandText:{0}&amp;quot;&lt;/span&gt;,command.CommandText);

            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }
    }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h1&gt;&lt;/h1&gt;

&lt;h1&gt;&lt;/h1&gt;

&lt;h1&gt;Feedback&lt;/h1&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Estoy seguro que todo el equipo va a necesitar feedback de esta nueva característica, que os gusta, que no, que necesitáis que no tengáis etc. por eso me gustaría pediros a todos que os animéis a pasar por el portal del producto y dejar vuestras necesidades / recomendaciones 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=209386" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="Entity Framework" scheme="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework/default.aspx" /><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /><category term="Entity Framework 6" scheme="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework+6/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>EF 6:Nuevas pequeñas grandes cosas..</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/04/25/ef-6-nuevas-peque-241-as-grandes-cosas.aspx" /><id>/blogs/unai/archive/2013/04/25/ef-6-nuevas-peque-241-as-grandes-cosas.aspx</id><published>2013-04-25T20:24:46Z</published><updated>2013-04-25T20:24:46Z</updated><content type="html">&lt;p&gt;Creo que son ya unas cuantas entradas las que llevo con EF 6 en este blog, y eso que aún no tenemos ni la primera CTP, pero a cada nueva build que hacen podemos ver nuevas e interesantes cosas que me gusta adelantarme a escribir. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;De entre estas nuevas cosillas me gustaría destacar estos tres nuevos métodos que he podido contribuir en sus correspondientes pull request ( &lt;a href="http://entityframework.codeplex.com/SourceControl/network/forks/UnaiZorrilla/efissue965/contribution/4501"&gt;addrange&lt;/a&gt;, &lt;a href="https://entityframework.codeplex.com/SourceControl/network/forks/UnaiZorrilla/ef1050/contribution/4512"&gt;removerange&lt;/a&gt;, &lt;a href="https://entityframework.codeplex.com/SourceControl/network/forks/UnaiZorrilla/ef1043/contribution/4510"&gt;haschanges&lt;/a&gt; )&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h1&gt;AddRange&lt;/h1&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Como seguramente os imaginaréis, &lt;a href="http://entityframework.codeplex.com/SourceControl/network/forks/UnaiZorrilla/efissue965/contribution/4501"&gt;este pequeño método nos&lt;/a&gt; permite agregar dentro de nuestros DbSet&amp;lt;T&amp;gt; y DbSet un conjunto de elementos de una única pasada, evitando así tener que hacer las n repetitivas llamadas al método Add. Aunque esto parezca trivial, y en realidad, fuera fácil de construir con un método extensor, la verdad es que tiene un pelín más de miga, puesto que algo que podíamos hacer era aprovechar este nuevo método para evitar la detección de cambios para cada uno de los elementos de la colección a incluir.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Como seguramente sabréis, EF realiza un proceso de detección de cambios de forma automática ( si no hemos configurado lo contrario ) en ciertos procesos, como por ejemplo en el de agregar elementos al DbSet, por lo tanto, esto podría suponer una sobrecarga en ciertos escenarios con muchas entradas en el &lt;strong&gt;ObjectStateManager&lt;/strong&gt;. Si quieres saber más sobre la detección de cambios en EF, entonces nada mejor que leer del mejor, en concreto, esta serie de &lt;a href="http://blog.oneunicorn.com/2012/03/10/secrets-of-detectchanges-part-1-what-does-detectchanges-do/"&gt;Arthur Vickers&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Al final, una vez valorado esto y agregado este nuevo método en la superficie publica de DbSet&amp;lt;T&amp;gt; y DbSet, el código queda tan liviano como vemos a continuación en el método AddRange de nuestro InternalSet.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddRange(IEnumerable entities)
        {
            DebugCheck.NotNull(entities);

            InternalContext.DetectChanges();

            ActOnSet(
                entity =&amp;gt; InternalContext.ObjectContext.AddObject(EntitySetName, entity), EntityState.Added, entities, &lt;span class="str"&gt;&amp;quot;Add&amp;quot;&lt;/span&gt;);
        }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h1&gt;RemoveRange&lt;/h1&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Bien, después de explicado lo anterior, este es de cajón, en realidad aplican los mimos argumentos con respecto a relajar la detección de cambios, por lo tanto, la implementación en nuestro InternalSet es similar a lo siguiente:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RemoveRange(IEnumerable entities)
        {
            DebugCheck.NotNull(entities);

            &lt;span class="rem"&gt;// prevent &amp;quot;enumerator was changed&amp;quot; exception&lt;/span&gt;
            &lt;span class="rem"&gt;// if entities is syncronized with other elements&lt;/span&gt;
            &lt;span class="rem"&gt;// (e.g: local view from DbSet.Local.)&lt;/span&gt;
            var copyOfEntities = entities
                .Cast&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;().ToList();

            InternalContext.DetectChanges();

            ActOnSet(
                entity =&amp;gt; InternalContext.ObjectContext.DeleteObject(entity), EntityState.Deleted, copyOfEntities, &lt;span class="str"&gt;&amp;quot;Delete&amp;quot;&lt;/span&gt;);
        }&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;

&lt;h1&gt;HasChanges&lt;/h1&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Este método es una pequeña ayuda para comprobar si nuestra unidad de trabajo tiene cambios pendientes, elementos agregados, borrados o modificados en la misma y no llevados aún a la base de datos. El mismo está situado en la clase DbChangeTracker y como podemos ver en el siguiente tests funcional lo tendremos accesible mediante la propiedad ChangeTracker de nuestros DbContext.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        [Fact]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; HasChanges_return_true_if_context_have_entities_in_deleted_state()
        {
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (var context = &lt;span class="kwrd"&gt;new&lt;/span&gt; SomeContext())
            {
                var foo = &lt;span class="kwrd"&gt;new&lt;/span&gt; Foo() { Bar = &lt;span class="str"&gt;&amp;quot;the foo&amp;quot;&lt;/span&gt; };

                context.Foos.Attach(foo);
                context.Entry(foo).State = EntityState.Deleted;

                Assert.True(context.ChangeTracker.HasChanges());
            }
        }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;La implementación es realmente sencilla puesto que internamente ya se dispone de un método para comprobar el número de entradas en el ObjectStateManager.&lt;/p&gt;

&lt;p&gt;&amp;#160;&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;///     Check if the &amp;lt;see cref=&amp;quot;DbContext&amp;quot; /&amp;gt; contain changes, added, modified or deleted entities and relationships of POCO entities. &lt;/span&gt;
        &lt;span class="rem"&gt;///     This method call first to detect changes on the underlying &amp;lt;see cref=&amp;quot;DbContext&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;True if underlying &amp;lt;see cref=&amp;quot;DbContext&amp;quot; /&amp;gt; have changes, else false.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; HasChanges()
        {
            _internalContext.DetectChanges();

            var objectStateManager = _internalContext
               .ObjectContext.ObjectStateManager;

            DebugCheck.NotNull(objectStateManager);

            var entriesAffected =
              objectStateManager.GetObjectStateEntriesCount(EntityState.Added | EntityState.Deleted | EntityState.Modified);


            &lt;span class="kwrd"&gt;return&lt;/span&gt; entriesAffected &amp;gt; 0;
        }&lt;/pre&gt;

&lt;p&gt;Para terminar esta pequeña entrada me gustaría hablar de otra “gran” novedad que tenemos en las últimas builds de EF, novedad introducida por el propio equipo, en concreto por Andrew Peters (@anpete), que consiste en la posibilidad de hacer el scaffolding de las entidades mapeadas con procedimientos almacenados de forma automática. Lo mejor para explicarlo es ver un pequeño ejemplo, para ello partiremos del siguiente modelo y su correspondiente configuración:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Blog
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Id { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FirstName { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; LastName { get; set; }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BlogContext
        :DbContext
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; DbSet&amp;lt;Blog&amp;gt; Blogs { get; set; }

        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.AddFromAssembly(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(BlogContext).Assembly);
        }
    }

    &lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BlogConfiguration
        :EntityTypeConfiguration&amp;lt;Blog&amp;gt;
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; BlogConfiguration()
        {
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.MapToStoredProcedures();
        }
    }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Nada nuevo, o por lo menos de lo que no hayamos hablado ya, una entidad mapeada con procedimientos almacenados por medió del método &lt;strong&gt;MapToStoreProcedures&lt;/strong&gt;, aplicando convenciones al no estar “configurado”. Lo nuevo en las últimas builds, le recomiendo usar los paquetes de NuGet del feed de ASP.NET Stack nightly builds, está en que las migraciones son capaces de hacer el scaffolding de estos procedimientos almacenados, por lo tanto, si ejecutaramos la creación de una migración, tal cual sigue:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;PM&amp;gt; enable-migrations
Checking &lt;span class="kwrd"&gt;if&lt;/span&gt; the context targets an existing database...
Code First Migrations enabled &lt;span class="kwrd"&gt;for&lt;/span&gt; project MapToStoreProcedures.&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;PM&amp;gt; Add-Migration InitialScaffolding
Scaffolding migration &lt;span class="str"&gt;&amp;#39;InitialScaffolding&amp;#39;&lt;/span&gt;.
The Designer Code &lt;span class="kwrd"&gt;for&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt; migration file includes a snapshot of your current Code First model. This snapshot &lt;span class="kwrd"&gt;is&lt;/span&gt; used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt; migration, then you can re-scaffold it by running &lt;span class="str"&gt;&amp;#39;Add-Migration InitialScaffolding&amp;#39;&lt;/span&gt; again.&lt;/pre&gt;

&lt;p&gt;Veríamos un resultado similar a lo siguiente:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; MapToStoreProcedures.Migrations
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt; System;
    &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Data.Entity.Migrations;
    
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; InitialScaffolding : DbMigration
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Up()
        {
            CreateTable(
                &lt;span class="str"&gt;&amp;quot;dbo.Blogs&amp;quot;&lt;/span&gt;,
                c =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt;
                    {
                        Id = c.Int(nullable: &lt;span class="kwrd"&gt;false&lt;/span&gt;, identity: &lt;span class="kwrd"&gt;true&lt;/span&gt;),
                        FirstName = c.String(),
                        LastName = c.String(),
                    })
                .PrimaryKey(t =&amp;gt; t.Id);
            
            CreateStoredProcedure(
                &lt;span class="str"&gt;&amp;quot;Blog_Insert&amp;quot;&lt;/span&gt;,
                p =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt;
                    {
                        FirstName = p.String(),
                        LastName = p.String(),
                    },
                body:
                    &lt;span class="str"&gt;@&amp;quot;INSERT [dbo].[Blogs]([FirstName], [LastName])
                      VALUES (@FirstName, @LastName)
                      
                      DECLARE @Id int
                      SELECT @Id = [Id]
                      FROM [dbo].[Blogs]
                      WHERE @@ROWCOUNT &amp;gt; 0 and [Id] = scope_identity()
                      
                      SELECT t0.[Id]
                      FROM [dbo].[Blogs] as t0
                      WHERE @@ROWCOUNT &amp;gt; 0 and t0.[Id] = @Id&amp;quot;&lt;/span&gt;
            );
            
            CreateStoredProcedure(
                &lt;span class="str"&gt;&amp;quot;Blog_Update&amp;quot;&lt;/span&gt;,
                p =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt;
                    {
                        Id = p.Int(),
                        FirstName = p.String(),
                        LastName = p.String(),
                    },
                body:
                    &lt;span class="str"&gt;@&amp;quot;UPDATE [dbo].[Blogs]
                      SET [FirstName] = @FirstName, [LastName] = @LastName
                      WHERE ([Id] = @Id)&amp;quot;&lt;/span&gt;
            );
            
            CreateStoredProcedure(
                &lt;span class="str"&gt;&amp;quot;Blog_Delete&amp;quot;&lt;/span&gt;,
                p =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt;
                    {
                        Id = p.Int(),
                    },
                body:
                    &lt;span class="str"&gt;@&amp;quot;DELETE [dbo].[Blogs]
                      WHERE ([Id] = @Id)&amp;quot;&lt;/span&gt;
            );
            
        }
        
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Down()
        {
            DropStoredProcedure(&lt;span class="str"&gt;&amp;quot;Blog_Delete&amp;quot;&lt;/span&gt;);
            DropStoredProcedure(&lt;span class="str"&gt;&amp;quot;Blog_Update&amp;quot;&lt;/span&gt;);
            DropStoredProcedure(&lt;span class="str"&gt;&amp;quot;Blog_Insert&amp;quot;&lt;/span&gt;);
            DropTable(&lt;span class="str"&gt;&amp;quot;dbo.Blogs&amp;quot;&lt;/span&gt;);
        }
    }
}&lt;/pre&gt;


&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;

&lt;p&gt;¿Qué os parece? &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;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=209295" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term=".NET General" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx" /><category term="Entity Framework" scheme="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework/default.aspx" /><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /><category term="Entity Framework 6" scheme="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework+6/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>EF 6: Connection resiliency y azure</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/03/13/ef-6-connection-resiliency-y-azure.aspx" /><id>/blogs/unai/archive/2013/03/13/ef-6-connection-resiliency-y-azure.aspx</id><published>2013-03-13T22:45:55Z</published><updated>2013-03-13T22:45:55Z</updated><content type="html">&lt;p&gt;Seguro que de muchos es sabido que cuando trabajamos con Sql Database es posible que alguna de nuestras operaciones pueda fallar, independientemente de si usamos EF, NH o directamente con nuestro SqlClient, debido a inestabilidades de la red o problemas de back-end [si desea explorar el porque de la realidad de estos problemas le recomiendo &lt;a href="http://social.technet.microsoft.com/wiki/contents/articles/1541.windows-azure-sql-database-connection-management.aspx"&gt;este enlace&lt;/a&gt;].&amp;#160; Aunque en la realidad esto no es algo ni mucho menos habitual, puede pasar, y, por lo general, sino somos conscientes de ello suele dar bastantes dolores de cabeza, por lo aleatorio de los fallos. Por supuesto, hay muchos workaround para este problema, y como no, también para los que usamos actualmente EF, en cualquier de sus versiones como por ejemplo este que comenta mi buen amigo &lt;a href="http://blogs.msdn.com/b/cesardelatorre/archive/2010/12/20/handling-sql-azure-connections-issues-using-entity-framework-4-0.aspx"&gt;Cesar de La Torre.&lt;/a&gt; en un post de hace una eternidad. Con el fin de hacer&amp;#160; esto más sencillo para nosotros y en realidad para resolver otros posibles problema similares para este u otros motores relacionales el equipo de EF ya tiene en la &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/view/0a796b9b9b27"&gt;rama de EF 6 nuevas funcionalidades&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Estas nuevas características se pueden concretar en los siguientes elementos:&lt;/p&gt;  &lt;h3&gt;IExecutionStrategy&lt;/h3&gt;  &lt;p&gt;Esta interfaz define el contrato para la pieza que tendrá como responsabilidad la ejecución de operaciones que potencialmente necesiten reintentarse, por ejemplo las operaciones sobre Sql Database. El contrato de esta interfaz no es nada complicado como podemos ver a continuación:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;﻿&lt;span class="kwrd"&gt;namespace&lt;/span&gt; System.Data.Entity.Infrastructure
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Diagnostics.CodeAnalysis;
    &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading;
    &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Threading.Tasks;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IExecutionStrategy
    {
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Indicates whether this &amp;lt;see cref=&amp;quot;IExecutionStrategy&amp;quot;/&amp;gt; might retry the execution after a failure.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;bool&lt;/span&gt; RetriesOnFailure { get; }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Executes the specified action.&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;action&amp;quot;&amp;gt;A delegate representing an executable action that doesn&amp;#39;t return any results.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Execute(Action action);

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Executes the specified function and returns the result.&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;TResult&amp;quot;&amp;gt;The return type of &amp;lt;paramref name=&amp;quot;func&amp;quot;/&amp;gt;.&amp;lt;/typeparam&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;func&amp;quot;&amp;gt;A delegate representing an executable action that returns the result of type &amp;lt;typeparamref name=&amp;quot;TResult&amp;quot;/&amp;gt;.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;The result from the action.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        TResult Execute&amp;lt;TResult&amp;gt;(Func&amp;lt;TResult&amp;gt; func);
        
&lt;span class="preproc"&gt;#if&lt;/span&gt; !NET40

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Executes the specified asynchronous action.&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;taskAction&amp;quot;&amp;gt;A function that returns a started task.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     A task that will run to completion if the original task completes successfully (either the&lt;/span&gt;
        &lt;span class="rem"&gt;///     first time or after retrying transient failures). If the task fails with a non-transient error or&lt;/span&gt;
        &lt;span class="rem"&gt;///     the retry limit is reached, the returned task will become faulted and the exception must be observed.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/returns&amp;gt;&lt;/span&gt;
        Task ExecuteAsync(Func&amp;lt;Task&amp;gt; taskFunc);

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Executes the specified asynchronous action.&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;taskAction&amp;quot;&amp;gt;A function that returns a started task.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;cancellationToken&amp;quot;&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     A cancellation token used to cancel the retry operation, but not operations that are already in flight&lt;/span&gt;
        &lt;span class="rem"&gt;///     or that already completed successfully.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     A task that will run to completion if the original task completes successfully (either the&lt;/span&gt;
        &lt;span class="rem"&gt;///     first time or after retrying transient failures). If the task fails with a non-transient error or&lt;/span&gt;
        &lt;span class="rem"&gt;///     the retry limit is reached, the returned task will become faulted and the exception must be observed.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/returns&amp;gt;&lt;/span&gt;
        Task ExecuteAsync(Func&amp;lt;Task&amp;gt; taskFunc, CancellationToken cancellationToken);

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Executes the specified asynchronous function and returns the result.&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;TResult&amp;quot;&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     The type parameter of the &amp;lt;see cref=&amp;quot;Task{T}&amp;quot;/&amp;gt; returned by &amp;lt;paramref name=&amp;quot;taskFunc&amp;quot;/&amp;gt;.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/typeparam&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;taskFunc&amp;quot;&amp;gt;A function that returns a started task of type &amp;lt;typeparamref name=&amp;quot;TResult&amp;quot;/&amp;gt;.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     A task that will run to completion if the original task completes successfully (either the&lt;/span&gt;
        &lt;span class="rem"&gt;///     first time or after retrying transient failures). If the task fails with a non-transient error or&lt;/span&gt;
        &lt;span class="rem"&gt;///     the retry limit is reached, the returned task will become faulted and the exception must be observed.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/returns&amp;gt;&lt;/span&gt;
        [SuppressMessage(&lt;span class="str"&gt;&amp;quot;Microsoft.Design&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;CA1006:DoNotNestGenericTypesInMemberSignatures&amp;quot;&lt;/span&gt;)]
        Task&amp;lt;TResult&amp;gt; ExecuteAsync&amp;lt;TResult&amp;gt;(Func&amp;lt;Task&amp;lt;TResult&amp;gt;&amp;gt; taskFunc);

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Executes the specified asynchronous function and returns the result.&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;TResult&amp;quot;&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     The type parameter of the &amp;lt;see cref=&amp;quot;Task{T}&amp;quot;/&amp;gt; returned by &amp;lt;paramref name=&amp;quot;taskFunc&amp;quot;/&amp;gt;.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/typeparam&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;taskFunc&amp;quot;&amp;gt;A function that returns a started task of type &amp;lt;typeparamref name=&amp;quot;TResult&amp;quot;/&amp;gt;.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;cancellationToken&amp;quot;&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     A cancellation token used to cancel the retry operation, but not operations that are already in flight&lt;/span&gt;
        &lt;span class="rem"&gt;///     or that already completed successfully.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     A task that will run to completion if the original task completes successfully (either the&lt;/span&gt;
        &lt;span class="rem"&gt;///     first time or after retrying transient failures). If the task fails with a non-transient error or&lt;/span&gt;
        &lt;span class="rem"&gt;///     the retry limit is reached, the returned task will become faulted and the exception must be observed.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/returns&amp;gt;&lt;/span&gt;
        [SuppressMessage(&lt;span class="str"&gt;&amp;quot;Microsoft.Design&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;CA1006:DoNotNestGenericTypesInMemberSignatures&amp;quot;&lt;/span&gt;)]
        Task&amp;lt;TResult&amp;gt; ExecuteAsync&amp;lt;TResult&amp;gt;(Func&amp;lt;Task&amp;lt;TResult&amp;gt;&amp;gt; taskFunc, CancellationToken cancellationToken);

&lt;span class="preproc"&gt;#endif&lt;/span&gt;

    }
}&lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;La idea básica que hay detrás de esta interfaz es poder envolver una acción en un determinado ámbito capaz de decidir si las excepciones que se produzcan son o no candidatas para reintentarse, por ejemplo porque entendemos que es un fallo de Sql Database y no relacionado con el mapeo, consulta etc…, cada cierto tiempo. Por supuesto, decidir si una excepción&amp;#160; de una operación implica que la operación debe repetirse es algo configurable y no fijo, cuya implementación esta marcada por una nueva interfaz, que vemos a continuación.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;IRetriableExceptionDetector&lt;/h3&gt;

&lt;p&gt;Mediante este contrato tendremos la posibilidad de especificar que excepciones son candidatas a “resolver” por medio de reintentos, el siguiente código representa este contrato&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;﻿&lt;span class="rem"&gt;// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.&lt;/span&gt;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; System.Data.Entity.Infrastructure
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IRetriableExceptionDetector
    {
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Determines whether the specified exception represents a transient failure that can be compensated by a retry.&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;ex&amp;quot;&amp;gt;The exception object to be verified.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;c&amp;gt;true&amp;lt;/c&amp;gt; if the specified exception is considered as transient, otherwise &amp;lt;c&amp;gt;false&amp;lt;/c&amp;gt;.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;bool&lt;/span&gt; ShouldRetryOn(Exception ex);
    }
}&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;IRetryDelayStrategy&lt;/h3&gt;

&lt;p&gt;Este es el último elemento que necesitamos, y probablemente el más sencillo puesto que tiene como única finalidad marcar el tiempo entre reintentos de operaciones fallidas.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.&lt;/span&gt;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; System.Data.Entity.Infrastructure
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IRetryDelayStrategy
    {
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Determines whether the action should be retried and the delay before the next attempt.&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;lastException&amp;quot;&amp;gt;The exception thrown during the last execution attempt.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Returns the delay indicating how long to wait for before the next execution attempt if the action should be retried;&lt;/span&gt;
        &lt;span class="rem"&gt;///     &amp;lt;c&amp;gt;null&amp;lt;/c&amp;gt; otherwise&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/returns&amp;gt;&lt;/span&gt;
        TimeSpan? GetNextDelay(Exception lastException);
    }
}&lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Bien, ahora que ya conocemos las piezas, ya podemos entender que tenemos para Sql Database, y esto, no es más que implementaciones concretas para estos contratos que podemos “inyectar” dentro de EF .&lt;/p&gt;

&lt;p&gt;La implementación para el trabajo de Azure, Sql Database, se basa principalmente en la clase &lt;strong&gt;SqlAzureExecutionStrategy&lt;/strong&gt;, que tendremos por defecto en el proveedor de Sql Server por defecto.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;﻿&lt;span class="rem"&gt;// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.&lt;/span&gt;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; System.Data.Entity.SqlServer
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Data.Entity.Infrastructure;

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;///     An &amp;lt;see cref=&amp;quot;ExecutionStrategy&amp;quot;/&amp;gt; that uses the &amp;lt;see cref=&amp;quot;ExponentialRetryDelayStrategy&amp;quot;/&amp;gt; and&lt;/span&gt;
    &lt;span class="rem"&gt;///     &amp;lt;see cref=&amp;quot;SqlAzureRetriableExceptionDetector&amp;quot;/&amp;gt;.&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    [DbProviderName(&lt;span class="str"&gt;&amp;quot;System.Data.SqlClient&amp;quot;&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SqlAzureExecutionStrategy : ExecutionStrategy
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; SqlAzureExecutionStrategy()
            : &lt;span class="kwrd"&gt;base&lt;/span&gt;(&lt;span class="kwrd"&gt;new&lt;/span&gt; ExponentialRetryDelayStrategy(), &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlAzureRetriableExceptionDetector())
        {
        }
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Como observará, en realidad esto no tiene nada más que el marcador de tiempos, &lt;strong&gt;ExponentialRetryDelayStrategy&lt;/strong&gt;, que cuyo nombre indica hace un incremento exponencial basado en la siguiente fórmula:min &lt;strong&gt;(minDelay + coefficient * random(1, maxRandomFactor) * (exponentialBase ^ retryCount - 1), maxDelay), &lt;/strong&gt;y un detector de excepciones personalizado que permitirá reintentar las siguientes excepciones.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;SqlException con diferentes numberos de error, revisar el código siguiente para ver los &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/view/0a796b9b9b27#src/EntityFramework.SqlServer/SqlAzureRetriableExceptionDetector.cs"&gt;casos concretos&lt;/a&gt;.&lt;/li&gt;

  &lt;li&gt;Un TimeoutException.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Como se establece la estrategia que queremos usar? por ejemplo esta para Sql Database?, pues bien, tan simple como hacemos otras inyecciones, por medio de nuestro &lt;strong&gt;DbConfiguration&lt;/strong&gt; y el método &lt;strong&gt;AddExecutionStrategy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&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;///     Call this method from the constructor of a class derived from &amp;lt;see cref=&amp;quot;DbConfiguration&amp;quot; /&amp;gt; to add an&lt;/span&gt;
        &lt;span class="rem"&gt;///     &amp;lt;see cref=&amp;quot;IExecutionStrategy&amp;quot;/&amp;gt; for use with the associated provider.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     The &amp;lt;typeparamref name=&amp;quot;T&amp;quot;/&amp;gt; type should have a &amp;lt;see cref=&amp;quot;DbProviderNameAttribute&amp;quot;/&amp;gt; applied to it.&lt;/span&gt;
        &lt;span class="rem"&gt;///     This method is provided as a convenient and discoverable way to add configuration to the Entity Framework.&lt;/span&gt;
        &lt;span class="rem"&gt;///     Internally it works in the same way as using AddDependencyResolver to add an appropriate resolver for&lt;/span&gt;
        &lt;span class="rem"&gt;///     &amp;lt;see cref=&amp;quot;IExecutionStrategy&amp;quot; /&amp;gt;. This means that, if desired, the same functionality can be achieved using&lt;/span&gt;
        &lt;span class="rem"&gt;///     a custom resolver or a resolver backed by an Inversion-of-Control container.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;typeparam name=&amp;quot;T&amp;quot;&amp;gt; The type that implements &amp;lt;see cref=&amp;quot;IExecutionStrategy&amp;quot;/&amp;gt;. &amp;lt;/typeparam&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;getExecutionStrategy&amp;quot;&amp;gt; A function that returns a new instance of an execution strategy. &amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddExecutionStrategy&amp;lt;T&amp;gt;(Func&amp;lt;T&amp;gt; getExecutionStrategy)
            &lt;span class="kwrd"&gt;where&lt;/span&gt; T : IExecutionStrategy
        {
            Check.NotNull(getExecutionStrategy, &lt;span class="str"&gt;&amp;quot;getExecutionStrategy&amp;quot;&lt;/span&gt;);

            _internalConfiguration.CheckNotLocked(&lt;span class="str"&gt;&amp;quot;AddExecutionStrategy&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var providerInvariantNameAttribute &lt;span class="kwrd"&gt;in&lt;/span&gt; DbProviderNameAttribute.GetFromType(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(T)))
            {
                _internalConfiguration.AddDependencyResolver(
                    &lt;span class="kwrd"&gt;new&lt;/span&gt; ExecutionStrategyResolver&amp;lt;T&amp;gt;(providerInvariantNameAttribute.Name, &lt;span class="rem"&gt;/*serverName:*/&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;, getExecutionStrategy));
            }
        }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Si nos fijamos un poco veremos como lo primero que hace este método es recuperar el proveedor para el que aplica esta estrategia, buscando un atributo, &lt;strong&gt;DbProviderName&lt;/strong&gt;. Una vez localizado este atributo se establece el dependency resolver con la estrategia indicada. A partir de ese momento, ya tendremos disponible nuestra estrategia de reintentos..&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Bueno, esto ha sido todo, espero que os sigan gustando las novedades de EF 6 y que sigáis &lt;a href="http://blogs.msdn.com/b/adonet/archive/2013/02/27/ef6-alpha-3-available-on-nuget.aspx"&gt;viendo todo lo nuevo que poco a poco vamos teniendo&lt;/a&gt;…&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=208852" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="Entity Framework" scheme="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework/default.aspx" /><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /></entry><entry><title>EF 6: Snack Preview de MapToStoreProcedures en EF 6</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/02/27/ef-6-snack-preview-de-maptostoreprocedures-en-ef-6.aspx" /><id>/blogs/unai/archive/2013/02/27/ef-6-snack-preview-de-maptostoreprocedures-en-ef-6.aspx</id><published>2013-02-27T17:33:07Z</published><updated>2013-02-27T17:33:07Z</updated><content type="html">&lt;p&gt;Por diversas razones, que no son objetivo de este post, el mapeo a procedimientos almacenados ha sido una de los issues más votados dentro del proyecto &lt;a href="http://entityframework.codeplex.com"&gt;de EF 6,&lt;/a&gt; y por eso, tal como estaba en el roadmap inicial, el equipo ya ha empezado a trabajar en esta característica, de la cual ya tenemos algo hecho con lo que podemos jugar. Aunque aún tengo unas cuantas preguntas sin responder del equipo, con las fuentes actuales vemos como se ha incluído un nuevo método &lt;strong&gt;MapToStoreProcedures&lt;/strong&gt; dentro de nuestra bien conocida clase&lt;strong&gt; EntityTypeConfiguration&amp;lt;T&amp;gt;.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;        [SuppressMessage(&lt;span class="str"&gt;&amp;quot;Microsoft.Design&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;CA1006:DoNotNestGenericTypesInMemberSignatures&amp;quot;&lt;/span&gt;)]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; EntityTypeConfiguration&amp;lt;TEntityType&amp;gt; MapToStoredProcedures(
            Action&amp;lt;ModificationFunctionsConfiguration&amp;lt;TEntityType&amp;gt;&amp;gt; modificationFunctionMappingConfigurationAction)
        {
            Check.NotNull(modificationFunctionMappingConfigurationAction, &lt;span class="str"&gt;&amp;quot;modificationFunctionMappingConfigurationAction&amp;quot;&lt;/span&gt;);

            var modificationFunctionMappingConfiguration
                = &lt;span class="kwrd"&gt;new&lt;/span&gt; ModificationFunctionsConfiguration&amp;lt;TEntityType&amp;gt;();

            modificationFunctionMappingConfigurationAction(modificationFunctionMappingConfiguration);

            _entityTypeConfiguration.MapToStoredProcedures(modificationFunctionMappingConfiguration.Configuration);

            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;;
        }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Como se puede ver en este pequeño fragmento, gracias a este nuevo método, tendremos la posibilidad de configurar el mapeo contra los procedimientos de inserción, borrado y actualización utilizando esta configuración. Como siempre se aprende mejor de los ejemplo, a continuación ponemos el ejemplo trivial de mapeo, que nos va a permitir ver algunas cosas interesantes.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity&amp;lt;Customer&amp;gt;()
                .MapToStoredProcedures((mfc) =&amp;gt;
                {
                    mfc.Update(umfc =&amp;gt; umfc.HasName(&lt;span class="str"&gt;&amp;quot;uspCustomer&amp;quot;&lt;/span&gt;)
                                            .Parameter(c =&amp;gt; c.FirstName, &lt;span class="str"&gt;&amp;quot;fname&amp;quot;&lt;/span&gt;));

                    mfc.Insert(imfc =&amp;gt; imfc.HasName(&lt;span class="str"&gt;&amp;quot;ispCustomer&amp;quot;&lt;/span&gt;)
                                        .Parameter(c =&amp;gt; c.FirstName, &lt;span class="str"&gt;&amp;quot;fname&amp;quot;&lt;/span&gt;)
                                        .Parameter(c =&amp;gt; c.LastName, &lt;span class="str"&gt;&amp;quot;lname&amp;quot;&lt;/span&gt;)
                                        .Result(c=&amp;gt;c.Id,&lt;span class="str"&gt;&amp;quot;Id&amp;quot;&lt;/span&gt;));

                    mfc.Delete(dmfc =&amp;gt; dmfc.HasName(&lt;span class="str"&gt;&amp;quot;dspCustomer&amp;quot;&lt;/span&gt;)
                                        .Parameter(c =&amp;gt; c.Id, &lt;span class="str"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;));
                });
        }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Como observará, con el método anterior podremos especificar los mapeos de los diferentes procedimientos, pudiendo personalizar desde el nombre de los mismos hasta el nombre de los parámetros, tanto de entrada como de salida. Bueno, hasta aquí esta pequeñita entrega, como rezaba el título era solamente un &lt;strong&gt;sneak…&lt;/strong&gt; espero que los que conozcáis EF os animéis a hacer más clones y si encontráis mejoras no dudéis en contribuir…&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update 1: &lt;/strong&gt;Parece que me he adelantado un pelin y la gente de ADO.NET ha liberado una &lt;a href="http://entityframework.codeplex.com/wikipage?title=Code%20First%20Insert%2fUpdate%2fDelete%20Stored%20Procedure%20Mapping"&gt;especificación&lt;/a&gt; de esta característica mucho más completa, que complementa lo comentado aquí con tras de las estupendas características de esta nueva novedad como son:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Convenciones por defecto para los nombres de los SP. Es decir, si como anteriormente no especificamos alguna de las funciones, por defecto se buscarán los siguientes nombres de SP, type_Insert,type_Update y type_Delete. En nuestro caso Customer_Update, Customer_Insert y Customer_Delete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Para las relaciones Many To Many hay soporte con SP para el trabajo de inserciones y borrados, revisar la especificación para más información.&lt;/li&gt;
&lt;/ul&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=208691" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /></entry><entry><title>Cloud Tour</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/01/29/cloud-tour.aspx" /><id>/blogs/unai/archive/2013/01/29/cloud-tour.aspx</id><published>2013-01-29T08:17:07Z</published><updated>2013-01-29T08:17:07Z</updated><content type="html">&lt;p&gt;Ya estamos otra vez de gira, en esta ocasión hablando sobre la plataforma de &lt;strong&gt;cloud computing de Microsoft, Windows Azure&lt;/strong&gt;. Aunque, desde un punto de vista especial y fuera de los convencionalismos típicos de esta plataforma. La idea es ver si Windows Azure también es una estupenda plataforma para aquellos que no trabajan en entornos Microsoft. La agenda y los detalles de las sesiones los podéis ver a continuación:&lt;/p&gt;  &lt;p&gt;En mi caso, yo me encargaré de la plataforma de acceso a datos, dónde veremos las posibilidades que Windows Azure nos da. Espero que os guste, para los que no estéis registrados, &lt;a href="http://www.plainconcepts.com/cloudtour/"&gt;aquí&lt;/a&gt; tenéis fechas y más información…. nos vemos..&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;AGENDA&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;9:30 – 10:30 Introducción a la plataforma &lt;/li&gt;    &lt;li&gt;10:30 – 11:30 IaaS – Linux, máquinas y redes virtuales &lt;/li&gt;    &lt;li&gt;11:30 Café &lt;/li&gt;    &lt;li&gt;11:45 – 12:30 PaaS – Trabajando con Java y Eclipse &lt;/li&gt;    &lt;li&gt;12:30 – 13:30 PHP y Azure Web Sites &lt;/li&gt;    &lt;li&gt;13:30 Comida &lt;/li&gt;    &lt;li&gt;14:30 – 15:30 Almacenamiento en la nube: SQL, NoSQL &lt;/li&gt;    &lt;li&gt;15:30 – 16:30 Big Data y Apache Hadoop &lt;/li&gt;    &lt;li&gt;16:30 – 17:30 Desarrollo de backends para dispositivos móviles&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;Organización&lt;/strong&gt;: &lt;a href="http://www.plainconcepts.com/"&gt;Plain Concepts&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Introducción a la plataforma&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;El objetivo de esta primera sesión será describir los principales servicios de la plataforma; Por qué puede interesar para mi empresa usar Cloud Computing, qué nivel de servicio, que opciones tengo si no trabajo con tecnologías Microsoft etc… Durante la sesión se hará especial hincapié en las diferentes opciones de interoperabilidad que existen y cómo es posible trabajar con otros lenguajes de programación como &lt;strong&gt;Java, Node.js o PH&lt;/strong&gt;P e incluso desde otros sistema operativos, &lt;strong&gt;Linux y MAC&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;IaaS - Linux, Máquinas y Redes Virtuales&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;La plataforma Windows Azure dispone de un servicio de infraestructura que permite de forma rápida y sencilla crear máquinas virtuales Windows y Linux. Durante esta sesión se mostrará las principales características de la misma y cómo es posible trabajar desde un ecosistema Linux, tanto a nivel de cliente como de servidor.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Cómo desplegar una máquina virtual Linux. &lt;/li&gt;    &lt;li&gt;Cómo montar tu propia red virtual. &lt;/li&gt;    &lt;li&gt;Cómo trabajar desde un ecosistema completamente Linux, tanto en desktop como en servidor.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;PaaS, trabajando con Java y Eclipse&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;El servicio de “Plataforma como Servicio” es otro de los pilaras básicos de Windows Azure, el cual permite abstraernos de gran parte del trabajo de infraestructura y centrarnos únicamente en la aplicación que queremos desarrollar, posibilitando escenario de escalabilidad y disponibilidad difíciles de conseguir en otro tipo de soluciones. Durante esta sesión veremos de forma práctica cómo podemos desplegar aplicaciones &lt;strong&gt;Java con Eclipse&lt;/strong&gt; en Windows Azure.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;PHP y Azure Web Sites&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Durante esta sesión se mostrará de forma prácticas las opciones disponibles para desplegar aplicaciones PHP en Windows Azure.&lt;/p&gt;  &lt;p&gt;Durante esta sesión se empleará Windows Azure Web Sites para desplegar este tipo de aplicaciones, sirviendo a su vez para explicar con más detalle cómo es posible disponer de un escenario de integración continua con &lt;strong&gt;PHP, Azure Web Sites y GitHub.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Así mismo se verá cómo es posible trabajar de forma rápida y sencilla con WordPress&lt;strong&gt;, Drupal o Joomla.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Almacenamiento en la nube – SQL, NoSQL&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Durante esta sesión se describirán las diferentes opciones de almacenamiento que están disponible en la nube, tanto base de datos relaciones, SQL Database y MySQL, como base de datos NOSQL como Windows Azure Table Storage, &lt;strong&gt;MongoDB o Cassandra&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;De forma práctica podrá verse un ejemplo de cómo es posible trabajar con MongoDB, desplegado en una máquina virtual o haciendo uso de MongoDB como servicio.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Big Data y Hadoop&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;No se puede negar que Big Data y Hadoop son términos de moda en el mundo de IT, pero ¿sabes lo que realmente pueden aportar a tu organización? Y, aún más importante, ¿cómo podrías implementarlo dentro de tu ecosistema?&lt;/p&gt;  &lt;p&gt;Durante esta sesión realizará una introducción a Big Data y Hadoop y de cómo es posible sacarle el máximo rendimiento a estas dos tecnologías dentro de nuestra organización.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Desarrollo de backends para el desarrollo de aplicaciones móviles&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Aplicaciones para Android, Windows Phone, iPhone, iPad, Windows 8… casi todas tienen en común que generalmente necesitan de servicios de backend para ciertas funcionalidades; almacenamiento, notificaciones push, envíos de SMS, seguridad con diferentes proveedores de identidad etc… Durante esta sesión hablaremos de Mobile Services, una tecnología que permite disponer de forma rápida y sencilla de servicios de backend que pueden ser utilizados desde cualquiera de los dispositivos mencionando anteriormente, ya que además de ofrecer un API REST de uso dispone de SDKs propios de cada plataforma que simplifica su utilización.&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=208401" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author></entry><entry><title>EF 6: Pluralization Service ahora es un servicio público</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2013/01/08/ef-6-pluralization-service-ahora-es-un-servicio-p-250-blico.aspx" /><id>/blogs/unai/archive/2013/01/08/ef-6-pluralization-service-ahora-es-un-servicio-p-250-blico.aspx</id><published>2013-01-08T00:00:16Z</published><updated>2013-01-08T00:00:16Z</updated><content type="html">&lt;p&gt;Esta ‘pequeña feature’ era algo que tenía en mente hacer desde hace tiempo, después de otros &lt;a href="http://geeks.ms/blogs/unai/archive/2012/12/07/ef-6-estableciendo-las-configuraciones-de-forma-autom-225-tica.aspx"&gt;pull request con features&lt;/a&gt; y &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/2a51ceb69480"&gt;pequeños arreglos&lt;/a&gt;, he podido sacar un rato&amp;#160; y realizar la implementación del mismo como podéis ver en este &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/813892347b97"&gt;change set&lt;/a&gt;.&amp;#160; La idea es básicamente poder tunear el servicio que se encarga de realizar la singularización y pluralización de nuestras entidades, por ejemplo para decidir por convención el nombre de una tabla. En realidad, este servicio es utilizado principalmente por &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/view/813892347b97#src/EntityFramework/ModelConfiguration/Conventions/Edm/Db/PluralizingTableNameConvention.cs"&gt;PluralizingTableNameConvention&lt;/a&gt; y &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/view/813892347b97#src/EntityFramework/ModelConfiguration/Conventions/Edm/PluralizingEntitySetNameConvention.cs"&gt;PluralizingEntitySetNameConvention&lt;/a&gt; para realizar su trabajo. Hasta ahora, es clase no era pública y su uso estaba fijado por las convenciones anteriores, no teniendo ninguna forma de cambiar la implementación del mismo. A lo largo de las siguientes líneas os contaré los cambios realizados y lo que podremos hacer en la siguiente versión de EF.&lt;/p&gt;  &lt;h3&gt;Haciendo el servicio público&lt;/h3&gt;  &lt;p&gt;Lo primero es crear&amp;#160; el contrato para este servicio, que como podéis ver a continuación es tan sencillo como lo siguiente:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IPluralizationService
    {
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Check if a word is plural.&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;word&amp;quot;&amp;gt;The word to check.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;True if word is plural; false otherwise..&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsPlural(&lt;span class="kwrd"&gt;string&lt;/span&gt; word);

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Check if a word is singular.&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;word&amp;quot;&amp;gt;The word to check.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;True if word is singular; false otherwise.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsSingular(&lt;span class="kwrd"&gt;string&lt;/span&gt; word);

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Pluralize a word using the service.&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;word&amp;quot;&amp;gt;The word to pluralize.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;The pluralized word &amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;string&lt;/span&gt; Pluralize(&lt;span class="kwrd"&gt;string&lt;/span&gt; word);

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Singularize a word using the service.&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;word&amp;quot;&amp;gt;The word to singularize.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;The singularized word.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;string&lt;/span&gt; Singularize(&lt;span class="kwrd"&gt;string&lt;/span&gt; word);
    }&lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Este servicio, por defecto, tendrá una implementación basada en lengua inglesa, llamado &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/view/813892347b97#src/EntityFramework/Infrastructure/Pluralization/EnglishPluralizationService.cs"&gt;EnglishPluralizationService&lt;/a&gt;, que no es más que la adaptación a este contrato del servicio anterior, por compatibilidad. Para registrar la implementación que queramos usar se ha incluido un nuevo método en &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/view/813892347b97#src/EntityFramework/Config/DbConfiguration.cs"&gt;DbConfiguration&lt;/a&gt; llamado &lt;strong&gt;SetPluralizationService&lt;/strong&gt;, gracias al cuál podremos establecer esta implementación, si es que queremos cambiar la existente. A continuación podemos ver un ejemplo de esto:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; OrderContextDbConfiguration
        : DbConfiguration
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; OrderContextDbConfiguration()
        {
            SetPluralizationService(&lt;span class="kwrd"&gt;new&lt;/span&gt; SpanishPluralizationService());
        }
    }&lt;/pre&gt;

&lt;h3&gt;Un pequeño añadido aprovechando la coyuntura..&lt;/h3&gt;

&lt;p&gt;Ya metidos en faena, hay una pequeña cosa que podíamos hacer&amp;#160; para no obligar a nadie a crear un servicio de pluralización si alguna de las reglas del existente no le convenía o quisiera ‘customizar’ este trabajo. La idea es básicamente permitir al usuario incluir en el servicio de pluralización la definición de una entrada de diccionario, con los correspondientes Singular y Plural, como podemos ver en el siguiente fragmento.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomPluralizationEntry
    {
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Get the singular.&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;string&lt;/span&gt; Singular { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Get the plural.&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;string&lt;/span&gt; Plural { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///     Create a new instance&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;singular&amp;quot;&amp;gt;A non null or empty string representing the singular.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;plural&amp;quot;&amp;gt;A non null or empty string representing the plural.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; CustomPluralizationEntry(&lt;span class="kwrd"&gt;string&lt;/span&gt; singular, &lt;span class="kwrd"&gt;string&lt;/span&gt; plural)
        {
            Check.NotEmpty(singular, &lt;span class="str"&gt;&amp;quot;singular&amp;quot;&lt;/span&gt;);
            Check.NotEmpty(plural, &lt;span class="str"&gt;&amp;quot;plural&amp;quot;&lt;/span&gt;);

            Singular = singular;
            Plural = plural;
        }
    }&lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Estas entradas de diccionario se pueden establecer en el constructor del servicio de pluralización antes de registrarlo, por ejemplo, ahora utilizando un &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/view/813892347b97#src/EntityFramework/Config/IDbDependencyResolver.cs"&gt;IDbDependencyResolver&lt;/a&gt;, como vemos:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UnityDependencyResolver
        : IDbDependencyResolver
    {
        IUnityContainer _container;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; UnityDependencyResolver()
        {
            _container = &lt;span class="kwrd"&gt;new&lt;/span&gt; UnityContainer();

            _container.RegisterType&amp;lt;IPluralizationService&amp;gt;(&lt;span class="kwrd"&gt;new&lt;/span&gt; InjectionFactory((c) =&amp;gt;
            {
                var pluralizationService = &lt;span class="kwrd"&gt;new&lt;/span&gt; EnglishPluralizationService(&lt;span class="kwrd"&gt;new&lt;/span&gt; CustomPluralizationEntry[]
                {
                    &lt;span class="kwrd"&gt;new&lt;/span&gt; CustomPluralizationEntry(&lt;span class="str"&gt;&amp;quot;Producto&amp;quot;&lt;/span&gt;,&lt;span class="str"&gt;&amp;quot;Productos&amp;quot;&lt;/span&gt;)
                });

                &lt;span class="kwrd"&gt;return&lt;/span&gt; pluralizationService;
            }));
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; GetService(Type type, &lt;span class="kwrd"&gt;object&lt;/span&gt; key)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_container.IsRegistered(type))
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _container.Resolve(type, (&lt;span class="kwrd"&gt;string&lt;/span&gt;)key);

            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        }
    }&lt;/pre&gt;

&lt;h3&gt;Bonus &lt;/h3&gt;

&lt;p&gt;Bien, una vez hecho público el servicio lo mejor era dar un ejemplo de implementación, por eso, otra de las cosas que he estado haciendo estas &lt;em&gt;vacaciones &lt;/em&gt;ha sido la creación de este servicio de pluralización en castellano, aunque por ahora no lo he hecho público puesto que estoy mirando la mejor manera de hacerlo…en cuanto esté os comentaré como podréis utilizarlo….&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Espero que os gustara la entrada y, como no, os invito a pasaros por el la página del proyecto en &lt;a href="http://entityframework.codeplex.com/"&gt;CodePlex&lt;/a&gt; y a contribuir de las muchas formas en las que se puede…&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=208165" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>EF 6: Buffering versus Streaming</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/12/19/ef-6-buffering-versus-streaming.aspx" /><id>/blogs/unai/archive/2012/12/19/ef-6-buffering-versus-streaming.aspx</id><published>2012-12-19T19:12:14Z</published><updated>2012-12-19T19:12:14Z</updated><content type="html">&lt;p&gt;Hace poco se incorporó un &lt;strong&gt;change set&lt;/strong&gt; con un nuevo ‘breaking change’ dentro de la rama principal de&lt;strong&gt; &lt;a href="http://entityframework.codeplex.com/"&gt;Entity Framework&lt;/a&gt;&lt;/strong&gt;. Este ‘breaking change’ se produce por el cambio en el modo de ejecución de las lecturas por parte de nuestras unidades de trabajo, pasando del modo habitual de lectura en streaming con un DbDataReader a un modo buffering, es decir, a la lectura temprana de los datos y al almacenamiento de los resultados en un buffer. A lo largo de esta entrada intentaremos ver&amp;#160; desde que supone para nosotros este cambio como desarrolladores, hasta las justificaciones para realizarlo, pasando como no, por algunas piezas de código que nos permitan entender mejor como lo han implementado.&lt;/p&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;El cambio&lt;/h3&gt;  &lt;p&gt;Cuando trabajamos con EF generalmente, solemos tener cosas como la siguiente:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;using&lt;/span&gt; (var unitOfWork = &lt;span class="kwrd"&gt;new&lt;/span&gt; UnitOfWork())
            {
                var someenumerable = unitOfWork.Entities;
            }&lt;/pre&gt;


&lt;p&gt;Y todos tenemos claro que ese enumerador es una consulta diferida, técnicamente por un shaper, la diferencia de este trabajo en EF 6 con respecto a las anteriores estriba en como se hace la materialización de este enumerable. En la versión actual de EF tendremos un &lt;strong&gt;data reader&lt;/strong&gt; que será usado en cada llamada al MoveNext del iterador. Aunque todos sabemos que internamente DataReader funciona con bloques para conjuntos de datos grandes estos se van incorporando a medida que se necesitan, es decir, hay un proceso de &lt;em&gt;streaming &lt;/em&gt;de los datos del servidor a cliente. Para ver esto solamente tendríamos que realizar una lectura de un cojunto grande y ver como el BatchStarting y el BatchCompleted sucenden al comienzo de la lectura y cuando hemos iterado por todos los resultado, es decir, para la siguiente consulta, podríamos ver los siguientes valores en nuestro profiler&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;             var enumerable = unitOfWork.Entities;

             &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var item &lt;span class="kwrd"&gt;in&lt;/span&gt; enumerable)
             {
                  &lt;span class="rem"&gt;//TODO: Some work here!&lt;/span&gt;
             }

             Console.ReadLine();&lt;/pre&gt;

&lt;p&gt;Comienzo de la lectura&lt;/p&gt;
&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled1_5F00_509C2241.png"&gt;&lt;img title="Untitled1" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;margin:5px 5px 5px 0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="Untitled1" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled1_5F00_thumb_5F00_7A2FED74.png" width="1508" height="42" /&gt;&lt;/a&gt;



&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;final del bucle&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled2_5F00_715FE528.png"&gt;&lt;img title="Untitled2" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;margin:5px 5px 5px 0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="Untitled2" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled2_5F00_thumb_5F00_2FE532CF.png" width="1511" height="60" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Lógico según lo se sabemos sobre el comportamiento de nuestros data readers ¿ verdad ?. Bien, pues ahora intentamos hacer esto mismo con EF 6 y veremos lo siguiente nada más ejecutar el paso por el primero de los elementos…&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/image_5F00_0E38E431.png"&gt;&lt;img title="image" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;margin:5px 5px 5px 0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/image_5F00_thumb_5F00_0C88185D.png" width="1505" height="62" /&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;La razón es la que comentamos más arriba, en la nueva versión de EF que tendremos el mecanismo de consultas reemplazará el DbDataReader por un &lt;strong&gt;BufferedDataReader &lt;/strong&gt;(System.Data.Entity.Core.Objects.Internal.BufferedDataReader) el cual en realidad no es más que un envoltorio de un DataReader que hace todo la lectura de sus elementos en su inicialización y los almacena en una estructura interna BufferedDataRecord, de ahí el nombre de Buffered, que será usada por el materializador ( shaper ) para crear las distintas entidades.&lt;/p&gt;

&lt;p&gt;Aunque esto pueda parecer un mero cambio interno a EF, en realidad no es tan sencillo y supone un breaking change porque tiene un impacto sobre las aplicaciones actuales. De entrada es lógico ver que hay una mayor presión de memoria, aunque sea memoria de generación 0, puesto que estamos &lt;strong&gt;duplicando &lt;/strong&gt;los datos en el proceso de materialización. El segundo motivo es que por ejemplo si se rompe el bucle anterior por cualquier condición en la versión anterior no tendríamos porque haber traído todos los bloques del reader mientras que en EF 6 si habríamos traído todos los bloques del reader. Otro impacto posible lo podemos observar en la llamada a nuestro GetEnumerator, puesto que ahora necesitará más tiempo para completar el trabajo.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;Los motivos&lt;/h3&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Las razones para movernos de un modo Streamed a Buffered se deben principalmente y tal como el equipo ha explicado en &lt;a href="http://entityframework.codeplex.com/wikipage?title=Design%20Meeting%20Notes%20-%20December%206%2c%202012"&gt;el siguiente design meeting&lt;/a&gt; a las siguientes razones:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Sql Azure connection resilience:&lt;/strong&gt; Como todos sabéis, el trabajo con Sql Azure tiene una problemática especial que nos obliga a necesitar en ciertos escenarios de reintentos en nuestro trabajo con EF, Cesar de la Torre &lt;a href="http://blogs.msdn.com/b/cesardelatorre/archive/2010/12/20/handling-sql-azure-connections-issues-using-entity-framework-4-0.aspx"&gt;escribió&lt;/a&gt; hace ya mucho tiempo sobre esto. Dentro de la iniciativa del equipo por hacer más robusto el uso de EF con Sql Azure este cambio es necesario ya que no retarda el uso de una conexión más allá de lo necesario.&lt;/li&gt;

  &lt;li&gt;El tiempo de uso de una &lt;strong&gt;conexión se reduce potencialmente&lt;/strong&gt;&lt;/li&gt;

  &lt;li&gt;Ya no es necesario MARS&amp;#160; ( obligatorio con lazy loading en la versión actual )&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Y si quiero mi antiguo comportamiento&lt;/h3&gt;

&lt;p&gt;Bien sea por compatibilidad o porque el escenario así lo requiera, en EF tendremos un mecanismo para seguir usando streaming en nuestras consultas, para ello, solamente tendremos que utilizar el método AsStreaming, gracias al cual EF volverá a usar un DbDataReader en lugar del ya mencionado BufferedDataReader. A continuación podemos ver un ejemplo de ello:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;                var enumerable = unitOfWork.Entities
                                           .Where(a=&amp;gt;a.Id&amp;gt;0)
                                           .AsStreaming();&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Bueno, hasta aquí hemos llegado, espero que todos tengamos en cuenta este cambio si decidimos migrar aplicaciones de EF 5 a EF 6 puesto que tal y como hemos dicho puede tener impacto y producirse situaciones no deseadas sino nos fijamos…&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=207851" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="Entity Framework" scheme="http://geeks.ms/blogs/unai/archive/tags/Entity+Framework/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /></entry><entry><title>EF 6: Estableciendo las configuraciones de forma automática</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/12/07/ef-6-estableciendo-las-configuraciones-de-forma-autom-225-tica.aspx" /><id>/blogs/unai/archive/2012/12/07/ef-6-estableciendo-las-configuraciones-de-forma-autom-225-tica.aspx</id><published>2012-12-07T10:07:31Z</published><updated>2012-12-07T10:07:31Z</updated><content type="html">&lt;p&gt;La verdad es que no hace muchos días que publiqué un &lt;a href="http://geeks.ms/blogs/unai/archive/2012/11/15/ef-agregando-configuraciones-de-forma-autom-225-tica.aspx"&gt;post con este trabajo&lt;/a&gt; para todos aquellos, que como yo, consideraran interesante el hecho de disponer de una forma automática de agregar las configuración de nuestro modelo, con el fin de facilitar el trabajo y prevenir ese código repetitivo que solemos ver muy a menudo. Para que no tengamos que recurrir a lo mismo en EF 6, me decidí por hacer un pequeño &lt;strong&gt;pull request&lt;/strong&gt; que pudiera contener esta funcionalidad, ahora, que como ya sabréis todos, Entity Framework es Open Source&amp;#160; y, por lo tanto, abierto a que la comunidad pueda contribuir. Los que hayáis pasado alguna vez &lt;a href="http://entityframework.codeplex.com/"&gt;por el portal del proyecto&lt;/a&gt; en &lt;a href="http://entityframework.codeplex.com/"&gt;Codeplex&lt;/a&gt; sabréis que hay multitud de información sobre las diferentes vías de contribución, que no tienen porque ser solamente código, y como hacer estas contribuciones de una forma ordenada y consensuada. La palabra consensuada es importante aquí puesto que por mucho que a nosotros nos parezca importante y válida una contribución esta no tiene por que tener la misma validez para el equipo, por ejemplo, porque la pieza o piezas en las que vayamos a tocar se vayan a rediseñar o, a otra multitud de factores que se nos puedan escapar. El &lt;em&gt;principio&lt;/em&gt; &lt;a href="http://www.igvita.com/2011/12/19/dont-push-your-pull-requests/"&gt;Don’t Push Your Pull Request&lt;/a&gt; es la norma a seguir dentro del equipo de desarrollo y por lo tanto el primer trabajo que tenemos que hacer es discutir con ellos lo que queremos hacer y por supuesto como lo vamos a hacer, en este caso, la sugerencia de pull request y su discusión la podéis ver &lt;a href="http://entityframework.codeplex.com/discussions/403807"&gt;aquí&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Bueno, después de ver el feedback y de las guías sobre como les gustaría la aportación, el resultado que ha quedado es este &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/44ba79b2989a"&gt;Change Set&lt;/a&gt; con la característica comentada anteriormente y, que pasaremos a desgranar ahora mismo.&lt;/p&gt;  &lt;h1&gt;&amp;#160;&lt;/h1&gt;  &lt;h1&gt;Carga automática de configuraciones&lt;/h1&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Bien, esto es lo más básico y a la vez lo más natural de esta característica, puesto que como ya comentamos su primer trabajo es hacer la carga de configuraciones de forma automática, eliminando las típicas líneas repetitivas de carga de configuraciones, que en un proyecto real serán muchas y por lo tanto con un impacto en legibilidad y mantenibilidad. Es decir, lo que nos permitiría es cambiar cosas como esta:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder)
        {
            &lt;span class="rem"&gt;//.. more configurations entries&lt;/span&gt;

            modelBuilder.Configurations.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; OrderEntityTypeConfiguration());
            modelBuilder.Configurations.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; CustomerEntityTypeConfiguration());

            &lt;span class="rem"&gt;//.. more configurations entries&lt;/span&gt;
        }&lt;/pre&gt;

&lt;p&gt;Por lo siguiente:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly());
        }&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;

&lt;h1&gt;Visibilidad de tipos y constructores&lt;/h1&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Para realizar esta carga automática de configuraciones no estamos restringidos a ninguna visibilidad de nuestras clases, ni de sus constructores. De hecho, esto es lo ideal, puesto que estas clases solamente tienen fines de configuración y no están pensadas para ser usadas más que por la infraestructura, parece lógico que pudiéramos escribirlas como por ejemplo en la siguiente de forma no pública y con un constructor privado.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;   &lt;span class="kwrd"&gt;class&lt;/span&gt; OrderEntityTypeConfiguration
        :EntityTypeConfiguration&amp;lt;Order&amp;gt;
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; OrderEntityTypeConfiguration()
        {
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Property(o =&amp;gt; o.Total).HasPrecision(12, 2);
        }
    }&lt;/pre&gt;
&lt;/blockquote&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h1&gt;Configuraciones en jerarquía&lt;/h1&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;La última de las características de este trabajo, es el soporte a jerarquías de configuraciones, es decir, que nuestros tipos de configuración no implementen de forma directa EntityTypeConfiguration&amp;lt;&amp;gt;. Un ejemplo de este tipo de escenarios podría ser algo como lo siguiente:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;abstract class&lt;/span&gt; CommonEntityTypeConfiguration&amp;lt;TEntity&amp;gt;
        :EntityTypeConfiguration&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;public&lt;/span&gt; CommonEntityTypeConfiguration()
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; tableName = PrefixTableName(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(TEntity).Name);

            &lt;span class="kwrd"&gt;this&lt;/span&gt;.ToTable(tableName);

        }

        &lt;span class="kwrd"&gt;string&lt;/span&gt; PrefixTableName(&lt;span class="kwrd"&gt;string&lt;/span&gt; name)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;tbl&amp;quot;&lt;/span&gt; + name;
        }
    }&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si observa, lo que hemos hecho, con meros fines de ejemplo, es hacer una pequeña base para nuestras configuraciones que nos agrega un prefijo tbl a los nombres de nuestras tablas. Esta configuración base la podríamos utilizar en todas aquellas entidades que nos interesaran que ya tuvieran OOB esta característica.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; OrderEntityTypeConfiguration
        : CommonEntityTypeConfiguration&amp;lt;Order&amp;gt;
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; OrderEntityTypeConfiguration()
        {
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Property(o =&amp;gt; o.Total).HasPrecision(12, 2);
        }
    }&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Pues bien, como hemos dicho, aún en estas situaciones nuestro AddFromAssembly seguirá funcionando perfectamente y cargando nuestras configuraciones de la forma correcta, excluyendo tipos abstractos y definiciones de tipos genéricos…&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Bueno, espero que os resulte interesante esta novedad que tendremos en EF 6 y espero, que esta contribución os sea de la mayor utilidad posible, con ese fin está hecha…&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=207715" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /><category term="Pull Request" scheme="http://geeks.ms/blogs/unai/archive/tags/Pull+Request/default.aspx" /><category term="Open Source" scheme="http://geeks.ms/blogs/unai/archive/tags/Open+Source/default.aspx" /></entry><entry><title>Recursos, mensajes de excepción y otras cadenas…..</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/11/27/recursos-mensajes-de-excepci-243-n-y-otras-cadenas.aspx" /><id>/blogs/unai/archive/2012/11/27/recursos-mensajes-de-excepci-243-n-y-otras-cadenas.aspx</id><published>2012-11-26T23:41:15Z</published><updated>2012-11-26T23:41:15Z</updated><content type="html">&lt;p&gt;Bueno, imagino que después de leer el título le quedará bastante claro de lo que vamos a hablar en este pequeño post. A lo largo de este tiempo he visto muchas y diversas formas de manejar los típicos mensajes de excepción y otros elementos localizables de nuestro código ( sin hablar nada de UI en este caso ), unas mejores y otras peores. Con la llegada de .NET y los recursos incrustados, muchos de los inconvenientes tradicionales que teníamos se vieron resueltos. Elementos como el &lt;em&gt;fallback&lt;/em&gt; en la resolución de la cultura, los conceptos de culturas específicas y neutras, sin duda, facilitaron enormemente nuestro trabajo. El consumo de estos recursos incrustados de .NET, por regla general, se realiza utilizando las propiedades de la clase que se nos genera automáticamente por cada uno los archivos de recursos [ recuerde que por defecto estos ficheros tienen asociada una custom tool, ResXFileCodeGenerator, para la generación de esta clase ]. Elementos habituales podrían ser, algunos como los siguientes:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:          &lt;/span&gt;&lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(Resource.AnyExceptionMessageForOperation);&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; AnyTryMethod(&lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; error)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;            &lt;span class="rem"&gt;//.... &lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;            error = Resource.AnyMessageToUser;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;            &lt;span class="rem"&gt;//....&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        }&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Alguno de los problemas con esta forma de trabajo surge por ejemplo cuando queremos hacer estos mensajes parametrizados, puesto que tendríamos que recurrir a cosas como la siguiente:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:          &lt;/span&gt;var localizedMessage = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(Resource.AnyMessageToUser, &lt;span class="str"&gt;&amp;quot;p0&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;p1&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Cuando se utiliza esta entrada de recursos, no hay más remedio que acudir a nuestro mensaje para descubrir si este toma parámetros o no y establecerlos en caso necesario, por no hablar de que la legibilidad podría verse afectada, sin duda. Mecanismos para intentar solventar estos problemas hay muchos y variados pero uno que últimamente me ha gustado y que he seguido ha sido el utilizado por el equipo &lt;a href="http://entityframework.codeplex.com/SourceControl/changeset/view/5f7a1a4d87c8#src%2fEntityFramework%2fProperties%2fResources.tt"&gt;de EF para hacer la gestión de esta problemática&lt;/a&gt;. Mecanismo que se basa en una sencilla plantilla .tt&amp;nbsp; junto a un fichero de recursos que nos permite generar 2 clases fundamentales &lt;strong&gt;Strings&lt;/strong&gt; y &lt;strong&gt;Error&lt;/strong&gt; preparadas para ser utilizadas en el código de una forma más simple y legible que mediante el código por defecto de ResXFileCodeGenerator. De entre algunas de las características que incorpora esta plantilla podemos ver que expone en forma de parámetros los parámetros de las entradas del archivo de recursos, de tal forma que si, por ejemplo, tenemos una entrada con valor&lt;em&gt; “any message for {0} and {1}”&amp;nbsp; &lt;/em&gt;esta plantilla nos expondrá en nuestra clase &lt;strong&gt;Strings&lt;/strong&gt; un método similar a lo siguiente:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:          &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;string&lt;/span&gt; AnyMessageToUser(&lt;span class="kwrd"&gt;object&lt;/span&gt; p0, &lt;span class="kwrd"&gt;object&lt;/span&gt; p1);&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Con lo cual, el uso anterior de esta clave de recurso podría realizarse como, por ejemplo de la siguiente manera:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:          &lt;/span&gt;var localizedMessage = Strings.AnyMessageToUser(&lt;span class="str"&gt;&amp;quot;p0&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;p1&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La parte de &lt;strong&gt;Error&lt;/strong&gt;, es quizás, más interesante todavía, puesto que nos permite generar a partir de los claves de nuestros ficheros de recurso métodos que devuelvan las excepciónes que necesitemos, cuyos tipos se extraen además del mismo archivo de recursos gracias a un pequeño trick con el campo comentarios, puesto que interpretan comentarios como ## ExceptionType=InvalidOperationException como la necesidad de generar un método que devuelva una excepción &lt;em&gt;InvalidOperationException &lt;/em&gt;con el mensaje de la misma entrada del recurso. A continuación podemos ver un ejemplo de uno de los mensajes de Error que tenemos en el código de EF&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;        &lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Exception AutomaticDataLoss()&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Migrations.Infrastructure.AutomaticDataLossException(Strings.AutomaticDataLoss);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;        }&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Bueno, amigo lector, le invito desde aquí a revisar como otros resuelven problemas habituales en nuestro trabajo. En este caso, esta plantilla de la que acabamos de ver es un ejemplo bastante simple de tratar el problema. Aunque hay que tocar un par de cosas para que la misma se pueda utilizar en cualquier proyecto la verdad es que es terriblemente sencilla, por lo que le invito a probarla…&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&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=207554" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term=".NET General" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx" /><category term="EF 4.0" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+4.0/default.aspx" /><category term="EF 4.x" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+4.x/default.aspx" /><category term="EF 4.3" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+4.3/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>EF Agregando configuraciones de forma automática</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/11/15/ef-agregando-configuraciones-de-forma-autom-225-tica.aspx" /><id>/blogs/unai/archive/2012/11/15/ef-agregando-configuraciones-de-forma-autom-225-tica.aspx</id><published>2012-11-15T08:48:00Z</published><updated>2012-11-15T08:48:00Z</updated><content type="html">&lt;p&gt;Hay ciertas situaciones en las que las convenciones de EF para nuestros mapeos de entidades no nos sirven o bien no nos sirven completamente, un ejemplo de esto es cuando trabajamos con una base de datos existente, dónde, seguramente, la convención del nombre de las tablas ( pluralización en inglés de los nombres de las entidades ) no nos sirva, y así con otras muchas convenciones. En estas situaciones, es más que seguro que tengamos que hacer uso de las configuraciones personalizadas, instancias de &lt;em&gt;&lt;strong&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg696117(v=vs.103).aspx"&gt;EntityTypeConfiguration&amp;lt;&amp;gt;&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt; y &lt;a href="http://msdn.microsoft.com/en-us/library/gg696149(v=vs.103).aspx"&gt;&lt;em&gt;ComplexTypeConfiguration&amp;lt;&amp;gt;&lt;/em&gt;&lt;/a&gt;&lt;strong&gt;&lt;em&gt;.&amp;#160; &lt;/em&gt;&lt;/strong&gt;En estos casos, cuando el modelo es grande, el aspecto que tendrá nuestro OnModelCreating será un poco esperpéntico, algo similar a lo siguiente:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder)
{
          modelBuilder.Configuration.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Entiti1Configuration());
          modelBuilder.Configuration.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Entiti2Configuration());
          modelBuilder.Configuration.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Entiti3Configuration());
          modelBuilder.Configuration.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Entiti4Configuration());
          ...
          ...
          ...
          modelBuilder.Configuration.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Entiti20Configuration());
          modelBuilder.Configuration.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Entiti21Configuration());
          modelBuilder.Configuration.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Entiti22Configuration());
          modelBuilder.Configuration.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Entiti23Configuration());
}&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;El problema de este tipo de códigos, amén del &lt;strong&gt;matenimiento&lt;/strong&gt;, es la poca legibilidad del mismo, donde por ejemplo, nos costaría encontrar si una entidad está o no mapeada. Solventar este problema y hacer un código más legible y facilitar la vida al desarrollador no es difícil,&amp;#160; ya que en realidad lo único que estamos haciendo ahí es configurar todas las clases de un determinado tipo, algo por lo tanto muy fácil de automatizar. En el siguiente repositorio de &lt;a href="https://github.com/unaizorrilla/ef.contrib"&gt;GitHub&lt;/a&gt; he implementado una posible solución para estos problemas, que nos permite cambiar este código anterior por algo como lo siguiente:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder)
{
        modelBuilder.Configurations.Add(ConfigurationSolver.FromThisAssembly());
}&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;o, si tenemos los mapas de configuración en otro ensamblado, podríamos hacer:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder)
{
        modelBuilder.Configurations.Add(ConfigurationSolver.FromNamedAssembly(&lt;span class="str"&gt;&amp;quot;The_Assembly_With_Configs&amp;quot;&lt;/span&gt;));
}&lt;/pre&gt;

&lt;p&gt;Espero que os guste y, sobre todo, que os sea de utilidad…&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;Saludos&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;Unai&lt;/pre&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=207433" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term="EF 5.0" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+5.0/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="C#" scheme="http://geeks.ms/blogs/unai/archive/tags/C_2300_/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>EF 6 Alpha: Custom Conventions</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/11/03/ef-6-alpha-custom-conventions.aspx" /><id>/blogs/unai/archive/2012/11/03/ef-6-alpha-custom-conventions.aspx</id><published>2012-11-03T11:57:00Z</published><updated>2012-11-03T11:57:00Z</updated><content type="html">&lt;p&gt;El tema de las convenciones personalizadas para el modelo de Code First sin duda ha sido una de las cosas que m&amp;aacute;s echamos de menos en EF, de hecho, durante alguna de las betas estas posibilidades estaban incluidas como en su d&amp;iacute;a vimos en alg&amp;uacute;n &lt;a href="http://geeks.ms/blogs/unai/archive/2011/01/03/ef-4-ctp-5-code-first-conventions-ii.aspx"&gt;post&lt;/a&gt;. De entre las distintas novedades de esta versi&amp;oacute;n preliminar de EF 6 podemos destacar la vuelta al ruedo de estas features, aunque ahora con una implementaci&amp;oacute;n, en mi opini&amp;oacute;n, mucho m&amp;aacute;s acertada. A lo largo de la siguiente entrada intentaremos darle un vistazo a estas nuevas posibilidades, si lo desea, tambi&amp;eacute;n puede leer el &lt;a href="http://msdn.microsoft.com/en-us/data/jj819164"&gt;walkthough&lt;/a&gt; que el equipo de &lt;a href="http://blogs.msdn.com/adonet"&gt;ADO.NET&lt;/a&gt; tiene sobre este tema.&lt;/p&gt;
&lt;h1&gt;Introducci&amp;oacute;n&lt;/h1&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Todas las convenciones de EF, est&amp;aacute;n basadas en la siguiente interface, &lt;strong&gt;IConfigurationConvention:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;    [ContractClass(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(IConfigurationConventionContracts&amp;lt;,&amp;gt;))]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IConfigurationConvention&amp;lt;TMemberInfo, TConfiguration&amp;gt; : IConvention
        &lt;span class="kwrd"&gt;where&lt;/span&gt; TMemberInfo : MemberInfo
        &lt;span class="kwrd"&gt;where&lt;/span&gt; TConfiguration : ConfigurationBase
    {
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(TMemberInfo memberInfo, Func&amp;lt;TConfiguration&amp;gt; configuration);
    }&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;Esta interface, como observar&amp;aacute; tiene dos par&amp;aacute;metros gen&amp;eacute;ricos TMemberInfo y TConfiguration, que nos permite establecer, por un lado con TMemberInfo si la configuraci&amp;oacute;n es para un tipo o para una propiedad y en ultimo lugar a que elemento en concreto se aplica, para el caso de las propiedades ConfigurationBase tiene un jerarqu&amp;iacute;a similar a esta:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;ConfigurationBase&lt;/p&gt;
&lt;p&gt;&amp;nbsp; -&amp;gt; Property Configuration&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;-&amp;gt;NavigationPropertyConfiguration&lt;/p&gt;
&lt;p&gt;-&amp;gt;PrimitivePropertyConfiguraiton&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -&amp;gt; BinaryPropertyConfiguraiton&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -&amp;gt; DateTimePropertyConfiguration&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -&amp;gt; &amp;hellip;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dicho esto, para crear por ejemplo una convenci&amp;oacute;n que afecte a propiedades de tipo DateTime tendr&amp;iacute;amos que implementar una clase como la siguiente:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DateTimeIsMappedToSqlServerDateTime2
        :IConfigurationConvention&amp;lt;PropertyInfo,DateTimePropertyConfiguration&amp;gt;
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(PropertyInfo memberInfo, Func&amp;lt;DateTimePropertyConfiguration&amp;gt; configuration)
        {
           
        }
    }&lt;/pre&gt;
&lt;p&gt;

Por supuesto, dentro del m&amp;eacute;todo Apply tendr&amp;iacute;amos que establecer que queremos en la convenci&amp;oacute;n, si se fija, el delegado configuration nos permite obtener la configuraci&amp;oacute;n actual de esa propiedad, con lo cual, podr&amp;iacute;amos ver/modificar la misma. En este caso optaremos por hacer lo mismo que el el walkthoug, puesto que me parece muy &amp;lsquo;real&amp;rsquo; el hecho de adaptar el tipo de datos en Sql Server a datetime2 para estas propiedades.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DateTimeIsMappedToSqlServerDateTime2
        :IConfigurationConvention&amp;lt;PropertyInfo,DateTimePropertyConfiguration&amp;gt;
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(PropertyInfo memberInfo, Func&amp;lt;DateTimePropertyConfiguration&amp;gt; configuration)
        {
            &lt;span class="rem"&gt;//get the current datetimepropertyconfiguration&lt;/span&gt;
            var dateTimeConfiguration = configuration();&lt;/pre&gt;
&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (dateTimeConfiguration.ColumnType == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                dateTimeConfiguration.ColumnType = &lt;span class="str"&gt;&amp;quot;datetime2&amp;quot;&lt;/span&gt;;
        }
    }&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;Por supuesto, usted puede revisar el miembro memberInfo para decidir a que propiedades se aplica, por ejemplo, le podr&amp;iacute;a interesar solo aplicar esta convenci&amp;oacute;n a las propiedades cuyo nombre por ejemplo acaben con un postfijo determinado, aunque esto, en mi humilde opini&amp;oacute;n no es algo que me guste para nada. Las convenciones a nivel de entidad, son pr&amp;aacute;cticamente iguales, con la salvedad de que l&amp;oacute;gicamente configuran aspectos de la entidad y no de las propiedades, por ejemplo, la convenci&amp;oacute;n de que la propiedad Id sea la clave primaria de una entidad podr&amp;iacute;a haberse escrito as&amp;iacute;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; IdPropertyIsPrimaryKeyConvention
       : IConfigurationConvention&amp;lt;Type, EntityTypeConfiguration&amp;gt;
    {

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(Type memberInfo, Func&amp;lt;EntityTypeConfiguration&amp;gt; configuration)
        {
            var entityTypeConfiguration = configuration();

            var idProperty = memberInfo.GetProperty(&lt;span class="str"&gt;&amp;quot;Id&amp;quot;&lt;/span&gt;, BindingFlags.Public | BindingFlags.Instance);

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (idProperty != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                entityTypeConfiguration.Key(idProperty);
        }
    }&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;Bien, una vez que tenemos definidas nuestras convenciones, para agregarla usaremos la propiedad Conventions, que ya es conocida de nuestros DbContext, con la diferencia que ahora dispone de m&amp;eacute;todos para incluir convenciones y no solamente para eliminarlas. De hecho, incluso me permite establecer el orden de ejecuci&amp;oacute;n de las mismas.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;      modelBuilder.Conventions.Add&amp;lt;IdPropertyIsPrimaryKeyConvention&amp;gt;();&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;Con el fin de simplificarnos la vida, el equipo de &lt;strong&gt;ADO.NET&lt;/strong&gt; nos ha creado una peque&amp;ntilde;a clase &lt;strong&gt;LightweigtConvention&lt;/strong&gt; con la cual podremos establecer convenciones sin necesidad de escribir una nueva clase para las mismas. Esta clase no es m&amp;aacute;s que una implementaci&amp;oacute;n de IConventionConfiguration para tipos y propiedades que hace uso de una clase, &lt;strong&gt;EntityConventionConfiguration&lt;/strong&gt; para agregar convenciones mediante un API fluent.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; EntityConventionConfiguration
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; List&amp;lt;Func&amp;lt;Type, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; _predicates = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Func&amp;lt;Type, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt;();
        &lt;span class="kwrd"&gt;private&lt;/span&gt; Action&amp;lt;LightweightEntityConfiguration&amp;gt; _configurationAction;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; PropertyConventionConfiguration _propertyConfiguration;

        &lt;span class="kwrd"&gt;internal&lt;/span&gt; EntityConventionConfiguration()
        {
        }

        &lt;span class="kwrd"&gt;internal&lt;/span&gt; Action&amp;lt;LightweightEntityConfiguration&amp;gt; ConfigurationAction
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _configurationAction; }
        }

        &lt;span class="kwrd"&gt;internal&lt;/span&gt; List&amp;lt;Func&amp;lt;Type, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; Predicates
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _predicates; }
        }

        &lt;span class="kwrd"&gt;internal&lt;/span&gt; PropertyConventionConfiguration PropertyConfiguration
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _propertyConfiguration; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Filters the entity types that this convention applies to based on a&lt;/span&gt;
        &lt;span class="rem"&gt;/// predicate.&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;predicate&amp;quot;&amp;gt;A function to test each entity type for a condition.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// The same EntityConventionConfiguration instance so that multiple calls can&lt;/span&gt;
        &lt;span class="rem"&gt;/// be chained.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; EntityConventionConfiguration Where(Func&amp;lt;Type, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt; predicate)
        {
            Contract.Requires(predicate != &lt;span class="kwrd"&gt;null&lt;/span&gt;);

            _predicates.Add(predicate);

            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;;
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Allows configuration of the entity types that this convention applies to.&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;entityConfigurationAction&amp;quot;&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// An action that performs configuration against a &amp;lt;see cref=&amp;quot;LightweightEntityConfiguration&amp;quot; /&amp;gt;.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Configure(Action&amp;lt;LightweightEntityConfiguration&amp;gt; entityConfigurationAction)
        {
            Contract.Requires(entityConfigurationAction != &lt;span class="kwrd"&gt;null&lt;/span&gt;);

            _configurationAction = entityConfigurationAction;
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Allows further configuration of the convention based on the properties of&lt;/span&gt;
        &lt;span class="rem"&gt;/// the entity types that this convention applies to.&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;&lt;/span&gt;
        &lt;span class="rem"&gt;/// A configuration object that can be used to configure this convention based&lt;/span&gt;
        &lt;span class="rem"&gt;/// on properties.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; PropertyConventionConfiguration Properties()
        {
            var propertyConfiguration = &lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyConventionConfiguration();
            _propertyConfiguration = propertyConfiguration;

            &lt;span class="kwrd"&gt;return&lt;/span&gt; propertyConfiguration;
        }
    }&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;Utilizando esta clase, por lo tanto, podr&amp;iacute;amos crear una convenci&amp;oacute;n tal y como sigue:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BlogUnitOfWork
        :DbContext
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; IDbSet&amp;lt;Blog&amp;gt; Blogs { get; set; }

        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Add(entityConventionConfiguration =&amp;gt;
            {
                entityConventionConfiguration.Properties()
                                            .Where(p =&amp;gt; p.Name == &lt;span class="str"&gt;&amp;quot;Id&amp;quot;&lt;/span&gt;)
                                            .Configure(lpc =&amp;gt; lpc.IsKey());
            });
        }
    }&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;Puede observar como el trabajo a realizar depende de si configura propiedad o entidad y este est&amp;aacute; representado por las clases LightweighPropertyConfiguration o LightweighEntityConfiguration.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Bien, pero &amp;iquest;y si quiero hacer las convenciones con atributos? Pues sencillo, en vez de implementar IConfigurationConvention trabajaremos con AttributeConfigurationConvention, el cual, nos permite indicar que atributo es el que ser&amp;aacute; el atributo &lt;strong&gt;marcador,&lt;/strong&gt; es decir aquel atributo que EF revisar&amp;aacute; para saber que tiene que aplicar una convenci&amp;oacute;n. Para verlo, utilizaremos tambi&amp;eacute;n el del walkthoug, puesto que al igual que con el DateTime es tambi&amp;eacute;n bastante habitual. En este ejemplo el objetivo es poder disponer de un atributo, por ejemplo NonUnicodeAttribute que nos permita decorar a las propiedades como no unicode. Pues bien, este atributo ser&amp;aacute; un atributo marcador, es decir, no necesita c&amp;oacute;digo de trabajo con EF, por ejemplo igual que as&amp;iacute;:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;    [AttributeUsage(AttributeTargets.Property, AllowMultiple = &lt;span class="kwrd"&gt;false&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; NonUnicodeAttribute : Attribute
    {

    }&lt;/pre&gt;
&lt;p&gt;

Bien, ahora que tenemos creado el atributo marcador, solamente tenemos que aplicarle la convenci&amp;oacute;n ,tal cual podr&amp;iacute;amos hacer antes con nuestras PrimitivePropertyConfiguration&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; NonUnicodeAttributeConvention :
        AttributeConfigurationConvention&amp;lt;PropertyInfo, StringPropertyConfiguration, NonUnicodeAttribute&amp;gt;
    {

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Apply(

            PropertyInfo propertyInfo,

            StringPropertyConfiguration configuration,

            NonUnicodeAttribute attribute)
        {

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (configuration.IsUnicode == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                configuration.IsUnicode = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            }
        }
    }&lt;/pre&gt;
&lt;p&gt;

Sencillo &amp;iquest;verdad?&amp;hellip;Bueno, espero poder publicar alguna entrada m&amp;aacute;s sobre EF 6, de hecho hay un par de novedades que me parecen super interesantes.. y me gustar&amp;iacute;a tambi&amp;eacute;n sacar algo de tiempo para colaborar un poco con el c&amp;oacute;digo, a ver si lo logro&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&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=207305" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="EF" scheme="http://geeks.ms/blogs/unai/archive/tags/EF/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="EF 6" scheme="http://geeks.ms/blogs/unai/archive/tags/EF+6/default.aspx" /></entry><entry><title>Azure: AAL + Web API, una mezcla ‘casi’ perfecta</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/10/31/azure-aal-web-api-una-mezcla-casi-perfecta.aspx" /><id>/blogs/unai/archive/2012/10/31/azure-aal-web-api-una-mezcla-casi-perfecta.aspx</id><published>2012-10-31T11:36:40Z</published><updated>2012-10-31T11:36:40Z</updated><content type="html">&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;En el post anterior empezamos a ver un poco sobre AAL, y como empezar a trabajar con este simple paquete. En esta ocasión, continuaremos hablando de AAL y de como juntarlo con &lt;a href="http://www.asp.net/web-api/overview"&gt;ASP.NET Web API&lt;/a&gt;. Cuando uno diseña sus servicios utilizando Web API uno de los elementos que siempre entran en juego es la autorización en los mismos, de hecho, dándonos un pequeño paseo por la propia Web de &lt;a href="http://www.asp.net/web-api/overview"&gt;ASP.NET Web API&lt;/a&gt; podemos ver &lt;a href="http://www.asp.net/web-api/videos/getting-started/authorization"&gt;diferente documentación&lt;/a&gt; acerca de este tema. A mayores, por supuesto, buceando en la web podemos obtener diferente información acerca de como realizar los procesos de authenticación, desde &lt;a href="http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/"&gt;API Keys&lt;/a&gt; hasta &lt;a href="http://www.dotnetopenauth.net/"&gt;OAuth&lt;/a&gt; . Todos estos procesos técnicamente se hacen de una forma o en otra, pero, tienen en común que ninguno externaliza el proceso de autenticación teniendo que incorporar nosotros este dentro de nuestras aplicaciones y por lo tanto, cuando necesitamos diferentes proveedores de identidad la cosa se complica. A lo largo de esta entrada intentaremos ver como construir un servicio de Web API que soporte a usuarios autenticados con diferentes proveedores de identidad como por ejemplo Azure AD, Office 365,ADFS 2, Windows Live, Google, nuestro propio STS etc, de una manera sencilla y sin apenas desarrollo.&lt;/p&gt;  &lt;h3&gt;Diseño&lt;/h3&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;p&gt;Una vez marcado el objetivo vamos a ver como realizamos esta tarea. En primer lugar necesitaremos que nuestro servicio disponga de un mecanismo para obtener y validar los tokens en las diferentes peticiones que al mismo se le realicen. Al igual que para el resto de ejemplos que hemos puesto en los enlaces anteriores, el mejor mecanismo para esto parece la creación de un &lt;a href="http://www.asp.net/web-api/overview/working-with-http/http-message-handlers"&gt;DelegatingHandler&lt;/a&gt;. Tal y como podemos ver en la &lt;a href="http://www.asp.net/web-api/overview/working-with-http/http-message-handlers"&gt;documentación&lt;/a&gt; mediante estas piezas podremos agregar procesamiento al pipeline de ejecución de ASP.NET Web API. Por lo tanto, nuestro objetivo es crear un manejador capaz de interceptar nuestro token y validarlo. Por supuesto una vez validado crearemos los correspondientes &lt;strong&gt;ClaimsPrincipal&lt;/strong&gt; en el hilo de ejecución y el contexto &lt;strong&gt;Http &lt;/strong&gt;para que puedan ser usados / revisados por el resto de elementos que componen la petición. Para seguir la norma, utilizaremos la cabecera &lt;strong&gt;Authorization &lt;/strong&gt;como contenedor del token a validar. Una vez dicho esto el esqueleto de nuestra pieza podría ser algo como lo siguiente:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/webapi_5F00_handlers_5F00_02_5F00_4460A32E.png"&gt;&lt;img title="webapi_handlers_02" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;float:right;padding-top:0px;padding-left:0px;margin:5px 5px 5px 0px;display:inline;padding-right:0px;border-top-width:0px;" border="0" alt="webapi_handlers_02" align="right" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/webapi_5F00_handlers_5F00_02_5F00_thumb_5F00_3C6900CC.png" width="371" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AALMessageHandler
        : DelegatingHandler
    {
        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; Task&amp;lt;HttpResponseMessage&amp;gt; SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var authorization = request.Headers.Authorization;

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (authorization != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; authorization.IsAuthorizationSchema())
            {
                var token = authorization.Parameter;

                &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsValidToken(token))
                {
                    &lt;span class="rem"&gt;//set thread principal and http context user&lt;/span&gt;
                }

            }

            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.SendAsync(request, cancellationToken);
        }

        &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsValidToken(&lt;span class="kwrd"&gt;string&lt;/span&gt; token)
        {
            &lt;span class="rem"&gt;//validate the token&lt;/span&gt;
        }
    }
        &lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Con respecto a la parte de cliente no tenemos que hacer mucho más que en la anterior entrada, si acaso, lo único es ver como convertir nuestro Assertion Credential en un &lt;strong&gt;bearer&lt;/strong&gt; token, pero esto con AAL es tan sencillo como podemos ver a continuación, gracias al método &lt;strong&gt;CreateAuthorizationHeader.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; tenant = ConfigurationManager.AppSettings[&lt;span class="str"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt;];
            &lt;span class="kwrd"&gt;string&lt;/span&gt; realm = ConfigurationManager.AppSettings[&lt;span class="str"&gt;&amp;quot;realm&amp;quot;&lt;/span&gt;];&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;using&lt;/span&gt;(AuthenticationContext context = &lt;span class="kwrd"&gt;new&lt;/span&gt; AuthenticationContext(tenant))
            {
                var credential = context.AcquireUserCredentialUsingUI(realm);
                
                &lt;span class="kwrd"&gt;return&lt;/span&gt; credential != &lt;span class="kwrd"&gt;null&lt;/span&gt; ? credential.CreateAuthorizationHeader() : &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            }&lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;El resultado de las líneas anteriores es que una vez un usuario es autenticado usado cualquiera de los proveedores de identidad configurados en nuestro &lt;strong&gt;Azure Access Control&lt;/strong&gt; obtenemos un &lt;a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-04"&gt;bearer token&lt;/a&gt;, representado en una cadena de texto. Un &lt;a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-04"&gt;bearer token&lt;/a&gt; no es más que un token con la propiedad de que cualquier portador puede usar el token en los otros lugares, es decir, se elimina la necesidad de disponer de material criptográfico ( proof-of-possesion).&lt;/p&gt;

&lt;h3&gt;La implementacion&lt;/h3&gt;

&lt;p&gt;Bien, ahora que ya tenemos más o menos claro como haremos nuestro trabajo llega la hora de la implementación. Empezaremos por la parte más sencilla que es la parte de cliente, en la que además de las líneas anteriores pare obtener un token con AAL simplemente haremos una petición a un servicio de Web API cualquier, por ejemplo &lt;strong&gt;GET /API/Some.&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;            &lt;span class="rem"&gt;//get the bearer token using AAL&lt;/span&gt;
            var token = CreateToken();

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (token != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                &lt;span class="rem"&gt;//create http client&lt;/span&gt;
                var httpClient = HttpClientFactory.Create();
                httpClient.BaseAddress = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;the base address of your web api project&amp;quot;&lt;/span&gt;);

                &lt;span class="rem"&gt;//add default media type &lt;/span&gt;
                httpClient.DefaultRequestHeaders.Accept.Add(
                    &lt;span class="kwrd"&gt;new&lt;/span&gt; MediaTypeWithQualityHeaderValue(&lt;span class="str"&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;));

                &lt;span class="rem"&gt;//add the token&lt;/span&gt;
                httpClient.DefaultRequestHeaders.Authorization = &lt;span class="kwrd"&gt;new&lt;/span&gt; AuthenticationHeaderValue(&lt;span class="str"&gt;&amp;quot;Authorization&amp;quot;&lt;/span&gt;, token);

                &lt;span class="rem"&gt;//perform the request&lt;/span&gt;
                var request = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpRequestMessage(HttpMethod.Get, &lt;span class="str"&gt;&amp;quot;api/some&amp;quot;&lt;/span&gt;);

                httpClient.SendAsync(request)
                        .ContinueWith((t) =&amp;gt;
                        {
                            &lt;span class="kwrd"&gt;if&lt;/span&gt; (t.Result.IsSuccessStatusCode)
                            {
                                var content = t.Result.Content.ReadAsAsync&amp;lt;IEnumerable&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;&amp;gt;().Result;

                                &lt;span class="rem"&gt;//display the secret content...&lt;/span&gt;
                            }
                        }, TaskContinuationOptions.OnlyOnRanToCompletion);
            }&lt;/pre&gt;


&lt;p&gt;Del código anterior, la nota a destacar es el uso de la cabecera con el token recuperado de la autenticación del usuario. Cabecera que viajará en todas las peticiones realizadas con nuestro &lt;a href="http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&amp;amp;l=EN-US&amp;amp;k=k(System.Net.Http.HttpClientFactory);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.0);k(DevLang-csharp)&amp;amp;rd=true"&gt;HttpClient&lt;/a&gt;. En el caso del servidor, del esqueleto anterior tenemos que hacer dos trabajos fundamentales. La validación del token y el establecimiento de las credenciales recuperadas. Empezemos por la primera de las tareas. Gracias a AAL, la validación de un token es casi tan sencilla como la obtención del mismo, puesto que solamente tendremos que realizar lo siguiente:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; //if token is bearer remove text &amp;#39;Bearer &amp;#39; &lt;/p&gt;

  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if ( token.StartsWith(&amp;quot;Bearer &amp;quot;) ) 
    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; token =token.Substring(7);&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;      var tenant = ConfigurationManager.AppSettings[&lt;span class="str"&gt;&amp;quot;tenant&amp;quot;&lt;/span&gt;];&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;pre class="csharpcode"&gt;            var authenticationContext = &lt;span class="kwrd"&gt;new&lt;/span&gt; AuthenticationContext(tenant);
            authenticationContext.Options = options;

            principal = authenticationContext.AcceptToken(token);&lt;/pre&gt;


&lt;p&gt;Antes de nada, disculpad por el pequeño toque con el texto&lt;em&gt; &lt;strong&gt;Bearer&amp;#160; &lt;/strong&gt;&lt;/em&gt;del &lt;strong&gt;token&lt;/strong&gt;, pero creí que era más entendible ponerlo así que tratarlo como sería en un código &lt;em&gt;normal&lt;/em&gt; por medio de algún método de sanitización. Por supuesto, al método anterior tendremos que indicarle cuales son las opciones de autenticación, mediante nuestro objeto options, el cual podría ser algo similar a lo siguiente:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;            var certString = ConfigurationManager.AppSettings[&lt;span class="str"&gt;&amp;quot;CertificateForAAL&amp;quot;&lt;/span&gt;];
            var certificate = &lt;span class="kwrd"&gt;new&lt;/span&gt; X509Certificate2(Convert.FromBase64String(certString));
            var options = &lt;span class="kwrd"&gt;new&lt;/span&gt; AuthenticationOptions();
            options.Audiences.Add(audience);
            options.Issuer = tenant;
            options.SigningCredential = &lt;span class="kwrd"&gt;new&lt;/span&gt; X509CertificateCredential(audience, certificate);&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Por supuesto, el certificado seleccionado, está dado de alta en el portal de ACS en la sección Certificates and Keys, como se ven en la siguiente imagen.&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/Untitled_5F00_0CCAE240.png"&gt;&lt;img title="Untitled" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;float:none;padding-top:0px;padding-left:0px;margin:5px auto;display:block;padding-right:0px;border-top-width:0px;" border="0" alt="Untitled" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled_5F00_thumb_5F00_6BD76F98.png" width="644" height="220" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;h3&gt;El casi&lt;/h3&gt;

&lt;p&gt;Umm. el casi. Bueno, el primer motivo por el que esto no está perfecto es porque AAL solamente está compilada para WIF 3.5 y por lo tanto tendremos esta dependencia. Esto es una pena si trabajamos en VS 2012 y .NET 4.5 puesto que los elementos de Microsoft.IdentityModel ya los tendremos incluídos como hemos dicho ya muchas veces. A mayores, me queda por jugar un poco con el api de cliente para otras plataformas para ver como está y de verdad darle una nota sobresaliente… amén de que estamos en beta aún :-(.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Bueno, como siempre, espero que os sea de utilidad…&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=207280" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="Azure" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure/default.aspx" /><category term="ACS" scheme="http://geeks.ms/blogs/unai/archive/tags/ACS/default.aspx" /><category term="AAL" scheme="http://geeks.ms/blogs/unai/archive/tags/AAL/default.aspx" /><category term="ASP.NET MVC" scheme="http://geeks.ms/blogs/unai/archive/tags/ASP.NET+MVC/default.aspx" /><category term="C#" scheme="http://geeks.ms/blogs/unai/archive/tags/C_2300_/default.aspx" /><category term="Web API" scheme="http://geeks.ms/blogs/unai/archive/tags/Web+API/default.aspx" /><category term=".NET" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET/default.aspx" /></entry><entry><title>Home Realm Discovery en MVC 4 y Identity and Access Tool</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/10/25/home-realm-discovery-en-mvc-4-y-identity-and-access-tool.aspx" /><id>/blogs/unai/archive/2012/10/25/home-realm-discovery-en-mvc-4-y-identity-and-access-tool.aspx</id><published>2012-10-25T18:45:46Z</published><updated>2012-10-25T18:45:46Z</updated><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;En una anterior &lt;a href="http://geeks.ms/blogs/unai/archive/2012/08/03/identity-amp-net-4-5-vi.aspx"&gt;entrada&lt;/a&gt;, no muy lejana la verdad, vimos como configurar nuestro sitio construído en MVC 4 contra un ACS de Windows Azure para lograr la externalización de la autenticación y tener un modelo basado en claims de una forma terriblemente sencilla. Leyendo el blog de &lt;a href="http://blogs.msdn.com/b/vbertocci/"&gt;V Bertocci&lt;/a&gt; veo que la liberación de la RTM de la herramienta Identity and Access Tool incluye la posibilidad de que el proceso de Home Realm Discovey se pueda realizar nuestro propio sitio web en vez de tener la página por defecto para ese namespace en Windows Azure, y así, lograr una experiencia más agradable al usuario y un mismo diseño para nuestra web y esta vista. El proceso para realizar esto es realmente sencillo, no voy a volver a realizar los paso comunes a la anterior entrada, la dejor para su &lt;a href="http://geeks.ms/blogs/unai/archive/2012/08/03/identity-amp-net-4-5-vi.aspx"&gt;lectura&lt;/a&gt;. Lo único que haremos es fijarnos como ahora, en esta nueva versión de la herramienta disponemos de una opción para crear un controlador y una vista para tener el HRD en nuestro sitio, como acabamos de comentar.&lt;/p&gt; &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled3_5F00_5DAE21D7.png"&gt;&lt;img title="Untitled3" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;float:right;padding-top:0px;padding-left:0px;margin:5px 0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="Untitled3" align="right" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled3_5F00_thumb_5F00_787A47E3.png" width="644" height="200" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Esta opción, que podemos ver en la imagen de la derecha nos permitirá seleccionar tanto el nombre del controlador como de la acción que queremos que hagan el trabajo. Una vez seleccionada, al aceptar el paso veremos como una serie de elementos son agregados a nuestro sitio MVC 4, concrétamente los siguientes:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Un nuevo controlador, por defecto llamado HrdAuthenticationController&lt;/li&gt; &lt;li&gt;Una nueva accion al controlador anterior llamado Login&lt;/li&gt; &lt;li&gt;Una vista para la acción Login&lt;/li&gt; &lt;li&gt;Un script de javascript llamado HrdAuthentication.js&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;A continuación, haremos un breve repaso de que contiene cada uno de estos elementos. En primer lugar el controlador como veremos es realmente sencillo, puesto que su código únicamente contiene lo siguiente.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HrdAuthenticationController : Controller
    {
        [AllowAnonymous]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult Login()
        {
            ViewBag.MetaDataScript = &lt;span class="str"&gt;&amp;quot;https://geeksms.accesscontrol.windows.net/v2/metadata/identityProviders.js?protocol=wsfederation&amp;amp;realm=http://localhost:13021/&amp;amp;version=1.0&amp;amp;callback=ShowSigninPage&amp;quot;&lt;/span&gt;;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; View(&lt;span class="str"&gt;&amp;quot;~/Views/HrdAuthentication/Login.cshtml&amp;quot;&lt;/span&gt;);
        }
    }&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;p&gt;Como puede observar, no hay nada en especial,&amp;nbsp; solamente la entrada de nuestro ViewBag MetaDataScript el cual contiene la Url de un script js alojado en nuestro ACS en la que hay una callback ( jsonp ) a un función llamada &lt;strong&gt;ShowSigninPage&lt;/strong&gt;. Si buscamos en el javascript HrdAuthentication.js veremos que el contenido del mismo trae precisamente esta función.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// &lt;/span&gt;
&lt;span class="rem"&gt;// Code generated by Identity and Access VS Package&lt;/span&gt;
&lt;span class="rem"&gt;// &lt;/span&gt;

&lt;span class="kwrd"&gt;function&lt;/span&gt; ShowSigninPage(IPs) {
    $.each(IPs, &lt;span class="kwrd"&gt;function&lt;/span&gt; (i, ip) {
        $(&lt;span class="str"&gt;&amp;quot;#IPDiv&amp;quot;&lt;/span&gt;).append(&lt;span class="str"&gt;&amp;#39;&amp;lt;a href=&amp;quot;&amp;#39;&lt;/span&gt; + ip.LoginUrl + &lt;span class="str"&gt;&amp;#39;&amp;quot;&amp;gt;&amp;#39;&lt;/span&gt; + ip.Name + &lt;span class="str"&gt;&amp;#39;&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;#39;&lt;/span&gt;);
    });
};&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Fíjese como es en esta función dónde se definen como se construyen los enlaces a los diferentes Identity Providers y por lo tanto, podría ser un punto de toque al querer estilizar nuestra visa. Para terminar, el código de la vista también es terriblemente sencillo, puesto que solamente incorporar los dos js mencionados anteriormente, amén del div IPDiv usado.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;@*
Code generated by Identity and Access VS Package
*@

&amp;lt;hgroup &lt;span class="kwrd"&gt;class&lt;/span&gt;=&lt;span class="str"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&amp;gt;
    &amp;lt;h1&amp;gt;Log &lt;span class="kwrd"&gt;in&lt;/span&gt;&amp;lt;/h1&amp;gt;
    &amp;lt;h2&amp;gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; one of the identity providers below&amp;lt;/h2&amp;gt;
&amp;lt;/hgroup&amp;gt;

&amp;lt;div id=&lt;span class="str"&gt;&amp;quot;IPDiv&amp;quot;&lt;/span&gt;/&amp;gt;

&lt;span class="preproc"&gt;@section&lt;/span&gt; Scripts {
    @Scripts.Render(&lt;span class="str"&gt;&amp;quot;~/scripts/HrdAuthentication.js&amp;quot;&lt;/span&gt;);

    &amp;lt;script src=&lt;span class="str"&gt;&amp;quot;@ViewBag.MetaDataScript&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
}
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Sencillo verdad? y todo sigue funcionando perfectamente.&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/Untitled5_5F00_7016728C.png"&gt;&lt;img title="Untitled5" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;float:none;padding-top:0px;padding-left:0px;margin:5px auto;border-left:0px;display:block;padding-right:0px;" border="0" alt="Untitled5" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled5_5F00_thumb_5F00_6F3E0CA2.png" width="644" height="354" /&gt;&lt;/a&gt;&lt;/p&gt;






&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ha sido una entrada pequeña, pero creo que muy interesante&amp;nbsp; este pequeño descubrimiento…&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&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=207232" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="Azure" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure/default.aspx" /><category term="WIF" scheme="http://geeks.ms/blogs/unai/archive/tags/WIF/default.aspx" /><category term="MVC" scheme="http://geeks.ms/blogs/unai/archive/tags/MVC/default.aspx" /><category term="ASP.NET" scheme="http://geeks.ms/blogs/unai/archive/tags/ASP.NET/default.aspx" /><category term="Azure ACS" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure+ACS/default.aspx" /><category term="ACS" scheme="http://geeks.ms/blogs/unai/archive/tags/ACS/default.aspx" /><category term="HRD" scheme="http://geeks.ms/blogs/unai/archive/tags/HRD/default.aspx" /></entry><entry><title>Azure: Windows Azure Authentication Library</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/10/22/azure-windows-azure-authentication-library.aspx" /><id>/blogs/unai/archive/2012/10/22/azure-windows-azure-authentication-library.aspx</id><published>2012-10-22T16:23:42Z</published><updated>2012-10-22T16:23:42Z</updated><content type="html">&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Como seguro que todos los que leéis mi blog sabréis, el manejo de la identidad es un tema que me apasiona y sobre el que ya he escrito mucho. De hecho, ahora mismo me encuentro en fase de preparación sobre un libro acerca del manejo de la identidad, que espero en poco tiempo esté a vuestra disposición de forma gratuita. Pues bien, desde hace un tiempo para aquí sobre este tema se ha avanzado mucho en plataforma &lt;a&gt;Microsoft&lt;/a&gt;, tanto que a veces no damos ni seguido ciertos elementos, como por ejemplo era mi caso con &lt;a href="http://docs.nuget.org/docs/start-here/overview"&gt;AAL ( Azure Authentication Library),&lt;/a&gt; por eso, para intentar remediar este inconveniente, empezaré una serie de post acerca de este temática que nos permitan ver todo el trabajo que el equipo de &lt;a href="http://windows.azure.com/"&gt;Windows Azure&lt;/a&gt; está haciendo sobre esto, centrándonos especialmente en los siguientes puntos&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;h5&gt;Azure Authentication Library&lt;/h5&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://docs.nuget.org/docs/start-here/overview"&gt;AAL&lt;/a&gt;, es básicamente un paquete de NuGet que nos habilita un serie de ensamblados para realizar alguna de las siguientes tareas:&lt;/p&gt;    &lt;ul&gt;     &lt;ul&gt;       &lt;li&gt;Gestión de tokens, generalmente server to server &lt;/li&gt;        &lt;li&gt;Autenticación con Azure AD, Azure ACS&amp;#160; y ADFS 2.0 y otros proveedores&lt;/li&gt;        &lt;li&gt;Validación de tokens&lt;/li&gt;     &lt;/ul&gt;   &lt;/ul&gt;    &lt;p&gt;Como en casi todo lo que tenga que ver con la identidad y su gestión, una de las principales fuentes ( a mayores de lo que yo mismo pueda ir masticando y contando en este blog ) es el blog de &lt;a href="http://blogs.msdn.com/b/vbertocci/archive/2012/08/01/windows-azure-authentication-library-a-deep-dive.aspx"&gt;Vittorio Bertoci&lt;/a&gt;, el cual recomiendo encarecidamente puesto que, tal y como acabo de decir, es siempre una de mis fuentes principales de información y aprendizaje.&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;h5&gt;Windows Azure Active Directory&lt;/h5&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;El segundo de los temas que trataremos es &lt;a href="http://blogs.msdn.com/b/windowsazure/archive/2012/07/12/announcing-the-developer-preview-of-windows-azure-active-directory.aspx"&gt;Azure Active Directory&lt;/a&gt; junto con dos elementos fundamtales como &lt;a href="http://blogs.msdn.com/b/windowsazure/archive/2012/06/19/reimagining-active-directory-for-the-social-enterprise-part-2.aspx"&gt;Graph API&lt;/a&gt; y &lt;a href="https://github.com/WindowsAzure/azure-sdk-for-dotnet-samples"&gt;Web Single Sign-ON&lt;/a&gt;.&lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Con el fin de que esta &lt;strong&gt;entrada no se quede en una mera entrada informativa&lt;/strong&gt;, no me parece muy adecuado, empezaremos por sentar las bases de AAL y desgranar algunos conceptos.&lt;/p&gt;  &lt;h3&gt;AAL&lt;/h3&gt;  &lt;p&gt;¿Que es AAL y para que sirve? Aunque, ya lo explicamos un poco en las líneas anterior hay una frase de Vittorio que creo que da una buena explicación de que es y para que no sirve esta nueva librería&lt;em&gt;.”AAL viene a dar solución a algunas de las tareas que los desarrolladores necesitan para manejar la autenticación;asumiendo para ello que no tenemos un profundo conocimiento del protocolo en juego”.&lt;/em&gt; Para utilizar AAL solamente tenemos que instalar el paquete &lt;a href="https://nuget.org/packages/Microsoft.WindowsAzure.ActiveDirectory.Authentication.x64/0.5.0"&gt;Windows Azure Authentication Library BETA&lt;/a&gt; gracias al cual incorporaremos a nuestro proyecto la librería&lt;strong&gt; Microsoft.WindowsAzure.ActiveDirectory.Authentication.dll&lt;/strong&gt; cuyo contenido puede verse de forma resumida en la siguiente imagen.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&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/5100_5F00_image_5F00_thumb_5F00_077C2CA7_5F00_54E40D0D.png"&gt;&lt;img title="5100_image_thumb_077C2CA7" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;float:none;padding-top:0px;padding-left:0px;margin:5px auto;border-left:0px;display:block;padding-right:0px;" border="0" alt="5100_image_thumb_077C2CA7" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/5100_5F00_image_5F00_thumb_5F00_077C2CA7_5F00_thumb_5F00_213BA0AF.png" width="644" height="309" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Con el fin de empezar con un pequeño detalle que nos muestre alguna de sus características haremos un pequeño ejemplo en una aplicación de Windows Forms terriblemente sencilla, tanto que lo único que tendremos es un boton con el siguiente manejador.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;           &lt;span class="kwrd"&gt;using&lt;/span&gt; (var context = &lt;span class="kwrd"&gt;new&lt;/span&gt; AuthenticationContext(&lt;span class="str"&gt;&amp;quot;https://identity45.accesscontrol.windows.net&amp;quot;&lt;/span&gt;))
           {
                var credentials = context.AcquireUserCredentialUsingUI(&lt;span class="str"&gt;&amp;quot;urn:geeksmsaalsample&amp;quot;&lt;/span&gt;);
           }&lt;/pre&gt;


&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Dónde &lt;em&gt;&lt;strong&gt;“https://identity45.accesscontrol.windows.net” &lt;/strong&gt;&lt;/em&gt;representa el namespace de nuestro servicio de Azure Access Control Service y “urn:geeksmsaalsample” es el realm de nuestra aplicación. Si simplemente con eso ejecutamos nuestra aplicación veremos como se nos mostrará una pequeña ventana que contendrá el siguiente mensaje de error:&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/1_5F00_71314F2D.png"&gt;&lt;img title="1" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;float:none;padding-top:0px;padding-left:0px;margin:5px auto;border-left:0px;display:block;padding-right:0px;" border="0" alt="1" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/1_5F00_thumb_5F00_1E463BFC.png" width="644" height="130" /&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Este mensaje de error se debe a la inexistencia en la configuración de nuestro namespace de access control service de un RP con este REALM. Para arreglarlo nos vamos a nuestra configuración de Azure y creamos un nuevo Relay Party, en nuestro ejemplo tan simple como se ve a continuación.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/c4_5F00_443BEC52.png"&gt;&lt;img title="c4" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;float:none;padding-top:0px;padding-left:0px;margin:5px auto;border-left:0px;display:block;padding-right:0px;" border="0" alt="c4" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/c4_5F00_thumb_5F00_42F75373.png" width="573" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Una vez creado, ahora si se nos presentarán los diferentes proveedores de identidad configurados en Azure ACS para esta nueva RP y nos podremos autenticar de esta forma tan sencilla utilizando distintos proveedores tal y como se ven en las siguientes imagenes. Aunque no lo hemos comentado, en el paso anterior hay que especificar las reglas de este RP, en nuestro ejemplo hemos puesto un passthrough de los proveedores de identidad configurados.&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/2_5F00_3A274B27.png"&gt;&lt;img title="2" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;float:none;padding-top:0px;padding-left:0px;margin:5px auto;border-left:0px;display:block;padding-right:0px;" border="0" alt="2" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/2_5F00_thumb_5F00_27061E7B.png" width="644" height="412" /&gt;&lt;/a&gt;&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/c3_5F00_17830CAC.png"&gt;&lt;img title="c3" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;float:none;padding-top:0px;padding-left:0px;margin:5px auto;border-left:0px;display:block;padding-right:0px;" border="0" alt="c3" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/c3_5F00_thumb_5F00_1D5DB045.png" width="485" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;









&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Tal y como observá, el proceso que hemos hecho es &lt;a href="http://geeks.ms/blogs/unai/archive/2012/08/03/identity-amp-net-4-5-vi.aspx"&gt;idéntico al proceso de dar de alta Access Control Service para un proyecto web&lt;/a&gt; ahora en un cliente rico de una manera insultantemente sencilla. Es más, si observa en el tipo de resultado &lt;strong&gt;AssertionCredential &lt;/strong&gt;este nos permite generar un token para ser utilizado en servicios &lt;strong&gt;OAuth&lt;/strong&gt; o para enviar este token a nuestros servicios, por ejemplo&lt;strong&gt; web api&lt;/strong&gt;,que después, podrán validar también utilizando este mismo paquete.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;            &lt;span class="kwrd"&gt;using&lt;/span&gt; (var context = &lt;span class="kwrd"&gt;new&lt;/span&gt; AuthenticationContext(&lt;span class="str"&gt;&amp;quot;https://identity45.accesscontrol.windows.net&amp;quot;&lt;/span&gt;))
            {
                &lt;span class="rem"&gt;//authenticate and return credentials&lt;/span&gt;
                var credentials = context.AcquireUserCredentialUsingUI(&lt;span class="str"&gt;&amp;quot;urn:geeksmsaalsample&amp;quot;&lt;/span&gt;);

                &lt;span class="kwrd"&gt;if&lt;/span&gt; (credentials != &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="rem"&gt;//the user is logged!&lt;/span&gt;
                {
                    &lt;span class="rem"&gt;//get token to use in com to server&lt;/span&gt;
                    var token = credentials.CreateAuthorizationHeader();
                }
            }&lt;/pre&gt;

&lt;p&gt;Bueno, aquí lo dejamos, si le ha gustado, no se preocupe porque pronto volveremos al ataque con más y esperemos que mejor…&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=207198" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="Azure AppFabric" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure+AppFabric/default.aspx" /><category term="windows Identity Foundation" scheme="http://geeks.ms/blogs/unai/archive/tags/windows+Identity+Foundation/default.aspx" /><category term="Azure" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure/default.aspx" /><category term="seguridad" scheme="http://geeks.ms/blogs/unai/archive/tags/seguridad/default.aspx" /><category term="WIF" scheme="http://geeks.ms/blogs/unai/archive/tags/WIF/default.aspx" /><category term="STS" scheme="http://geeks.ms/blogs/unai/archive/tags/STS/default.aspx" /><category term="Identity Model" scheme="http://geeks.ms/blogs/unai/archive/tags/Identity+Model/default.aspx" /><category term="Security" scheme="http://geeks.ms/blogs/unai/archive/tags/Security/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="Idenity" scheme="http://geeks.ms/blogs/unai/archive/tags/Idenity/default.aspx" /><category term="Azure ACS" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure+ACS/default.aspx" /></entry><entry><title>Windows Azure Storage Account Monitoring and Logging</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/10/16/windows-azure-storage-account-monitoring-and-logging.aspx" /><id>/blogs/unai/archive/2012/10/16/windows-azure-storage-account-monitoring-and-logging.aspx</id><published>2012-10-16T21:45:00Z</published><updated>2012-10-16T21:45:00Z</updated><content type="html">&lt;p&gt;Aunque era algo que ya ten&amp;iacute;amos en el antiguo portal de Windows Azure, sin duda, una de las cosas m&amp;aacute;s interesantes que nos ofrece la nueva versi&amp;oacute;n es la facilidad para manejar la monitorizaci&amp;oacute;n de los distintos elementos disponibles, entre ellos las cuantas de Storage. Como puede observar en la siguiente imagen, la interfaz nos permite de una forma sencilla habilitar la monitorizaci&amp;oacute;n para los diferentes elementos de un storage ( blob, queues y tables ). En ocasiones, disponer de el portal de azure como herramienta de trabajo principal no es posible, imagine que usted esta usando la infraestructura de azure para terceros y que desea en sus propias herramientas habilitar y ver toda esta informaci&amp;oacute;n de monitorizaci&amp;oacute;n. En estos casos, necesitamos de un mecanismo para poder habilit&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled_5F00_2E2E527E.png"&gt;&lt;img height="484" width="644" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/unai/Untitled_5F00_thumb_5F00_24098B86.png" align="right" alt="Untitled" border="0" style="border-left-width:0px;border-right-width:0px;background-image:none;border-bottom-width:0px;float:right;padding-top:0px;padding-left:0px;margin:5px 5px 5px 0px;display:inline;padding-right:0px;border-top-width:0px;" title="Untitled" /&gt;&lt;/a&gt;ar de forma program&amp;aacute;tica la configuraci&amp;oacute;n de monitorizaci&amp;oacute;n, y, por supuesto, tambi&amp;eacute;n necesitaremos un mecanismos para ver los diferentes valores de las m&amp;eacute;tricas de esta configuraci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Por suerte, todo lo que tenemos disponible en el portal lo tenemos disponible nosotros, puesto que en teor&amp;iacute;a este portal est&amp;aacute; construido con el mismo API que nosotros tenemos a nuestra disposici&amp;oacute;n. Por lo tanto vamos a intentar realizar dos pasos, configuraci&amp;oacute;n de la monitorizaci&amp;oacute;n y revisi&amp;oacute;n de las m&amp;eacute;tricas sin necesidad de utilizar el portal de azure. por supuesto el c&amp;oacute;digo es meramente demostrativo, como casi siempre en los posts, y tendr&amp;aacute; muchas posibilidades de mejora, pero ya le queda a usted estimado lector para ganarse su trabajo;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Configuraci&amp;oacute;n de la monitorizaci&amp;oacute;n&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Para realizar la configuraci&amp;oacute;n de la monitorizaci&amp;oacute;n utilizaremos uno de esos N API Rest que Azure nos pone a nuestra disposici&amp;oacute;n, en concreto el API rest referido a los servicios de Blob, Queues y/o Tables, dependiendo de que monitorizaci&amp;oacute;n querramos habilitar. En el siguiente &lt;a href="http://msdn.microsoft.com/en-us/library/hh452235.aspx"&gt;enlace&lt;/a&gt; puede ver el caso concreto del servicio de blob &lt;a href="http://msdn.microsoft.com/en-us/library/hh452235.aspx"&gt;Set Blob Service Properties&lt;/a&gt; gracias al cual podremos hacer este trabajo. En realidad el API para los diferentes elementos solamente presenta cambios en la url ( los segmentos blob,queues o tables dependiendo del servicio ) y el modo de autenticaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Seg&amp;uacute;n el m&amp;eacute;todo mencionado anteriormente, para habilitar la configuraci&amp;oacute;n solamente tendremos que realizar una petici&amp;oacute;n PUT a laa url &lt;code&gt;&lt;a href="http://&amp;lt;account-name&amp;gt;.blob.core.windows.net/?restype=service&amp;amp;comp=properties"&gt;.blob.core.windows.net/?restype=service&amp;amp;comp=properties&amp;quot;&amp;gt;.blob.core.windows.net/?restype=service&amp;amp;comp=properties&amp;quot;&amp;gt;.blob.core.windows.net/?restype=service&amp;amp;comp=properties&amp;quot;&amp;gt;.blob.core.windows.net/?restype=service&amp;amp;comp=properties&amp;quot;&amp;gt;http://&amp;lt;account-name&amp;gt;.blob.core.windows.net/?restype=service&amp;amp;comp=properties&lt;/a&gt; &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;utilizando un cuerpo de mensaje similar al siguiente fragmento (extra&amp;iacute;do del enlace anterior )&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&amp;lt;?xml version=&lt;span class="str"&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; encoding=&lt;span class="str"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&amp;gt;
&amp;lt;StorageServiceProperties&amp;gt;
    &amp;lt;Logging&amp;gt;
        &amp;lt;Version&amp;gt;version-number&amp;lt;/Version&amp;gt;
        &amp;lt;Delete&amp;gt;&lt;span class="kwrd"&gt;true&lt;/span&gt;|&lt;span class="kwrd"&gt;false&lt;/span&gt;&amp;lt;/Delete&amp;gt;
        &amp;lt;Read&amp;gt;&lt;span class="kwrd"&gt;true&lt;/span&gt;|&lt;span class="kwrd"&gt;false&lt;/span&gt;&amp;lt;/Read&amp;gt;
        &amp;lt;Write&amp;gt;&lt;span class="kwrd"&gt;true&lt;/span&gt;|&lt;span class="kwrd"&gt;false&lt;/span&gt;&amp;lt;/Write&amp;gt;
        &amp;lt;RetentionPolicy&amp;gt;
            &amp;lt;Enabled&amp;gt;&lt;span class="kwrd"&gt;true&lt;/span&gt;|&lt;span class="kwrd"&gt;false&lt;/span&gt;&amp;lt;/Enabled&amp;gt;
            &amp;lt;Days&amp;gt;number-of-days&amp;lt;/Days&amp;gt;
        &amp;lt;/RetentionPolicy&amp;gt;
    &amp;lt;/Logging&amp;gt;
    &amp;lt;Metrics&amp;gt;
        &amp;lt;Version&amp;gt;version-number&amp;lt;/Version&amp;gt;
        &amp;lt;Enabled&amp;gt;&lt;span class="kwrd"&gt;true&lt;/span&gt;|&lt;span class="kwrd"&gt;false&lt;/span&gt;&amp;lt;/Enabled&amp;gt;
        &amp;lt;IncludeAPIs&amp;gt;&lt;span class="kwrd"&gt;true&lt;/span&gt;|&lt;span class="kwrd"&gt;false&lt;/span&gt;&amp;lt;/IncludeAPIs&amp;gt;
        &amp;lt;RetentionPolicy&amp;gt;
            &amp;lt;Enabled&amp;gt;&lt;span class="kwrd"&gt;true&lt;/span&gt;|&lt;span class="kwrd"&gt;false&lt;/span&gt;&amp;lt;/Enabled&amp;gt;
            &amp;lt;Days&amp;gt;number-of-days&amp;lt;/Days&amp;gt;
        &amp;lt;/RetentionPolicy&amp;gt;
    &amp;lt;/Metrics&amp;gt;
    &amp;lt;!-- The DefaultServiceVersion element can only be set &lt;span class="kwrd"&gt;for&lt;/span&gt; the Blob service and the request must be made &lt;span class="kwrd"&gt;using&lt;/span&gt; the 2011-08-18 version --&amp;gt;
    &amp;lt;DefaultServiceVersion&amp;gt;&lt;span class="kwrd"&gt;default&lt;/span&gt;-service-version-&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;lt;/DefaultServiceVersion&amp;gt;
&amp;lt;/StorageServiceProperties&amp;gt;&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;Pues bien, vamos a intentarlo:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para generar el XML anterior utilizaremos una serializaci&amp;oacute;n XML de las clases siguientes, las cuales, representan como ver&amp;aacute; este sencillo fragmento. Por supuesto, usted puede crear cualquier otro mecanismo, para conseguir tener este fragmento de XML. [Si utiliza &lt;strong&gt;XmlSerializer&lt;/strong&gt; no se olvide de utilizar &lt;strong&gt;XmlSerializerNamespace&lt;/strong&gt; para eliminar los namespaces que este serializador incluye por defecto]&lt;/p&gt;
&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; StorageServiceProperties
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Logging Logging { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Metrics Metrics { get; set; }
    }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Metrics
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Version { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Enabled { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IncludeAPIs { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; RetentionPolicy RetentionPolicy { get; set; }
    }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Logging
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Version { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Delete { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Read { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Write { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; RetentionPolicy RetentionPolicy { get; set; }
    }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RetentionPolicy
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Enabled { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Days { get; set; }
    }&lt;/pre&gt;
&lt;p&gt;Para la petici&amp;oacute;n utilizaremos &lt;a href="http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&amp;amp;l=EN-US&amp;amp;k=k(System.Net.HttpWebRequest);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&amp;amp;rd=true"&gt;HttpWebRequest&lt;/a&gt; o cualquier API de cliente&amp;nbsp; como HttpClient o &lt;a href="http://restsharp.org/"&gt;RestSharp&lt;/a&gt;. En nuestro caso, para no molestar al lector con otras API diferente a las habituales optaremos por el uso de la primera opci&amp;oacute;n, aunque habitualmente haga uso de &lt;a href="http://restsharp.org/"&gt;RestSharp&lt;/a&gt; para este tipo de tareas. A lo largo de las siguientes lineas, veremos como realizar la petici&amp;oacute;n solicitada por el API mencionado anteriormente.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;            &lt;span class="rem"&gt;//create the http request and set default headers&lt;/span&gt;
            &lt;span class="kwrd"&gt;string&lt;/span&gt; baseUri = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;http://{0}.blob.core.windows.net/?restype=service&amp;amp;comp=properties&amp;quot;&lt;/span&gt;, accountName);

            var request = (HttpWebRequest)HttpWebRequest.Create(baseUri);
            request.Headers.Add(&lt;span class="str"&gt;&amp;quot;x-ms-version&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;2009-09-19&amp;quot;&lt;/span&gt;);
            request.Method = &lt;span class="str"&gt;&amp;quot;PUT&amp;quot;&lt;/span&gt;;

            &lt;span class="rem"&gt;//set the content length from settings&lt;/span&gt;
            var bytes = UTF8Encoding.UTF8.GetBytes(settings);
            request.ContentLength = bytes.Length;&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;En estas lineas, &amp;eacute;l &amp;uacute;nico trabajo que hemos realizado es la creaci&amp;oacute;n de un request a la direcci&amp;oacute;n dada y seteados los valores de cabeceras como &amp;ldquo;x-ms-version&amp;rdquo; obligatorias seg&amp;uacute;n la informaci&amp;oacute;n que el API nos ofrece. El siguiente paso, es establecer la cabecera de authorizaci&amp;oacute;n, proceso que no es simple como podemos ver en los &lt;a href="http://msdn.microsoft.com/en-us/library/dd179428.aspx"&gt;esquemas de autenticaci&amp;oacute;n&lt;/a&gt; de Windows Azure pero que resolveremos de una forma terriblemente simple gracias a la clase &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storagecredentialsaccountandkey.aspx"&gt;StorageCredentialsAccountAndKey&lt;/a&gt; y a su m&amp;eacute;todo &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/microsoft.windowsazure.storagecredentialsaccountandkey.signrequest(v=azure.100).aspx"&gt;SignRequest&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;            var storageCredentials = &lt;span class="kwrd"&gt;new&lt;/span&gt; StorageCredentialsAccountAndKey(accountName,mystorageaccountprimarykey);
            storageCredentials.SignRequest(request);&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;Bien, ya solamente tenemos que escribir el cuerpo de la petici&amp;oacute;n y obtener la respuesta, y esto, es id&amp;eacute;ntico a cualquier petici&amp;oacute;n que ya hubi&amp;eacute;ramos hecho con &lt;a href="http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&amp;amp;l=EN-US&amp;amp;k=k(System.Net.HttpWebRequest);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&amp;amp;rd=true"&gt;HttpWebRequest&lt;/a&gt;. anteiormente.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;            request.GetRequestStream().Write(bytes, 0, bytes.Length);
            

            var response = request.GetResponse();&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consulta de las m&amp;eacute;tricas&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A lo largo de las l&amp;iacute;neas anteriores hemos visto como habilitar la monitorizaci&amp;oacute;n de una cuenta de storage de una forma simple. Pero, a&amp;uacute;n nos queda el elemento importante, que no es otro que la recuperaci&amp;oacute;n de los valores de las diferentes m&amp;eacute;tricas que hemos habilitado. Como se ha podido imaginar de las l&amp;iacute;neas anteriores, la activaci&amp;oacute;n/configuraci&amp;oacute;n se realiza a nivel de servicio ( para blob, queue, tables ) no para la cuenta de storage. Las m&amp;eacute;tricas de estos diferentes servicios las posemos categorizar en los siguientes puntos:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;M&amp;eacute;tricas de transacciones&lt;/strong&gt; - Expuesta, tal y como se puede ver &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/hh343264.aspx"&gt;aqu&amp;iacute;&lt;/a&gt;, en tres tablas fundamentales: &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;nbsp;
&lt;ul&gt;
&lt;li&gt;$MetricsTransactionBlob &lt;/li&gt;
&lt;li&gt;$MetricsTransactionsTable &lt;/li&gt;
&lt;li&gt;$MetricsTransactionsQueue &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;M&amp;eacute;tricas de capacidad &amp;ndash; &lt;/strong&gt;Expuestas, tal y como se puede ver &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/hh343258.aspx"&gt;aqui&lt;/a&gt;, en la siguiente tabla: &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;nbsp;
&lt;ul&gt;
&lt;li&gt;$MetricsCapacityBlob &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Para consultar los esquemas de las diferentes tablas de m&amp;eacute;tricas podemos acudir a la &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/hh343264.aspx"&gt;MSDN&lt;/a&gt; d&amp;oacute;nde obtendremos la informaci&amp;oacute;n necesaria. En realidad, no tiene demasiada historia, por lo menos no mucho m&amp;aacute;s que trabajar con cualquier Table Service de Azure. En nuestro caso, por ver un ejemplo, haremos lo siguiente, el mapeo de una entidad para trabajar con $MetricsTransactionsBlob, tal cual nos dice la &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/hh343258.aspx"&gt;documentaci&amp;oacute;n&lt;/a&gt;, y una consulta de todos los contadores usando un &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/microsoft.windowsazure.storageclient.tableservicecontext_members(v=azure.100).aspx"&gt;TableServiceContext&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;            var entitySetName = &lt;span class="str"&gt;&amp;quot;$MetricsTransactionsBlob&amp;quot;&lt;/span&gt;;

            var client = storageAccount.CreateCloudTableClient();

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (client.DoesTableExist(entitySetName))
            {
                var context = client.GetDataServiceContext();
                var data = context.CreateQuery&amp;lt;StorageMetrics&amp;gt;(entitySetName)
                                .ToList();
            }&lt;/pre&gt;
&lt;blockquote&gt;
&lt;pre class="csharpcode"&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; StorageMetrics : TableServiceEntity
      {
          &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; TotalRequests { get; set; }
          &lt;span class="kwrd"&gt;public&lt;/span&gt; StorageMetrics() { }
      }&lt;/pre&gt;

&lt;/blockquote&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;pre class="csharpcode"&gt;            &lt;/pre&gt;
&lt;p&gt;Espero que os haya resultado de inter&amp;eacute;s..&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&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=207146" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term=".NET General" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+General/default.aspx" /><category term="Azure" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure/default.aspx" /></entry><entry><title>Azure Service Bus : Topic Brokered Message</title><link rel="alternate" type="text/html" href="/blogs/unai/archive/2012/10/09/azure-service-bus-topic-brokered-message.aspx" /><id>/blogs/unai/archive/2012/10/09/azure-service-bus-topic-brokered-message.aspx</id><published>2012-10-09T20:26:00Z</published><updated>2012-10-09T20:26:00Z</updated><content type="html">&lt;p&gt;En las entradas anteriores ( &lt;a href="http://geeks.ms/blogs/unai/archive/2012/10/05/azure-service-bus-queues-brokered-messages-i.aspx"&gt;I&lt;/a&gt;,&lt;a href="http://geeks.ms/blogs/unai/archive/2012/10/06/azure-service-bus-queues-brokered-messages-ii.aspx"&gt;II&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/unai/archive/2012/10/08/azure-service-bus-queues-brokered-messages-iii.aspx"&gt;III&lt;/a&gt; ) vimos una peque&amp;ntilde;a introducci&amp;oacute;n a las colas de Service Bus y ya empezamos a hablar, ligeramente de los Topics. A lo largo de esta entrada ( en esta ocasi&amp;oacute;n el tema no da para una serie) veremos m&amp;aacute;s detenido el concepto de Topic.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Multiples lectores/subscriptores&lt;/h3&gt;
&lt;p&gt;Este t&amp;iacute;tulo es el concepto que define un &lt;strong&gt;Topic &lt;/strong&gt;de la mejor forma. En muchas ocasiones, necesitamos que un mismo mensaje de una cola pudiera ser procesado por m&amp;uacute;ltiples clientes, por ejemplo para que cada uno de ellos le pudiera dar un tratamiento diferente. Por poner un ejemplo, imag&amp;iacute;nese que est&amp;aacute; construyendo un sistema de procesado de datos en tiempo real y que cada dato tiene que ser procesado para diferentes tareas, compresi&amp;oacute;n y almacenado, agregaci&amp;oacute;n e historizaci&amp;oacute;n. Si tenemos una cola para realizar todas las tareas ser&amp;aacute; dificil separar las responsabilidades del receptor, en aquellas que hemos definido en nuestra premisa. Sin embargo, si pudi&amp;eacute;ramos tener diferentes lectores para cada uno de los mensajes podr&amp;iacute;amos tener un Subscriptor para leer mensajes e historiarlos, otro Subscriptor para leer mensajes y agregarlos y otro Subscriptor m&amp;aacute;s para comprimirlos y almacenarlos as&amp;iacute; conseguir&amp;iacute;amos dividir las responsabilidades en partes simples y por lo tanto m&amp;aacute;s mantenibles. Los topics en poco se diferencian de las colas, de hecho, su API es pr&amp;aacute;cticamente id&amp;eacute;ntico y disponen &lt;em&gt;casi &lt;/em&gt;de las mismas caracter&amp;iacute;sticas, tama&amp;ntilde;os de cola, formateadores, detecci&amp;oacute;n de duplicados. A continuaci&amp;oacute;n veremos el c&amp;oacute;digo necesario para la creaci&amp;oacute;n y envi&amp;oacute; de un mensaje a un Topic.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;            &lt;span class="rem"&gt;// The connection string for namespace manager is stored&lt;/span&gt;
            &lt;span class="rem"&gt;// in Microsoft.ServiceBus.ConnectionString app settings key&lt;/span&gt;
            var namespaceManager = NamespaceManager.Create();

            &lt;span class="rem"&gt;//create topic&lt;/span&gt;
            var topicDescription = namespaceManager.CreateTopic(&lt;span class="str"&gt;&amp;quot;topic&amp;quot;&lt;/span&gt;);

            &lt;span class="rem"&gt;//add subscriptions&lt;/span&gt;
            var historizationSubscription = namespaceManager.CreateSubscription(&lt;span class="str"&gt;&amp;quot;topic&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Historization&amp;quot;&lt;/span&gt;);
            var storeSubscription = namespaceManager.CreateSubscription(&lt;span class="str"&gt;&amp;quot;topic&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Store&amp;quot;&lt;/span&gt;);
            var aggregateSubscription = namespaceManager.CreateSubscription(&lt;span class="str"&gt;&amp;quot;topic&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Aggregate&amp;quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Si se para y recuerda el trabajo con las colas observar&amp;aacute; como es pr&amp;aacute;cticamente id&amp;eacute;ntico a lo que ya conoc&amp;iacute;amos de entradas anteriores, con la salvedad de que adem&amp;aacute;s de la creaci&amp;oacute;n del topic tambi&amp;eacute;n se ha procedido a la creaci&amp;oacute;n de las diferentes subscripciones de las que habl&amp;aacute;bamos anteriormente.&amp;nbsp; Con respecto al env&amp;iacute;o de mensajes en este caso no hay nada particular ni diferente respecto al uso de colas.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;            var messagingFactory = MessagingFactory.Create();
            var topic = messagingFactory.CreateTopicClient(&lt;span class="str"&gt;&amp;quot;topic&amp;quot;&lt;/span&gt;);

            topic.Send(&lt;span class="kwrd"&gt;new&lt;/span&gt; BrokeredMessage(&lt;span class="str"&gt;&amp;quot;the content&amp;quot;&lt;/span&gt;));&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;El c&amp;oacute;digo para la recepci&amp;oacute;n de mensajes en cada subscripci&amp;oacute;n podr&amp;iacute;a ser algo como lo siguiente:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;            var messagingFactory = MessagingFactory.Create();
            var subcriptor = messagingFactory.CreateSubscriptionClient(&lt;span class="str"&gt;&amp;quot;topic&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Historization&amp;quot;&lt;/span&gt;);

            var content = subcriptor.Receive().GetBody&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Filtros&lt;/h3&gt;
&lt;p&gt;En los pasos anteriores hemos visto los elementos fundamentales del trabajo con los topics. Sin embargo no hemos hablado de una caracter&amp;iacute;stica fundamental para los subscriptores que es la capacidad de filtrar los mensajes que quieren recibir. Por ejemplo, podr&amp;iacute;amos decidir que el subscriptor de agregaci&amp;oacute;n solamente recibiera aquellos mensajes con valores de se&amp;ntilde;ales que pudieran agregarse ( SUM,AVG, MAX &amp;hellip; ) . Estos filtros, representados por la clase &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/microsoft.servicebus.messaging.sqlfilter.sqlfilter(v=azure.100).aspx"&gt;Filter&lt;/a&gt;, y m&amp;aacute;s concretamente por &lt;a href="http://msdn.microsoft.com/en-us/library/windowsazure/microsoft.servicebus.messaging.sqlfilter.sqlfilter(v=azure.100).aspx"&gt;SqlFilter&lt;/a&gt;, nos permiten &amp;ldquo;filtrar&amp;rdquo; en funci&amp;oacute;n de las propiedades de los mensajes y usuario. El nombre de SqlFilter viene dado por la posibilidad de utilizar &lt;strong&gt;SQL92&lt;/strong&gt; como norma para los filtros.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&amp;lt;predicate ::=
{ NOT &amp;lt;predicate&amp;gt; }
| &amp;lt;predicate&amp;gt; AND &amp;lt;predicate&amp;gt;
| &amp;lt;predicate&amp;gt; OR &amp;lt;predicate&amp;gt;
| &amp;lt;expression&amp;gt; { = | &amp;lt;&amp;gt; | != | &amp;gt; | &amp;gt;= | &amp;lt; | &amp;lt;= } &amp;lt;expression&amp;gt;
| &amp;lt;property&amp;gt; IS [NOT] NULL
| &amp;lt;expression&amp;gt; [NOT] IN ( &amp;lt;expression&amp;gt; [, ...n] )
| &amp;lt;expression&amp;gt; [NOT] LIKE &amp;lt;pattern&amp;gt; [ESCAPE &amp;lt;escape_char&amp;gt;]
| EXISTS ( &amp;lt;property&amp;gt; )
| ( &amp;lt;predicate&amp;gt; )
 
&amp;lt;expression&amp;gt; ::=
&amp;lt;constant&amp;gt; 
| &amp;lt;property&amp;gt;
| &amp;lt;expression&amp;gt; { + | - | * | / } &amp;lt;expression&amp;gt;
| { + | - } &amp;lt;expression&amp;gt;
| ( &amp;lt;expression&amp;gt; )
&lt;/pre&gt;
&lt;p&gt;

&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Con el fin de poner un ejemplo podremos ver el siguiente &lt;strong&gt;tip&lt;/strong&gt;, donde se muestra la creaci&amp;oacute;n de un filtro para la subscripci&amp;oacute;n y el env&amp;iacute;o de un mensaje con esta propiedad:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="csharpcode"&gt;      var aggregateSubscription = namespaceManager.CreateSubscription(&lt;span class="str"&gt;&amp;quot;topic&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Aggregate&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlFilter(&lt;span class="str"&gt;&amp;quot;RequireAggregate=true&amp;quot;&lt;/span&gt;));&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;pre class="csharpcode"&gt;            var message = &lt;span class="kwrd"&gt;new&lt;/span&gt; BrokeredMessage(&lt;span class="str"&gt;&amp;quot;the content&amp;quot;&lt;/span&gt;);
            message.Properties[&lt;span class="str"&gt;&amp;quot;RequireAggregate&amp;quot;&lt;/span&gt;] = &lt;span class="kwrd"&gt;true&lt;/span&gt;;

            topic.Send(&lt;span class="kwrd"&gt;new&lt;/span&gt; BrokeredMessage(&lt;span class="str"&gt;&amp;quot;the content&amp;quot;&lt;/span&gt;));&lt;/pre&gt;
&lt;pre class="csharpcode"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;p&gt;Bueno, hasta aqu&amp;iacute; hemos llegado, creo que no me dejo nada, si es as&amp;iacute;, hac&amp;eacute;rmelo saber&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&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=207075" width="1" height="1"&gt;</content><author><name>Unai</name><uri>http://geeks.ms/members/Unai/default.aspx</uri></author><category term="Azure" scheme="http://geeks.ms/blogs/unai/archive/tags/Azure/default.aspx" /><category term=".NET 4.5" scheme="http://geeks.ms/blogs/unai/archive/tags/.NET+4.5/default.aspx" /><category term="ServiceBus" scheme="http://geeks.ms/blogs/unai/archive/tags/ServiceBus/default.aspx" /><category term="Topic" scheme="http://geeks.ms/blogs/unai/archive/tags/Topic/default.aspx" /><category term="Topics" scheme="http://geeks.ms/blogs/unai/archive/tags/Topics/default.aspx" /><category term="SqlFilter" scheme="http://geeks.ms/blogs/unai/archive/tags/SqlFilter/default.aspx" /></entry></feed>