Acheve.TestHost una pequeña ayuda en nuestros tests…

¿Usas Microsoft.AspNetCore.TestHost? Si la respuesta es si, seguramente (espero) lo que te contaré en este post te resulte útil. Por el contrario, si aún no conoces como y para que usar esta librería este post igual te ayuda a descubrir una nueva forma de testar tus HTPP API.

Para los que conozcáis TestServer, incluida dentro de Microsoft.AspNetCore.TestHost, sabréis que nos ofrece una manera de testar nuestros proyectos de HTTP API de una forma simple y muy poderosa. La idea subyacente es ofrecernos un cliente HttpClient que podremos utilizar para llamar a nuestro API sin necesidad de que este sea alojado en ningún servidor web.

Introducción

Para ilustrar este trabajo supongamos que partimos de la plantilla por defecto de ASP.NET Core para API HTTP.

Probar este controlador tal cual seria llamado por un cliente usando HTTP se vuelve insultantemente simple, tan solo tendremos que configurar nuestro TestServer y realizar las llamadas.

Del fragmento anterior hay un elemento importante que mencionar. Para crear nuestro TestServer hemos utilizado un IWebHost construido con una clase de Startup, la cual podría ser tranquilamente la misma que usamos en el proyecto para definir nuestro HTTP API aunque esto, para ilustrar nuestro post sirve, en realidad, suele ser mejor idea que el propio proyecto de test pueda definir su clase de startup.

Separar el alojamiento de tus proyectos de API HTTP siempre es una buena idea, y no solamente porque nos permitirá en nuestros proyecto de test quitarnos ruido que solo afecta al alojamiento.

Ahora que ya tenemos nuestro HttpClient ya podremos utilizarlo para hacer las llamadas a nuestro controlador.

En este post solamente nos estamos centrando en presentar de forma ligera TestServer. En futuras entradas veremos como es recomendable reutilizar para nuestros diferentes tests esta instancia y como podremos hacerlo con ClassFixtures / CollectionFixtures, en el caso de xunit, así como otros elementos habituales en este tipo de Tests, pero que se escapan aquí al propósito de esta entrada.

¿Porqué usar Acheve.TestHost?

¿Para que crear una librería si TestServer es ya tan potente? Pues bien, porque hay ciertos escenarios habituales que nos puede resultar  muy útil y nos librará de mucho código extra que hacer. A continuación presentaremos dos puntos  donde nos ofrecerá mejoras apreciables.

Seguridad

Por regla general, nuestras HTTP API están securizadas y la ejecución de las acciones requerirá que el usuario esté autorizado. De hecho, en nuestro ejemplo hemos puesto el atributo Authorization por el cual solamente los usuarios autenticados podrán ejecutar las acciones del controlador ValuesController. 

Nuestro host es quien elige como autenticamos estas llamadas, así por ejemplo en nuestro caso podríamos tener lo siguiente:

Si no hemos separado las clases de Startup de nuestro alojamiento de la clase Startup usada al construir TestServer, tendremos que lidiar en como conseguir estos tokens JWT para hacer nuestras llamadas con las clase HttpClient conseguida anteriormente. Sin embargo, si separamos ambos mundos, en nuestro alojamiento podríamos tener el código anterior y en nuestros tests podríamos cambiarlo para hacernos la vida mas sencilla. Achve.TestHost nos permite que podamos configurar nuestra clase Startup de test con un mecanismo propio de autenticación que nos simplificará mucho las pruebas en nuestros tests.

El método AddTestServerAuthentication nos habilita que las llamadas que hagamos con nuestro HttpClient estén autenticadas y además que en los tests podamos establecer fácilmente las claims que necesitemos para cada prueba.

Como podemos ver en el siguiente fragmento.

En pocas palabras diríamos que AddTestServerAuthentication nos habilita un nuevo middleware sobre el que después podremos establecer un conjunto de claims que serán establecidas en el contexto del usuario para cada una de las pruebas que hagamos. En concreto, el método WithIdentity es el que  nos permitirá establecer estas claims a utilizar para cada uno de nuestros tests.

Uris

Otro de los elementos con los que solemos lidiar en los tests con TestServer es el manejo de estas magic strings que representan las uris de las rutas a las que llamamos, como en el caso anterior api/values. Las alternativas habituales son varias, como crear una pequeña clase estática en la que definamos estas rutas y que sea fácilmente modificable y/o parametrizable como por ejemplo la siguiente.

El problema de esta aproximación, aunque también tiene sus ventajas está en el hecho de que precisamente son magic strings, que representan unas rutas que en el día a día pueden ser alteradas y que romperán muchos tests por el mero hecho de una cambio de nombre, un nuevo segmento de ruta etc. Acheve.TestHost nos ofrece un nuevo método extensor a TestServerCreateHttpApiRequest, que nos permitirá devolvernos un RequestBuilder configurado con una ruta construída con una expresión lambda de la llamada al controlador. En el siguiente fragmento podemos ver un sencillo ejemplo:

En estos momentos CreateHttpApiRequest solamente es capaz de entender rutas construídas con AttributeRouting y no mediante la definición de mapa de rutas y/o otras convenciones. En nuestro caso suponemos que AttributeRouting es la norma por defecto por ser la más flexible de todas.

Resúmen

Acheve.TestHost es un proyecto de Xabaril, en el que he tenido la suerte de participar junto con el impulsor y padre del mismo Hugo Biarge  @hbiarge.

https://github.com/Xabaril/Acheve.TestHost

https://github.com/Xabaril

Aunque hay mucho que profundizar, en esta entrada hemos visto que es TestServer y porqué Acheve.TestHost nos aporta ciertas funcionalidades que nos ayudarán en su uso.

Si quiere ver algún ejemplo de uso de Acheve.TestHost aquí.

Si quiere aprender más las posibilidades de CreateHttpApiRequest aquí.

Si quiere revisar la WiKi del proyecto aquí.

EF Core, de las convenciones a …?

Los que conocéis un poco EF 6.X seguro que sabéis que disponemos de un mecanismo para cambiar las convenciones por defecto a la hora de crear nuestros modelos. Este característica por lo general viene dada por la clase base DbConnection, sobre la cual podemos trabajar para personalizar las convenciones existentes o bien poder poner nuevas convenciones.

Un ejemplo de las posibilidades que esta clase base nos ofrece  se representan en el siguiente ejemplo de código, con una de las típicas convenciones que usamos cuando utilizamos EF 6.X.

 

Este modelo de convenciones es muy potente, aunque también tiene ciertas debilidades. El principal punto débil es que podemos configurar los tipos asignados pero no podemos decir a EF que un determinado tipo CLR o bien alguna determinada propiedad con alguna característica concreta se mapeará de una determinada manera en la base de datos. Seguro que ahora mismo está un poco confundido con el párrafo anterior, puesto que precisamente el ejemplo que acabamos de poner mapea las propiedades de tipo DateTime a DateTime2, entonces. Pues bien, esto funciona porque este tipo de datos datetime2 es conocido por EF, pero ¿que pasa si asignamos una propiedad a una columna de la cual no hay soporte, como por ejemplo XML? La respuesta es que esto no funcionará.

En EF Core 1.1, al contrario que en EF 6.X no tiene un API de primer nivel para el trabajo de convenciones.  Suponemos que algún futuro no muy lejano este API de primer nivel será creado, bien directamente por el equipo de trabajo de Entity Framework Core o bien por diferentes contribuciones de la comunidad. Sin embargo, si tiene abstracciones de base que nos darán mucha potencia y que veremos a continuación.

Si trabajamos con Sql Server, de manera idéntica tendremos este mecanismo con otros proveedores, tenemos una implementación de un RelationalTypeMapper que nos permitirá tener soporte para jugar con ciertos elementos convencionales o la modificación de como ciertas propiedades se mapean a nuestros elementos relacionales.

A continuación veremos un pequeño ejemplo en el que no solamente podemos configurar el tamaño por defecto de nuestras cadenas de caracteres sino también la longitud de los parámetros de las consultas.

 

Usar este nuevo mapper es relativamente sencillo, una de las cosas que tenemos en EF Core gracias a la utilización del sistema de dependencias por defecto está precisamente en la facilidad que tenemos para cambiar ciertos componentes por otros.

 

Hay otros muchos ejemplos de personalizaciones de esta clase, como por ejemplo la comentada anteriormente para la asignación de un tipo. Para no repetir código que ya está publicado y accesible mostraremos este ejemplo sacando el mismo del repositorio de Rowan Miller, uno de los PM de EF Core. El mismo puedes localizarlo aquí.

 

Del código anterior fíjese como podemos crear nuestro propio RelationalTypeMapping asignando en el tanto el tipo CLR como el tipo en el modelo  relacional subyacente. Es verdad que aún no tenemos las API de primer nivel, pero si tenemos las bases que permitirán su construcción o bien su uso directo, aunque no sea tan simple como debería.

 

Saludos

Unai

 

 

 

Shadow Properties – Otros ejemplos de uso

La verdad es que ya llevo unas cuantas charlas encima sobre EF Core 1.1 en las que trato de hacer un repaso por encima de las diferentes características nuevas o de como se han implementado las que ya conocíamos de EF 6.X.  Por suerte, cada vez tenemos más características que enseñar o más capacidades dentro de las características ya existentes que hacen que estas charlas no sean tan repetitivas.

Una de estas características nuevas que suele llamar la atención es el concepto de Shadow Properties, o propiedades que existirán en nuestro modelo relacional pero no las tendremos «visibles» en nuestro modelo de entidades. Para explicar estas propiedades, casi siempre suelo recurrir al típico ejemplo de propiedades de «fontanería» como por ejemplo los típicos conceptos de UpdatedBy, UpdatedOn. Por lo general este tipo de elementos los queremos como elementos básicos de funcionamiento pero no son importantes a la hora de modelar un problema, por eso nos referimos a ellos como elementos de «fontanería». Incluir estos conceptos resulta de lo más trivial como podemos ver a continuación:

Fíjese como en nuestro método de configuración del modelo, OnModelCreating, hemos dispuesto dos propiedades nuevas que no tenemos en nuestra entidad. Si hacemos una simple migración podríamos ver como efectivamente EF generará estos elementos en nuestro modelo relacional.

Por supuesto, y más en este caso que las hemos establecido como requeridas, tenemos que tener la posibilidad de establecer los valores de las mismas. Aunque hay diferentes alternativas y patrones de código para hacer esto relativamente sencillo lo más natural para demostrarlo sería recurrir a nuestro SaveChanges para hacer este trabajo.

Pues bien, aunque las Shadow Properties, se explican muy bien con estos conceptos de fontanería en realidad pueden tener más utilidades. Si hay algo que mucha gente pregunta con respecto a EF 6.X es  que ya no existe el concepto de ComplexTypes, que por lo general eran usados como ValueObjects en estilos orientados al dominio. Una forma simple para realizar ValueObjects dentro de EF Core podría ser precisamente con el uso de Shadow Properties. Para ello, veamos un ejemplo simple, que por supuesto tiene detalles que deberían ser revisados y/o mejorados.

Lo primero, será definir una pequeña clase base que nos permita marcar ciertos elementos como Value Objects y por lo tanto que sepa compararlos por su contenido. Para ello, podemos buscar por internet muchos ejemplos de implementaciones, aunque lo más básico ( no lo mejor ) podría ser algo como esto:

 

Una vez definida esta clase, podemos ya marcar nuestras entidades con la misma, por ejemplo una clase Address, que podríamos escribir como sigue:

¿Donde entre el uso de las Shadow Properties? Pues bien, una de las cosas que restringimos en nuestros Value Objects es el concepto de identidad en contenido. Es decir dos direcciones son iguales si su contenido es el mismo no si una clave de identidad es igual. Sin embargo EF nos obliga a que todas las entidades que mapeemos tengan un clave primaria/identidad. Las Shadow Properties nos permitirán sacar esta «restricción» fuera de nuestra clase Address y sin embargo que EF siga pudiendo funcionar.

En este caso el mapeo podría realizarse como sigue:

Como hemos visto, el concepto de Shadow Properties nos habilitan más escenarios que el simple de mecanismos de fontanería. En este caso hemos visto otro uso con respecto a la definición de Value Objects pero seguro que se le ocurren muchos más.

 

Saludos

Unai

 

 

 

 

 

 

 

 

 

 

Inyeccion de dependencias de .NET Core – #3 TransientAndDispose

Bien, esta será la última entrada por ahora de esta pequeña serie acerca de elementos con los que tenemos que tener cuidado cuando trabajemos con inyección de dependencias en .NET Core. En esta ocasión hablaremos sobre como funciona el ciclo de vida de nuestras dependencias y cuando se liberan los recursos de las mismas. Paria ello, vamos a empezar con la misma clase que hemos utilizado en esta serie, aunque ahora implementando IDisposable.

Bien, el sistema de DI de .NET Core nos asegura que la llamada a nuestro método Dispose se realizará  una vez que el proveedor finalize su ámbito. Por el código que estoy viendo últimamente, mucha gente tiende a registrar ciertos componentes usando directamente el IServiceProvider que tenemos en nuestro método de configuración, que generalmente vivirá todo el tiempo que viva nuestra aplicación web. Por lo tanto, todas estas dependencias transient seguirán vivas en nuestras aplicaciones, haciendo que la memoria crezca ad infinitum. Vamos a ilustrar este caso con un sencillo ejemplo.

Si cuando acaba la ejecución de este bucle revisáramos los miembros de nuestro provider veriamos un campo llamado _transientDisposables que mantienen una referencia a las 1000 dependencias que hemos resuelto del contenedor.

Por supuesto, esto no sucede en un ciclo normal de una aplicación ASP.NET Core puesto que las mismas se hacen en un scope que después es limpiado. Vendría ser algo como lo siguiente:

El corolario de esta entrada es entonces.. ten cuidado de que proveedor haces la resolución de tus dependencias, ten cuidado que el mismo se libere y todos tus objetos disposables puedan a su vez liberar recursos. Revisa _transientDisposables para obtener posible información de fugas de memoria.

 

Saludos

Unai

Inyeccion de dependencias de .NET Core – #2 Scoped2Singleton

Continuando con la serie empezada con los deadlock en la inyeccion de dependencias de .NET Core en esta ocasión vamos a hablar de otra práctica erronea como asignar una dependencia de tipo Scope a un componente registrado como Singleton. Empezaremos como siempre ilustrándolo con un pequeño ejemplo, dónde usaremos las mismas clases que en la entrada anterior:

Estas clases las registraremos como sigue:

Como observas, tenemos un componente SomeClass registrado como Singleton pero que depende de DependencyClass que está a su vez registrada como Scoped. El problema de este tipo de registros es que si no pensamos en realidad lo que estamos diciendo podemos pasar por alto que esta dependencia Scoped en realidad se convertirá en Singleton y, por lo tanto, podremos tener muchos problemas si no lo tenemos en consideración. Vamos a comprobarlo agregando el siguiente código después del registro de nuestras dependencias:

En el código anterior estamos simulando la creación de diferentes scopes, recuerde que en una aplicación ASP.NET Core cada request sería un nuevo Scope. Si observamos el HashCode de cada elemento Dependency nos será fácil ver que siempre tenemos el mismo valor.

Como hemos dicho al principio, esto no es un bug sino una consideración que tenemos que tener y ser consicente de ella, toda dependencia scope de un singleton se convierte en singleton.

En .NET Core 1.1 tenemos un pequeño flag para indicarle a nuestro sistema de DI que nos avise sobre estos posibles errores. Con el uso de este flag en la situación anterior se lanzaría una excepcion al intentar resolver SomeClass. En el siguiente fragmento podemos ver el codigo completo con el uso de este flag.

 

Saludos

Unai Zorrilla

Inyeccion de dependencias de .NET Core – #1 DeadLocks

A lo largo de esta serie de post que hoy empieza no quiero repetir muchos de los elementos que ya tenemos en la propia documentación oficial de .NET Core. El nuevo portal de documentación Microsoft Docs ya tiene mucha información sobre Quick Starts y los elementos más comunes, por lo que escribir sobre eso creo que no aporta demasiado. Incluso en el libro de introducción a .NET Core puedes ver muchos conceptos y prácticas más allá de estos «comienzos».  En esta serie de entradas me gustaría hablar de ciertos aspectos problemáticos o con los que podemos tener problemas si no los tenemos en consideración. Continúa leyendo Inyeccion de dependencias de .NET Core – #1 DeadLocks

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:

 

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:

 

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

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

 

 

 

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:

 

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.

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:

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.

 

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