MVC 6 – Tag Helper

A lo largo de las siguientes entradas, si el tiempo me lo permite, trataré de presentar algunas de las nuevas cosas que se están desarrollando en MVC 6 y que más pronto que tarde tendremos a nuestra disposición. En esta ocasión una de las novedades que mas curiosidad destacó entre los diferentes MVP que asistimos al MVP Summit celebrado en Noviembre y que corresponde a los nuevos Tag Helpers.

Seguro que para todos los que alguna vez habéis trabajado con MVC estáis habituados a los diferentes y varioados HTML Helpers que MVC 5 y anteriores ponen a nuestra disposición para nuestras vistas tal y como vemos en el siguiente código:

 

<h2>@ViewBag.Title.</h2>
<div class="row">
    <div class="col-md-8">
        <section id="loginForm">
            @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
            {
                @Html.AntiForgeryToken()
                <h4>Use a local account to log in.</h4>
                <hr />
                @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                <div class="form-group">
                    @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
                    <div class="col-md-10">
                        @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
                        @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
                    <div class="col-md-10">
                        @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
                        @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
                    </div>
                </div>

Aunque este código no llega a ser como nuestro ya muy viejo amigo para algunos ASP Spaguetti si tiene muchas trazas de esto y también padece de algunos de sus males. La dificultad que tiene este código para ser maquetado o trabajado por herramientas o personas que entienden HTML y no helpers. Con la idea de resolver estos problemas, y con las siempre idea de simplificar y mejorar las experiencias de los diferentes perfiles que pueden entrar en el desarrollo de una aplicación web, la nueva versión de MVC, MVC 6 incluirá la característica de Tag Helpers, que no son mas que pequeños parsers de atributos o contenido que nos permitirán tener un código mucho mas limpio y claro.

 

Como lo mejor es siempre ver un poco de código fíjese en las siguientes líneas:

 

<div class="form-group"> 
           @* no special-case for the "for" attribute; may eventually need to opt out on per-element basis here and in <form/> *@ 
           <label for="Name" class="control-label col-md-2" style="color:blue" /> 
           <div class="col-md-10"> 
               <input type="text" for="Name" style="color:blue" /> 
               <span validation-for="Name" style="color:blue" /> 
           </div> 
       </div> 
       <div class="form-group"> 
           <label for="DateOfBirth" class="control-label col-md-2" /> 
           <div class="col-md-10"> 
               @* will automatically infer type="date" (reused HTML attribute) and format="{0:d}" (optional bound attribute) *@ 
               <input for="DateOfBirth" /> 
               <span validation-for="DateOfBirth">When were you born?</span> 
           </div> 
       </div>

Aunque no entraremos en todos los atributos ni en todos los elementos soportados creo que con estas pocas líneas la idea se puede observar con claridad. Fíjese en el nuevo atributo for  usado en las etiquetas label o input iniciales. Observe como lo que indican no es mas que una expresión de acceso a nuestro modelo, en concreto a la propiedad Name, para el div inicial. Razor dispone ahora de una nueva directiva @addtaghelper, la cual permite descubrir el conjunto de clases que realizarán el parser de estos atributos y/o elementos para generar el mismo html que podríamos tener con nuestros HTML Helpers. En el caso de este ejemplo se usan los Tag Helpers por defecto como podemos ver en la definición de nuestro _ViewStart.cshtml

1 @addtaghelper "Microsoft.AspNet.Mvc.TagHelpers" 

¿Cómo funcionan estos parsers? El ensamblado anterior, Microsoft.AspNet.Mvc.TagHelpers, dispone de diferentes parsers,  en concreto para los elementos Anchor,Form,Input,Label,Option,Select,TextArea,Div , es posible que para la versión final algún nuevo elemento este soportado. Cada parser es una clase que hereda de TagHelper y tiene como responsabilidad procesar el elemento de entrada así como el conjunto de atributos de los que dispone para junto la información del modelo generar un output tal y como dicta esta clase base.

Para entender mejor como funcionan, en vez de ver el código de alguno de los existentes, veremos un Tag helper custom que permite parsear un elemento de tipo p y observar su contenido para  reemplazar en estos elementos todos las uri por su correspondiente elemento a.

 

[TagName("p")]     
[ContentBehavior(ContentBehavior.Modify)]     
public class AutoLinkerTagHelper : TagHelper     
{         
	public override void Process(TagHelperContext context, TagHelperOutput output)        
	{             
		// Find Urls in the content and replace them with their anchor tag equivalent.           
		  output.Content = Regex.Replace(                 
			output.Content,                 
			@"b(?:https?://|www.)(S+)b",                
			 "<strong><a target="_blank" href="http://$0">$0</a></strong>");         
	}    
} 

 

 

Por supuesto, al igual que hicimos antes, para que nuestras vistas usen este nuevo Tag Helper tendremos que indicárselo con la correspondiente directiva.

 

 

Bueno, espero que os guste esta entrada y esta novedad en MVC 6, espero poder seguir escribiendo un poco, que tenía el solar muy abandonado por otro tipo de contribuciones.

 

saludos

unai

EF 6.1.X: Configurando el tamaño de la cache

En la anterior entrada, la cual fue más bien un pequeño tipo hablamos de como funcionaba internamente la cache de consultas de ADO.NET Entity Framework, pues bien, en esta entrada vamos a ver como podemos configurar un poco los valores sobre los que esta cache trabaja. Esta opción solamente estará disponible desde EF 6.1.1 o EF 6.1.2, de la cual ya tenemos versiones preliminares, gracias a este pull request que  he terminado de hacer hace unos pocos días. En realidad, este pequeño PR lo único que hace es habilitar en la ya conocida configuración de ADO.NET Entity Framework la posiblidad de configurar los parámetros de máximo tamaño de cache y tiempo de paso para la expiración de objetos. Lo siguiente podría ser un ejemplo de configuración:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, 
Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"requirePermission="false" />
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
  </startup>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
    <queryCache size='1000' cleaningIntervalInSeconds='60'/>
  </entityFramework>
</configuration>

 

Si nos fijamos, el nuevo elemento de configuración, queryCache, nos permite establecer el tamaño máximo de entradas en cache, size,que por defecto es 1000, y que no sería recomendable tocar excepto por aquellas soluciones grandes, donde de verdad el número de entradas potenciales sea lo suficientemente alto como para que el incremento merezca la pena. Recuerde aquí que EF incluye dentro de esta cache los planes no solo de las operaciones de consulta sino también operaciones como inserciones, borrado y actualizaciones. El segundo de los parámetros, cleaningIntervalInSeconds, nos permite, por su lado especificar el tiempo de pasada para la revisión del estatus de entradas, valor especificado en segundos.

 

Espero que esta entrada aunque pequeñita le sirva para conocer un poco más por dentro como funciona ADO.NET EF

 

Saludos

Unai

EF: Cache de consultas

Nota: La información aquí presente aplica a Entity Framework 6, en versiones anteriores el comportamiento puede ser diferente.

 

Uno de los elementos que más desapercibido suele pasar de todos los elementos de Entity Framework es su sistema de cache de consultas. Cada vez que escribimos una consulta en LINQ, ESQL o realizamos una operación con nuestro contexto de trabajo, aplica también a operaciones de mantenimiento, Entity Framework utiliza una cache de la compilación de los diferentes Command Tree que son ejecutados. Aunque en un principio la compilación de estos CQT no debería llevar mas de unas pocas milésimas de segundo, en ocasiones, este tiempo puede ser muy alto, dependiendo de lo complejo de nuestras consultas, por lo que mantener una cache de estas estructuras es un aporte de rendimiento importante. A lo largo de este post trataremos de ver como funciona internamente este sistema de cache con el fin de que podamos aprender un poco más de Entity Framework.

 

QueryCacheManager

 

QueryCacheManager es la clase encargada de realizar nuestra cache de consultas, en realidad, las entradas pueden ser de otra naturaleza, pero para el post, lo simplificaremos así. Esta cache está limitada en su número de elementos, en concreto a 1000 entradas, por lo tanto, podríamos decir que a lo sumo una solución solamente podría tener para cada tipo de contexto de trabajo, fíjese que no digo instancia, 1000 entradas cacheadas. En realidad, este número difícilmente se va a llegar a conseguir puesto que nuestra clase de cache tiene un proceso de eviction que limpiará estos elementos. El desahucio de entradas se hace mediante un simple temporizador que se ejecuta cada minuto y comprueba si se deben de retirar entradas de cache, con una técnica muy simple y efectiva que veremos a continuación.

 

El desahucio

 

Para que Entity Framework libere entradas de nuestra cache el sistema tiene que superar un limite de entradas, que está establecido al 80 %, es decir, 800 entradas. Cada vez que nuestro temporizador de eviction salta, comprueba si el número de entradas es superior a 800. En caso afirmativo comienza la limpieza basándose en una propiedad, HitCount, que nos da una idea de las veces que esas entradas han sido utilizadas. Cada vez que se comprueba si una consulta está o no en la cache, esta incrementa el valor de la propiedad anterior, por lo tanto las consultas más utilizadas tienen unos valores de HitCount más altos. El proceso de eviction libera de la cache todas las entradas con un HitCount igual a 0, pero ¿como llegan las entradas a tener un hitcount igual a cero? La respuesta se debe a que a mayores de eliminar las entradas con hitcount cero el proceso de eviction se dedica en cada pasada a envejecer las entradas, con un simple right-shift con factores 1,1,2,4,8,16. Este envejecimiento hace que siempre que estemos en entornos de alto uso de cache, más de 800 entradas, los elementos menos utilizados irán desapareciendo.

cacheKeys[i].HitCount = cacheKeys[i].HitCount >> _agingFactor[agingIndex];
Posibles Mejoras

Aunque el número de entradas, 1000 elementos, no es algo seleccionado al azar, los diferentes tipos de soluciones con las que nos podemos enfrentar hace que este número no siempre pueda ser un número justo, modificarlo con el fin de aumentarlo podría introducir mejoras en el comportamiento de una solución en producción. Por desgracia, por ahora, este número es fijo y no disponemos de ninguna forma para parametrizarlo  y observar resultados. Lo mismo, en realidad, podríamos decir del valor de carga máxima de la cache, el 80 % como comentábamos, o del tiempo de pasada del proceso de eviction.

 

Espero que os ayude y se entienda un poco mejor como funcionan ciertas partes de EF.

 

 

Saludos

Unai

 

EF 6.1 [Preview] : Carga automática de convenciones

Otra pequeñita entrada para mostrar otro método de utilidad que tendremos en EF 6.1, versión que pronto estará con nosotros. En este caso nos ocuparemos de la carga de convenciones, que como sabéis hasta ahora solamente se podía realizar mediante los métodos Add, AddAfter y AddBefore. Puesto que puede ser habitual la creación de un número significante de convenciones el incluir estas llamadas en nuestro OnModelCreating puede resultar en “código repetitivo”. Para simplificar esta tarea, ConventionsConfiguration dispone ahora de un método AddFromAssembly que nos permite cargar de forma automática todas las convenciones que tengamos en un determinado ensamblado. Concretamente, el método creado es:

        /// <summary>
        /// Discover all conventions in the given assembly and add them for the <see cref="DbModelBuilder" />.
        /// <remarks>
        /// This method add all conventions ordered by type name.The order in which conventions are added 
        /// can have an impact on how they behave because it governs the order in which they are run.
        /// </remarks>
        /// </summary>
        /// <param name="assembly">The assembly containing conventions to be added.</param>
        public void AddFromAssembly(Assembly assembly)
        {
            Check.NotNull(assembly, "assembly");

            var types = assembly.GetAccessibleTypes()
                .OrderBy(type => type.Name);

            new ConventionsTypeFinder().AddConventions(types, convention => Add(convention));
        }

Es importante notar que como la ejecución de las convenciones se hace en orden de registro la carga automática de convenciones de un ensamblado impone un orden implícito basado en el nombre del tipo que representa la convención como se puede observar con el uso del método extensor OrderBy.

 

La selección de convenciones válidas se hace mediante el uso de un pequeño filtro, tal cual el siguiente, que nos permite registrar convenciones de modelo, almacén y de configuración.

 

        public virtual bool IsConvention(Type conventionType)
        {
            return IsConfigurationConvention(conventionType)
                ||
                IsConceptualModelConvention(conventionType)
                ||
                IsConceptualToStoreMappingConvention(conventionType)
                ||
                IsStoreModelConvention(conventionType);
        }

El pull request asociado a esta característica en la que podéis ver todos los cambios necesarios es este. Espero que os resulte interesante y sobre todo útil, puesto que para esto se ha hecho!!

 

saludos

Unai

 

 

 

 

EF6 Contrib: Operaciones de migración

 

Otra de las características que tenemos dentro de EF6 Contrib es la de agregar operaciones personalizadas de migración, por ahora ya hay unas cuantas que seguro serán de utilidad para algunas de vosotros y aquellas que  no están seguro que pronto estarán o bien os animo a escribirlas. La ultima ha venido de un pull request de Quique ( @quiu3 ) en el que ha incluido la posibilidad de agregar computed columns, os animo a ver el pull request para ver lo sencillo que es incluir nuevas migraciones.

    public class AddComputedColumnOperation : MigrationOperation
    {
        public string TableName { get; private set; }

        public string ColumnName { get; private set; }       
        public AddComputedColumnOperation(string tableName, string columnName, object anonymousArguments)
            : base(anonymousArguments)
        {
            Check.NotEmpty(tableName, "tableName");
            Check.NotEmpty(columnName, "columnName");            

            this.TableName = tableName;
            this.ColumnName = columnName;            
        }

        public override bool IsDestructiveChange
        {
            get { return false; }
        }

        public override MigrationOperation Inverse
        {
            get
            {
                return new DropComputedColumnOperation(TableName,ColumnName);
            }
        }
    }

Para hacer uso de estos elementos solamente tenemos que cambiar el generador a utilizar, por defecto en EF 6 Contrib solamente tenemos un generador para Sql Server. Establecer este generador es tan sencillo como se ve a continuación:

    internal sealed class Configuration : DbMigrationsConfiguration<ConsoleApplication1.CRMContext> 
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
            SetSqlGenerator("System.Data.SqlClient", new ExtendedSqlServerMigrationSqlGenerator());
        }

        protected override void Seed(ConsoleApplication1.CRMContext context)
        {
          
        }
    }

Por supuesto también se podría hacer utilizando un DbConfiguration, cualquier opción sería válida, a elegir. Hasta aquí esta pequeña entrada, espero que os sea de utilidad….

 

Saludos

Unai

 

Preview EF 6.1 Features: Transaction Handler

Una de las principales novedades en EF 6 y de la que hablamos aquí, en este mismo blog, unas cuantas veces hace referencia a la característica de “connection resiliency” gracias a la cual tenemos una forma simple de tener aplicaciones capaces de manejar los errores temporales que un cluster de sql server podría producir, sin tener para ello que escribir ningún tipo de código de reintentos. Sin embargo, había algún escenario que esta nueva característica no cubría como el escenario conocido por “Idempotent Issue”  producido cuando después de una ejecución de un IUD( Insert, Update, Delete ) obtenemos un connection failure  ya que no tenemos una forma segura de saber si en realidad esta escritura se ha realizado en la base de datos. La única forma de poder hacer algo es llevar un seguimiento del comando para garantizar la “idempotencia”. Por desgracia Sql Server no ofrece/dispone  de ningún mecanismo por lo que la tarea de realizar este seguimiento nos la tenemos que hacer nosotros. Aquí es dónde entra el trabajo del equipo de Entity Framwork, puesto que ha realizado esta tarea por nosotros, gracias a la cual cuando tenemos un connection failure en un IUD el sabrá si realizar un reintento del comando o bien si lo que ha pasado es que la notificación del commit no ha llegado correctamente.

¿Como activamos esta característica?

Nota: Durante la escritura de este post se ha usado la versión 6.1.0-alpha1-30121

 

Para activarla como hacemos desde la llegada de nuestra configuración en código es usar nuestras clases DbConfiguration para registrar este nuevo servicio, como podéis ver a continuación:

 

   public class Configuration
        : DbConfiguration
    {
        public Configuration()
        {
            SetTransactionHandler("System.Data.SqlClient", () => new CommitFailureHandler());
            SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy());
        }
    }

¿Cómo se hace el seguimiento?

Si nos fijamos un poco, cuando vemos la base de datos creada o usada por un contexto que tiene habilitada esta característica veremos una nueva tabla que nada tiene que ver con nuestro modelo, y al igual que la tabla de migraciones, empieza con un “_” para identificarla como una tabla de “fontanería”. Esta tabla es _TransactionHistory y contiene este seguimiento de comandos del que hablamos. Por supuesto, al igual que podemos customizar la tabla de migraciones también podremos hacer lo mismo con esta, fijaros que tenemos un TransactionContext del que podemos heredar.

 

Untitled

 

En esta tabla, irán apareciendo y desapareciendo entradas que permitirán identificar a los comandos que se están ejecutando en un determinado contexto, una vez que este contexto se destruye, sus entradas correspondientes desaparecerán.  Este log de transacciones también contiene otro elemento que hace que se limpie y consiste en un límite hardcoded establecido en CommitFailureHandler cuyo valor es 20, lo que quiere decir que cuando aparezcan 20 entradas de log para un mismo contexto estas entradas de log se limpiarán.

 

         /// <summary>
        /// Gets the number of transactions to be executed on the context before the transaction log will be cleaned.
        /// The default value is 20.
        /// </summary>
        protected virtual int PruningLimit
        {
            get { return 20; }
        }

 

Internals

 

Creo que más o menos ha quedado clara la problemática y como necesitamos un sistema de tracking de nuestras transacciones para posteriormente poder actuar ante los problemas de idempotencia. ¿ Pero como ha sido posible esto internamente? Ya en EF 6 se introdujeron unos pocos interceptores para mediar en la ejecución de consultas y comandos para la base de datos, pero estos no eran suficientes puesto que para este nivel necesitábamos más interceptores a nivel de transacción y conexión, por ello, ahora mismo disponemos de los siguientes elementos nuevos.

  • IDbTransactionInterceptor: Interceptor que nos permite interceptar diferentes operaciones relativas a las transacciones y a la solicitud de conexiones, etc.
  • IDbConnectionInterceptor: Interceptor que nos permite saber  e interceptar diferentes elementos relativos a las conexiones, cuando se abren, se cierran, empiezan una transacción etc.

Gracias a estos nuevos interceptores, que podrían ser registrados igualmente en nuestro DbInterception, se puede realizar esta característica. Seguro que otras muchas cosas saldrán gracias a estos nuevos interceptores y seguro que a muchos de vosotros ya se os han ocurrido ideas.

 

saludos

unai

EF 6 Contrib: Performance Interceptors

Como ya hemos dicho, tantas y tantas veces, desde este mismo blog, sin duda, una de las mejores cosas con la llegada de EF6 es la cantidad de puntos de extensibilidad de los que disponemos y que nos permiten jugar con ciertas cosas bastante interesantes. La nueva característica para subscribir código antes y después de cada ejecución, que Entity Framework hace contra la base de datos, es una de estas sobre la que siempre estamos pensando cosas que podemos hacer, en realidad hay muchas cosas que a la mayoría se nos ocurren como por ejemplo auditoria, cache, re-escritura de comandos etc etc etc. En el proyecto de EF 6 Contrib se hace uso de esta característica para darnos cierta información del rendimiento de nuestras aplicaciones haciendo uso de estos interceptores, gracias a los cuales se puede examinar la consulta y/o el plan de ejecución contra el motor de base de datos, por ahora solamente para Sql Server.

Para hacer uso de estos analizadores lo primero será incluir ef6.contrib desde nuestra consola de NuGet

PM> install-package ef6.contrib
Attempting to resolve dependency 'EntityFramework (≥ 6.0.2)'.
Attempting to resolve dependency 'Common.Logging (≥ 2.1.2)'.
Installing 'Common.Logging 2.1.2'.
Successfully installed 'Common.Logging 2.1.2'.
Installing 'EF6.Contrib 1.0.3'.

Una vez instalado, este pone a nuestra disposición el interceptor PerformanceInterceptor, que podemos registrar en nuestro archivo de configuración como sigue:

 

    public class Configuration
        : DbConfiguration
    {
        public Configuration()
        {
            this.AddInterceptor(new PerformanceInterceptor(msg =>
            {
                Console.WriteLine("{0}-{1}", msg.Message, msg.Command);
            }));
        }
    }

El delegado Action<PerformanceReport> nos permite decidir dónde queremos llevar la información generada, a un fichero, base de datos o como en nuestro caso, simplemente a la consola de salida. Amén de este parámetro en el constructor, esta clase nos permite incluir el conjunto de analizadores a usar. PerformanceInterceptor se basa en un conjunto de analizadores, IPerformanceAnalyzer, que podemos ampliar con los nuestros, para realizar el trabajo de revisión de las consultas. Si, como en este caso, no se hace uso de este parámetro el interceptor utilizará solamente el contenedor de dependencias para resolver los analizadores que se desean usar. Con el fin de ver un ejemplo nos crearemos un pequeño resolver que se encargará de registrar un analizador.

 

    class DummyResolver
            : IDbDependencyResolver
    {
        public object GetService(Type type, object key)
        {
            return null;
        }

        public IEnumerable<object> GetServices(Type type, object key)
        {
            if (typeof(IPerformanceAnalyzer).IsAssignableFrom(type))
            {
                return new List<IPerformanceAnalyzer>()
                {
                    new ExecutionTimePerformanceAnalyzer(TimeSpan.FromSeconds(3)),
                };
            }

            return Enumerable.Empty<object>();
        }
    }

Como podéis ver en en este  código, se está registrando en este caso, un único analizador llamada ExecutionTimePerformanceAnalyzer, que como os imaginaréis, se encarga de analizar los tiempos de ejecución de cada consulta y para aquellas cuyo tiempo sea superior a 3 segundos enviará un “informe”.  Crearse nuevos analizadores es sencillo, solamente tenemos que implementar la interfaz IPerformanceAnalyzer que es tan sencilla como sigue, por lo que os animo a crear y contribuir nuevos analizadores.

 

    public interface IPerformanceAnalyzer
    {
        PerformanceCommandReport Analyze(DbCommand command, TimeSpan executionTime);
    }

Si utilizas SqlServer, EF6 Contrib dispone de otro paquete, EF6.Contrib.SqlServerPerformanceAnalyzers, que contiene analizadores especiales para Sql Server, podríamos por ejemplo ampliar nuestro registro de analizadores como sigue, los nombres son representativos de sus funciones.

 

    class DummyResolver
            : IDbDependencyResolver
    {
        public object GetService(Type type, object key)
        {
            return null;
        }

        public IEnumerable<object> GetServices(Type type, object key)
        {
            if (typeof(IPerformanceAnalyzer).IsAssignableFrom(type))
            {
                return new List<IPerformanceAnalyzer>()
                {
                    new ExecutionTimePerformanceAnalyzer(TimeSpan.FromSeconds(3)),
                    new UnparametrizedWhereClausesPerformanceAnalyzer(),
                    new TopSlowQueriesPerformanceAnalyzer(topQueries:10)
                };
            }

            return Enumerable.Empty<object>();
        }

 

Estos son solo algunos ejemplos de analizadores, hay otros como la revisión de consultas de paginación etc etc etc. pero hay varios puntos de mejora como comentamos que se podrían utilizar, XEvents y el análisis de planes de ejecución, para ello EF6 Contrib está comenzando el trabajo con la clase SqlExecutionPlanPerformanceAnalyzer que servirá de base para todos los analizadores que deseen inspeccionar el plan de ejecución de un determinado comando:

 

    public abstract class SqlExecutionPlanPerformanceAnalyzer
        : IPerformanceAnalyzer
    {
        ///<inheritdoc/>
        public PerformanceCommandReport Analyze(DbCommand command, TimeSpan executionTime)
        {
            var plan = GetQueryPlan(command.Connection.ConnectionString, command.CommandText);

            if (plan != null)
            {
                return EvaluatePlan(plan);
            }

            return null;
        }

        /// <summary>
        /// Get the <see cref="PerformanceCommandReport"/> from Sql Plan
        /// </summary>
        /// <param name="sqlPlan">The sql plan to evaluate</param>
        /// <returns>The performance command report or null if no issues is present in plan</returns>
        public abstract PerformanceCommandReport EvaluatePlan(XDocument sqlPlan);

        /// <summary>
        /// Get query plan from specified command using database information
        /// </summary>
        /// <param name="connectionstring">The connection string to use</param>
        /// <param name="commandText">The command text</param>
        /// <returns>The query plan in XML format or null</returns>
        public virtual XDocument GetQueryPlan(string connectionstring, string commandText)
        {
            using (var connection = new SqlConnection(connectionstring))
            {
                var queryPlanCommand = connection.CreateCommand();

                queryPlanCommand.CommandText = "SELECT qp"
                    + " FROM sys.dm_exec_cached_plans as cp CROSS APPLY sys.dm_exec_query_plan(plan_handle) as qp"
                    + " CROSS APPLY sys.dm_exec_sql_text(plan_handle) as qt WHERE qt=@qt";

                queryPlanCommand.Parameters.AddWithValue("@qt", commandText);

                var plan = queryPlanCommand.ExecuteScalar();

                if (plan != DBNull.Value)
                {
                    return XDocument.Parse(plan.ToString());
                }

                return null;
            }
        }
    }

 

Si os ha gustado, me gustaría animaros a contribuir de las múltiples formas que se puede hacer…

 

Saludos

Unai

Evento: ¿Quieres conocer todo sobre VS 2013, ALM y desarrollo de aplicaciones web?

Los dias 3-5 de Diciembre tendré el placer de participar con mis compañeros de Plain Concepts en el evento ALM, arquitectura y desarrollo de aplicaciones web con VS 2013, evento en el que trataremos de enseñaros muchas de las novedades, sino todas, de los stack Microsoft en ALM, Acceso a Datos y desarrollo de aplicaciones Web. Usaremos para ello el conjunto de demos de My Company, demos desarrolladas por Plain Concepts para el lanzamiento de VS 2013 sobre las que discutiremos diferentes opciones tecnológicas.

 

Aquí os pego la  agenda y aquí podéis registraros en Barcelona y Madrid.. Por cierto, para el evento de Madrid contaremos con el inestimable de David Carmona, si, ese mismo con el que tantos y tantos hemos aprendido sobre el mundo del desarrollo de Software, no te lo pierdas!!!!!

 

// Capa de acceso a datos; Entity Framework 6

Durante esta primera sesión intentaremos realizar un resumen de todas aquellas novedades que acompañan a la versión de Entity Framework 6, cuya versión reléase ha sido incluida dentro de Visual Studio 2013.

Operaciones de migraciones personalizadas.
Convenciones personalizadas.
Mapeo a procedimientos almacenados.
Operaciones asíncronas.
Interceptores.
y mucho más…

// Capa de servicios; OWIN, Web API 2, OData

Hablando de la capa de servicios nos podemos encontrar con diferentes tecnologías que podemos emplear, cuyo uso dependerá de muchos factores que hay que ser capaz de analizar al iniciar la aplicación.

OWIN-Katana.
ASP.NET WebAPI 2; o Attribute Routing, CORS, OWIN…
ASP.NET Web API OData.
SignalR.

// Capa de presentación; HTML, JavaScript, CSS

Esta tercera sesión está centrada en todas aquellas novedades, trucos o herramientas que nos ayudarán a trabajar con HTML, JavaScript o CSS. Algunas de las cosas que trataremos son:

ASP.NET Scaffolding
BootStrap
Angular.js
Browser Link
Web Essentials

// Gestión del ciclo de vida de aplicaciones web

Tan importante es conocer la tecnología como ser capaces de desarrollar software de la manera más eficiente posible. Durante esta sesión veremos las principales novedades de Visual Studio 2013 para la gestión de ciclo de vida de aplicaciones.

Visual Studio Online. 
Monaco
InRelease
App Insights

// Despliegue de aplicaciones web en Windows Azure

La última sesión del día estará centrada en el despliegue de aplicaciones en Windows Azure y cómo es posible trabajar sencilla con Windows Azure desde Visual Studio.

Montar un escenario de desarrollo con Windows Azure.
Depuración remota.
Novedades del Sdk 2.2
Despliegue de aplicaciones a Azure Web Sites

 

Unai

EF 6 Contrib.. empezamos!!

Bueno, ya hace unos cuantos días que se liberó EF 6.0.1 en la que tuve el inmenso placer de participar con unos cuantos pull request con features y fixes. Puesto que todo no puede entrar dentro de la rama del producto, por diversas y variadas razones que creo que no vienen al caso comentar aquí, amén de seguir colaborando con otros nuevos pull request he decidido crear un pequeño proyecto de contribuciones dónde poder incluir aquellas otras cosas que como desarrollador me gustaría tener.

EF6 Contrib Site

Este es el sitio de Codeplex dónde está el proyecto de contribuciones y donde además del código estará la documentacion, backlog, issues etc.. Por supuesto, estás invitado a colaborar, de la forma que consideres adecuada, señalando bugs, creando nuevo código de contribución etc. En el caso de querer contribuir con código, las reglas y normas son las mismas que el equipo de EF tiene puesto para contribuir en la rama principal, podéis revisar las mismas en http://entityframework.codeplex.com

Try it

Actualmente ya hay una versión publicada en NuGet, para acceder a ella solamente tenemos que instalar el paquete ef6contrib como sigue:

 

install-package ef6contrib

 

 

Saludos

Unai

[Eventos] Plain Concepts Architecture Day

El dia 29 de Octubre tendré el placer junto a mis compañeros de Plain Concepts  de participar en un nuevo Architecture Day,  muy dedicado a puntos fundamentales hoy en día como son los siguientes:

 

  • Estado del arte en tecnologías y estilos arquitectónicos en tecnologías Microsoft.
  • El stack de desarrollo de aplicaciones web.
  • Arquitecturas en la nube.
  • Gestión de la identidad.

 

Como siempre, en este tipo de eventos, intentaremos que sea lo más ágil posible, así como involucrar a todos los asistentes para establecer un debate y así poder resolver todas las dudas o poner de manifiesto diferentes pensamientos.

 

Aquí tenéis el enlace del evento dónde podéis ver más información y registraros en el mismo..

 

http://www.plainconcepts.com/ArchitectureDay/

 

Saludos

unai