Visualizando la versión de la aplicación en proyectos ASP.NET MVC

Un recurso muy útil con lo que contamos los programadores .NET es la clase AssemblyInfo que se encuentra ubicada generalmente en el directorio-archivo “Properties\AssemblyInfo.cs“. Entre otros usos, nos permite definir y obtener – de manera centralizada – el número de versión de una aplicación.

MSDN la define de la siguiente manera:

Proporciona las propiedades para obtener información sobre la aplicación, como el número de versión, la descripción, los ensamblados cargados, etc.

Ahora bien, la forma más simple de definir la versión actual de la aplicación es actualizando el siguiente atributo de AssemblyInfo:

Atributo AssemblyVersion

Atributo AssemblyVersion

Para mostrar este dato actualizado en nuestro sitio, solo debemos agregar a la vista la siguiente línea (un buen lugar es el pie de página):

Agregando la versión a la vista.

Agregando la versión a la vista.

Tengan en cuenta que la versión que queremos visualizar en este caso corresponde el ensamblado de la aplicación web, que en este ejemplo se encontraría bajo el namespace Web.WebApiAplication.

Resultado:

Visualizando la versión de la app en el pie.

Visualizando la versión de la app en el pie.

Espero que les sea de utilidad!

Anuncios

ASP.NET MVC – Template Helpers

Generalmente se nos presentan situaciones en donde nuestro modelo posee varias entidades que comparten una misma propiedad. Supongamos que estamos trabajando un proyecto web ASP.NET MVC, y debemos armar el formulario para la administración de dichas entidades (operaciones CRUD). Nada mejor para estos casos que generar una vista parcial por cada una de estas propiedades “compartidas”, que entre otros beneficios nos permitiría reutilizar código, cierto?… si embargo, esto puede generar ciertos dolores de cabeza que a priori no teníamos en mente.

Para empezar con el ejemplo, veamos las entidades que conformaran el modelo, la primera de ellas representa un cliente – ClienteModel -, y la segunda una dirección – DireccionModel – que en nuestro caso será el atributo compartido:

Clases del Modelo

Clases del Modelo

Como podemos ver, el modelo DireccionModel se podría utilizar en muchas otras entidades, como por ejemplo, modelos para representar  un usuario, un proveedor, una empresa, etc.

Basándonos en el modelo previamente definido, la forma mas simple para generar el formulario de carga o edición sería crear la siguiente vista de tipado fuerte (strongly-typed view):

Formulario de cliente

Formulario de cliente

El formulario obtenido sería el siguiente:

Formulario de edición

Formulario de edición

Si completamos los datos del formulario y hacemos el submit del mismo, podremos validar que el binding del modelo se hizo de correctamente:

Enviando los datos del formulario

Enviando los datos del formulario

Ahora bien, como comentamos al inicio, podríamos generar una vista parcial donde poner los datos de la dirección solamente y poder reutilizarla en otros formularios. Quedaría algo como lo siguiente:

Vista parcial con los datos de la dirección

Vista parcial con los datos de la dirección

Finalmente modificamos la vista Edit agregando la referencia a la vista parcial:

Referenciando a la vista parcial

Referenciando a la vista parcial

Ejecutamos y vemos que el formulario obtenido es el “mismo”, aunque esto solo es en el aspecto “visual“. Si analizamos el HTML resultante, veremos que los inputs generados para la carga de la calle y el número tienen el atributo name diferente al que se generaba en el primer caso. Esto sucede porque los strongly-type helpers para construir los elementos del formulario utilizan expresiones lanbdas que se basan en el modelo proporcionado.

Comparemos los elementos HTML construidos utilizando vistas parciales y sin utilizarlas:

Html generados

Html generados

Los nombres generados son diferentes, porque los modelos utilizados en el strongly-type helper son diferentes, en el caso de las vistas parciales el modelo es DireccionModel  y en el otro caso modelo es ClienteModel.

Como ya sabemos, el atributo NAME es utilizado por ASP.NET MVC para bindear los datos del formulario con el modelo que espera el método de acción del controlador. En la vista parcial no estamos respetando el nombre de la propiedad de la clase Cliente a los cuales pertenecen estos campos y por consiguiente los datos no son enviados al método de acción del controlador. 😦

Modelo obtenido utilizando vistas parciales

Modelo obtenido utilizando vistas parciales

Entonces… de que manera puedo reutilizar código, si no podemos utilizar las vistas parciales? (aclaración, no es que no podamos utilizar vistas parciales, existen otras formas de solucionar este problema, sin embargo no son el propósito de este post). Una solución es utilizar Template Helpers que, a diferencia de las vistas parciales, reciben información del contexto padre.

Para crear nuestro template helper, lo primero que debemos hacer es generar una nueva carpeta llamada “EditorTemplates” dentro de “Views/Shared” (esta ubicación nos permitirá utilizar el template desde diferentes vistas) y mover ahí la vista parcial que habiamos creado, pero que ahora llamaremos con el mismo nombre del modelo DireccionModel.cshtml:

Moviendo nuestra vista parcial

Moviendo nuestra vista parcial

Bien, ahora solo resta modificar la vista Edit que invocara por medio del strongly-type helper Html.EditorFor a las vista del modelo correspondiente:

Utlizando Template Helper

Utlizando Template Helper

Ejecutamos y veremos que los datos del formulario si son enviados al método de acción del controlador:

Enviando los datos del formulario

Enviando los datos del formulario

En este caso, el modelo que recibe el template no es DireccionModel (o sí) sino la entidad que lo contiene, por lo que el elemento del formulario se generará con el name correcto.

Existen muchisimas mas características, como por ejemplo el helper Html.Display, que tiene un comportamiento similar al helper Html.Editor solo que es utilizado para visualizar los valores de una entidad. Les recomiendo leer este excelente post de Brad Wilson para más información.

ASP.NET MVC : Entendiendo ResponseRedirect

Quienes desarrollamos en algún momento en ASP.NET Webform no necesitábamos tener conocimientos web de bajo nivel ya que los mismos eran abstraídos por el mismo framework. Esto se debía a que ASP.NET, en ese entonces, había sido pensado para atraer a los desarrolladores de aplicaciones de escritorio que se resistían pasar al desarrollo de aplicaciones web. Por lo tanto, la estrategia de MS fue seguir con esa misma filosofía.

En el momento en que uno hace el pase a ASP.NET MVC – cosa que recomiendo a todo desarrollador web de .NET 🙂 – tiene la necesidad de conocer más en profundidad estas cuestiones (HTTP, HTML, CSS…), ya que es parte de la naturaleza del framework y facilita enormemente el desarrollo sobre el mismo.

Como mencione anteriormente, una de las cuestiones web son los protocolos y  hace un tiempo atrás participé de la excelente VAN que presento Leonardo Micheloni sobre HTTP (llamada “HTTP y las ruedas de la web“) donde uno de los tema que toco fueron los distintos códigos de estado que provee este protocolo.

Para quienes no conozcan demasiado de este tema cuando uno hace una petición por medio de una URL se inicia una transacción desde el cliente que termina con una respuesta del servidor que generalmente viene compuesta por el recurso solicitado (sea un HTML, XML…). Uno de los datos que viajan en el encabezado de la respuesta es el código de estado (de los cuales los más conocidos son 200 OK o 404 NOT FOUND).

Estos códigos de estado se encuentran agrupados según su función y uno de esos grupos corresponden a las Redirecciones : 3xx.

Todo esto me hizo pensar en como funcionaba realmente el método RedirectToAction que nos provee la clase Controller de ASP.NET MVC.  Y mis sospecha – no demasiadas brillantes – eran ciertas, la solicitud a una vista que utiliza RedirectToAction retorna HTTP Code Status 302.

Antes de continuar, veamos un poco más en profundidad, de que se trata el código 302 viendo una definición de Wikipedia:

Este es el código de redirección más popular, pero también un ejemplo de las prácticas de la industria contradiciendo el estándar. La especificación HTTP/1.0 (RFC 1945) requería que el cliente realizara una redirección temporal (la frase descriptiva original fue “Moved Temporarily”), pero los navegadores populares lo implementaron como 303 See Other. Por tanto, HTTP/1.1 añadió códigos de estado 303 y 307 para eliminar la ambigüedad entre ambos comportamientos. Sin embargo, la mayoría de aplicaciones web y bibliotecas de desarrollo aún utilizan el código de respuesta 302 como si fuera el 303.

Luego de esta larga introducción, vayamos al grano y definamos dos vistas, la primera la llamaremos Index y la segunda Final. Lo que hará la primer vista será simplemente redireccionar a la segunda:

1: public class HomeController : Controller
2: {
3:     public ActionResult Index()
4:     {
5:         return RedirectToAction("Final");
6:     }
7:
8:     public ActionResult Final()
9:     {
10:         return View();
11:     }
12: }

Ejecutemos y analicemos la respuesta del servidor:

Respuesta HTTP

Respuesta HTTP

Vemos que la petición GET a la URL “http://localhost…/Index” retorna el código 302 Found, y seguido se hace una nueva petición a “http://localhost…/Final” que finalmente es devuelta exitosamente (retornando el código 2oo OK).

Para saber donde tiene que hacer la redirección, uno de los datos que viajan en el encabezado de la respuesta es Location el cual contiene dicha información:

Encabezado de la respuesta HTTP

Encabezado de la respuesta HTTP

Es importante que entendamos como funcionan estas cuestiones, que si bien son simples, uno muchas veces las desconoce pensando que todo es resuelto “magicamente” por el framework.

Espero que les haya sido de utilidad.

Evitando JavaScript Injection en ASP.NET MVC

Hace unos días revisando un informe de sobre seguridad web, un ítem me llamo la atención porque es una de esas cosas que a uno se olvida de tenerlas en cuenta al momento de desarrollar un sitio. El mismo hablaba sobre los ataques de inyección de JavaScript.

Este tipo de ataque se denomina Cross-site scripting o de manera abreviada XSS:

XSS, del inglés Cross-site scripting es un tipo de inseguridad informática o agujero de seguridad basado en la explotación de vulnerabilidades del sistema de validación de HTML incrustado.

La idea de este post es ver de que forma podemos prevenir este tipo de ataques en aplicaciones ASP.NET MVC partiendo desde dos ópticas diferentes.

Antes que nada vamos a ver un poco mas en profundidad de que se trata JavaScript Injection y como se llevan a cabo este tipo de ataques. Para darnos una mejor idea supongamos que desde nuestro sitio web tenemos una caja de texto en la cual un usuario carga contenido y luego el mismo se visualiza en la página. Esta situación podría estar dejando abierta la posibilidad de un ataque de inyección de Javascript. Cómo es posible esto?… vamos a verlo con un simple ejemplo.

Lo primero sera crear una aplicación web tipo Twitter pero muy simplificada, en la cual vamos a permitir este tipo de ataques. Vamos a crear un controlador al cual vamos a llamar TweetController y a definir la siguiente entidad que formará parte del modelo de nuestra app y que se llamaremos Tweet:

1: public class Tweet
2: {
3:     public int TweetID { get ; set ; }
4:
5:    public string Usuario { get ; set ; }
6:
7:     public string Mensaje { get ; set ; }
8: }

Al momento de codificar la vista, la visualización de los items estará armada de la forma estandar:

1: <div class="tweetSection">
2:  <% foreach (var item in Model) {  %> 
3:     <span class="tweetUser">  <%= item.Usuario %></span>
4:    <br />
5:      <%= item.Mensaje  %> 
6:     <br />
7:     <br />
8:  <%   }  %>
9: </div>

Básicamente nuestra app esta conformada por un formulario donde se ingresa un nombre de usuario y un mensaje, el cual al momento de hacer el submit se grabara en una DB (para esto utilizaremos la librería EF) y luego se visualizara en la misma pantalla:

Interfaz de la aplicación

Interfaz de la aplicación

De la forma en que “dibujamos” el formulario, hemos dejado desprotegido nuestro sitio a los ataques de este tipo. Imaginemos que el usuario escribe un simple script de Javascript en nuestra caja de texto, por ejemplo, la ejecución de un mensaje de alerta informándonos que hemos sido atacados:

Cargando un script JS en el formulario

Cargando un script JS en el formulario

Una vez que “tweeteamos” nuestro contenido y volvemos a cargar la vista (que incluye la visualización del contenido de cada uno de los tweets) se estará ejecutando nuestro script:

Ataque de Javascript Injection

Ataque de Javascript Injection

Uno puede pensar que este tipo de ataques son inofensivos, sin embargo un hacker podría utilizar la inyección de JavaScript para realizar un ataque Cross-Site Scripting (XSS) robando información confidencial del usuario y enviando la misma a otro sitio web (dos ejemplos clásicos serían robar información de las cookies del navegador del usuario o información que se carga en un formulario que previamente a sido victima de Javascript Injection).

Cómo podemos evitar este ataque? Tenemos dos alternativas, la primera es utilizar el helper HTML.Encode el cual se encargara de renderizar el contenido de forma tal que no se ejecuten scripts que alguien pudo ingresar:

1: <div class="tweetSection">
2:  <% foreach (var item in Model) {  %> 
3:     <span class="tweetUser">  <%= item.Usuario %></span>
4:     <br />
5:      <%= Html.Encode(item.Mensaje)  %> 
6:     <br />
7:     <br />
8:  <%   }  %>

Ejecutamos y vemos que ya no se ejecuta nuestro script, ya que todo contenido reconocido como HTML a sido codificado de forma tal que se pueda visualizar como texto:

Utilizando el Helper Html.Encode

Utilizando el Helper Html.Encode

La segunda alternativa es codificar el contenido antes de grabarlo en la base de datos. Para esto podemos hacer uso del método Server.HtmlEncode que nos provee nuestro controlador:

1:             if (ModelState.IsValid)
2:             {
3:                 tweet.Mensaje = Server.HtmlEncode(tweet.Mensaje);
4:                 datos.Tweets.Add(tweet);
5:                 datos.SaveChanges();
6:             }

Utilizando este esquema ya no sería necesario utilizar el helper Html.Encode para visualizar el contenido (aunque no esta demás dejarlo). La desventaja de este enfoque es que los datos que se graban en la base de datos están codificados, lo cual no es del todo prolijo sobre todo si esta información se necesita visualizar en otro tipo de plataformas que no sean web. Observemos a continuación como se guardan los datos sin codificar (registro 2) y codificandolos (registro 3):

Registros de la base de datos

Registros de la base de datos

Para finalizar quería comentarles que utilizando el ViewEngine Razor los datos son “encodeados” automaticamente, sin necesidad de utilizar el helper Html.Encode y previniendonos de este tipo de ataques de entrada.  🙂

Quienes quieren el proyecto del ejemplo pueden descargarlo desde aquí: Projecto MvcJavascriptInjection

Minimizando hojas de estilos y scripts con Visual Studio

Generalmente cuando queremos pasar nuestras aplicaciones web ASP.NET o MVC ASP.NET a producción lo hacemos a través de la opción Publicar de Visual Studio. Esto funciona bien en aplicaciones sencillas, pero no es siempre lo que necesitamos. Supongamos que necesitamos automatizar ciertos aspectos de la implementación, que en nuestro caso será minificar los archivos CSS y JS antes de crear la aplicación final. Para estos casos podemos usar los proyectos Web Deployment Project.

El primer paso para poder utilizar este tipo de proyectos (no vienen por default en Visual Studio) y poder minimizar los archivos será instalar lo siguiente:

En este caso vamos a crear una aplicación web ASP.NET MVC 2.0 que llamaremos MvcEjemplo y le vamos a agregar algunos archivos CSS y script JS, que luego vamos a minimizar. Además de la aplicación web vamos a agregar a la solución un proyecto del tipo Web Deployment Project donde vamos a realizar las configuraciones necesarias para poder minimizar nuestros archivos.

Para agregar este tipo de proyecto, primero seleccionamos la aplicación web, y luego vamos a la opción “Build > Add Web Deployment Project”. Seleecionada esta opción llamaremos a nuestro nuevo proyecto MvcEjemplo.Deploy.

Estructura de la solución

Estructura de la solución

Agregado el proyecto, vamos a realizar la primera configuración para que los cambios siempre se apliquen sobre nuestra aplicación en modo Release. Para ello hacemos click derecho sobre el proyecto y vamos a la opción “Properties Windows”, dentro de la misma lo configuramos de la siguiente forma:

Configurando el proyecto

Configurando el proyecto

Existen otras configuraciones que en el ejemplo no las vamos a ver, pero que pueden serles muy útiles.

Una vez terminados estos pasos, vamos a comenzar las modificaciones, para esto hacemos click derecho sobre el proyecto y vamos a la opción “Open Project File”, la cual nos va a desplegar el archivo de configuración (un documento XML) en donde vamos a trabajar:

Abriendo el archivo del proyecto

Abriendo el archivo del proyecto

En el archivo de configuración el primer paso será hacer referencia a la librería Ajax Minifier, que nos va a proporcionar los métodos necesarios para poder minimizar nuestros archivos:

<Import Project="$(MSBuildExtensionsPath)\Microsoft\MicrosoftAjax\ajaxmin.tasks" />

La secciones dentro del XML de configuración que nos interesan en este caso son las encerradas dentro de los tags Target. El primero que vamos a modificar es el target “AfterMerge“. Dentro del mismo lo que vamos hacer es unificar todos los scripts JS del directorio “Script” (no tenemos en cuenta los que se encuentran en “Script\MyScripts” y nuestras hojas de estilos CSS en un único archivo para cada tipo (aclaro que unificamos dichos archivos en uno solo, ya que estos scripts y estilos suponemos se utilizan en todo el sitio y se referencian una única vez). Para esto agregamos lo siguiente:

<ItemGroup>
   <JsFiles Include="$(TempBuildDir)\Scripts\*.js;" Exclude="$(TempBuildDir)\Scripts\*.min.js;" />
   <CssFiles Include="$(TempBuildDir)\Content\*.css;" />
</ItemGroup>

Lo que hicimos fui incluir todos los archivos de script “JS” que se encuentran en el directorio “Scripts/” excepto los que terminen con la extensión “.min.js” (ya que los mismos ya se encuentran minimizados). Hacemos lo mismo con los archivos “CSS” que se encuentran en el directorio “Content” solo que en este caso no estamos excluyendo ninguno.

Hecho este paso, vamos a decir que todos los scripts que incluimos los escriba en un único archivo llamado AllJs.js:

<!-- Scripts Js -->
<ReadLinesFromFile File="%(JsFiles.Identity)">
   <Output TaskParameter="Lines" ItemName="jsLines" />
</ReadLinesFromFile>
<WriteLinesToFile File="$(TempBuildDir)\Scripts\AllJs.js" Lines="@(jsLines)" Overwrite="true" />

Para los archivos de estilos hacemos lo mismo pero en el archivo AllCss.css:

<!-- Css -->
<ReadLinesFromFile File="%(CssFiles.Identity)">
   <Output TaskParameter="Lines" ItemName="cssLines" />
</ReadLinesFromFile>
<WriteLinesToFile File="$(TempBuildDir)\Content\AllCss.css" Lines="@(cssLines)" Overwrite="true" />

Ahora vamos a trabajar en el Target “AfterBuild“. Lo que vamos a hacer es definir que archivos queremos minimizar, en nuestro caso los dos archivos que acabamos de “crear” y los script del directorio “MyScripts” por separados:

<ItemGroup>
   <JS Include="**\Scripts\AllJs.js;" />
   <JSMyScripts Include="**\Scripts\MyScripts\*.js;" />
</ItemGroup>
<ItemGroup>
   <CSS Include="**\Content\AllCss.css;" />
</ItemGroup>

Lo siguiente es “minimizar” dichos archivos:

<AjaxMin JsSourceFiles="@(JS)"
          JsSourceExtensionPattern="\.js$"
          JsTargetExtension=".min.js"
          CssSourceFiles="@(CSS)"
          CssSourceExtensionPattern="\.css$"
          CssTargetExtension=".min.css" />
<AjaxMin JsSourceFiles="@(JSMyScripts)" JsSourceExtensionPattern="\.js$" JsTargetExtension=".min.js" />

Finalmente podemos “eliminar” aquellos archivos que fueron minimizados y que no van a ser utilizados por tal motivo, por ejemplo:

<ItemGroup>
  <DeleteAfterBuild Include="$(OutputPath)Scripts\*.js" Exclude="$(OutputPath)Scripts\*.min.js" />
  <DeleteAfterBuild Include="$(OutputPath)Scripts\MyScripts\*.js" Exclude="$(OutputPath)Scripts\MyScripts\*.min.js" />
  <DeleteAfterBuild Include="$(OutputPath)Content\*.css" Exclude="$(OutputPath)Content\*.min.css" />
</ItemGroup>
<Delete Files="@(DeleteAfterBuild)" />

En nuestra aplicación web vamos a referenciar los scripts de dos formas diferentes, según se trate de la aplicación en modo debug (podríamos decir en desarrollo) o no (en producción):

<%if (HttpContext.Current.IsDebuggingEnabled){%>
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
<link href="../../Content/Style1.css" rel="stylesheet" type="text/css" />
<link href="../../Content/Style2.css" rel="stylesheet" type="text/css" />
<script src="../../Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="../../Scripts/ScriptJquery1.js" type="text/javascript"></script>
<script src="../../Scripts/ScriptJquery2.js" type="text/javascript"></script>
<script src="../../Scripts/MyScripts/Script2.js" type="text/javascript"></script>
<script src="../../Scripts/MyScripts/Script1.js" type="text/javascript"></script>
<%} else { %>
<link href="../../Content/AllCss.min.css" rel="stylesheet" type="text/css" />
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="Scripts/AllJs.min.js" type="text/javascript"></script>
<script src="Scripts/MyScripts/Script2.min.js" type="text/javascript"></script>
<script src="Scripts/MyScripts/Script1.min.js" type="text/javascript"></script>
% } %>

Nota: si bien esto es algo molesto de hacer (sobre todo si en cada vista donde referenciamos a un script debemos preguntar por lo mismo), lo podemos solucionar ,por ejemplo, por medio de HTML Helpers o utilizando otro mecanismo que nos automaticen esta tarea.

Finalmente hacemos el “Build” de nuestro nuevo proyecto y validamos que no haya errores:

Compilando el proyecto

Compilando el proyecto

El resultado lo encontramos dentro de la carpeta Release del proyecto:

Proyecto de salida con archivos minimizados.

Proyecto de salida con archivos minimizados.

Comparando un poco los resultados podemos ver cuanto más prolijo y liviano quedan las llamadas a nuestros scripts y hojas de estilos (en la primer imagen veremos los resultados sin minimizar y en la siguiente nuestros archivos “optimizados”):

Aplicación sin archivos minimizados

Aplicación sin archivos minimizados

Aplicación con archivos minimizados

Aplicación con archivos minimizados

Espero que les sea util, y no dejen de ver los otros tipos de configuraciones que nos ofrece los proyectos Web Deployment Project ya que van a encontrar cosas muy interesantes.

ValueProviders en ASP.NET MVC

Voy a comentarles en esta oportunidad sobre una característica de ASP.NET MVC 2 que son los ValueProviders. La documentación en MSDN es bastante pobre en este caso, pero los dejo el link para quienes quieran investigar un poco más.

Antes de comenzar recomiendo el post de Eduard Tomàs i Avellana del cual me inspiré para escribir este post.

Para hacer más fácil la explicación vamos a trabajar con un ejemplo, para ello vamos a crear una aplicación web ASP.NET MVC 2 y en primer lugar vamos a definir la clase Cliente de la siguiente manera:

public class Cliente
{
    public int Id { get; set; }
    public string Nombre { get; set; }
    public string Email { get; set; }
    public int Saldo { get; set; }
}

Seguido a esto vamos a crear un controlador, en este ejemplo lo llamaremos ClienteController y vamos a definir la acción Create (podemos utilizar la que nos crea por default Visual Studio):

[HttpPost]
public ActionResult Create(Cliente cliente)
{
    return View();
}

Por último vamos a definir la vista de la siguiente forma:

<h2>Create</h2>
<% using (Html.BeginForm()) {%>
    Nombre: <%= Html.TextBoxFor(model => model.Nombre) %>
    E-mail: <%= Html.TextBoxFor(model => model.Email)%>
    Saldo: <%= Html.TextBoxFor(model => model.Saldo) %>
    <input type="submit" value="Create" />
<% } %>

Ahora detengámonos un poco en este punto, y analicemos lo que pasa cuando hacemos un submit del formulario. Al clickear sobre el botón Create, MVC envía el formulario en una request generando los siguientes datos:

Datos de la request

Datos de la request

Podemos ver claramente que los datos que cargamos del cliente en el formulario viajan como parámetros POST, y los mismos son identificados a partir del atributo name de los controles que los contienen.  Ahora es ASP.NET MVC el responsable de hacer el binding de esos campos POST con las propiedades de nuestra clase Cliente, y de esta manera instanciar un nuevo cliente que será enviado a nuestro controlador. Para ser más precisos, quien se encarga de generar el cliente a partir de los valores de la petición es el ModelBinder (en otro post hablaremos de él) quien a su vez hace uso de los Value Providers.

Los ValueProviders son los encargados de  inspeccionar y obtener los valores de la petición y “guardarlos” hasta que sean solicitados por el ModelBinder.

Pero vayamos por parte, veamos una gráfica para que se entienda un poco mejor este proceso:

ModelBinder

ModelBinder

A grandes rasgos el proceso es el siguiente, el ModelBinder es el encargado de hacer el binding entre los valores de la request al objeto que corresponda – en nuestro ejemplo un Cliente – para luego enviárselo al controlador. Estos valores los deberá obtener de una lista de ValueProviders los cuales tienen guardarlos la información de los campos recuperados en la petición (el acceso a estos valores no es de forma directa, sino que cada ValueProvider tendrá una factoría que será la encargada de proporcionarlos al MoldelBinder, veremos esto con más detalle más adelante).

Vale aclarar que no existe un único ValueProvider, sino que pueden existir diferentes tipos, por ejemplo algunos que inspecciones los valores de los parametros POST, otros los valores de los parámetros de la URL, otros los valores de las cooquies… Además es importante tener en cuenta que el ModelBinder irá buscando los valores de cada campo que necesite por orden, y a medida que los vaya encontrando, dejará de buscarlos en los siguiente value providers (por ejemplo, si el campo Saldo esta presente en los values provider que inspeccionan los campos POST y también en el value provider que inspecciona los parámetros de la URL, el ModelBinder solamente se quedará con uno de ellos, y este valor será del primer value provider que inspeccionó).

Ahora vamos a lo interesante, crear nuestro propio value provider!. Para ello solo debemos crear y extender nuestra clase DefaultValueProvider de IValueProvider. Este tendrá como finalidad obtener un valor default para el parámetro Saldo leyéndolo desde el archivo de configuración web.config utilizando nuestra propia clase personalizada para poder accederlos:

public class DefaultValueProvider : IValueProvider
{
    private Dictionary<string, ValueProviderResult> values;

    public DefaultValueProvider()
    {
        values = new Dictionary<string, ValueProviderResult>();

        var configuracion = (ValoresDefaultConfigurationSection)ConfigurationManager.GetSection("valoresDefault");
        int saldo = configuracion.Saldo;

        values.Add("Saldo", new ValueProviderResult(saldo, saldo.ToString(), CultureInfo.InvariantCulture));
    }

    public bool ContainsPrefix(string prefix)
    {
        return values.ContainsKey(prefix);
    }

    public ValueProviderResult GetValue(string key)
    {
        ValueProviderResult value;
        values.TryGetValue(key, out value);
        return value;
    }
}

Lo primero que podemos observar es que de IValueProvider vamos a implementar los siguientes  métodos:

ConstainsPrefix: el cual nos permite saber si existe algun valor para el campo pedido.
GetValue: retorna el valor solicitado para una clave.

En el constructor de la clase, vamos a leer el valor del saldo que tenemos definido en nuestro web.config y una vez obtenido lo agregaremos a nuestro diccionario de valores, poniéndole como clave el nombre del campo y como valor un objeto del tipo ValueProviderResult el cual tiene como parámetros: el valor en sí, el valor expresado como string y por último el tipo de cultura (este objeto es el que le retornamos a ModelBinder cuando solicita el valor de un campo, como verán no es un simple valor).

Finalizado nuestro value provider deberemos crear su factory, ya que como dijimos anteriormente, el ModelBinder no accede directamente a los valores, sino que lo hace por medio de sus factories (esto entre otras cosas permite hacer más extensible nuestro código).

Las factories tendrán la responsabilidad de devolver los valores en cada petición:

public class DefaultValueProviderFactory : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        return new DefaultValueProvider();
    }
}

Es bastante simple su construcción, deberemos heredar de ValueProviderFactory y sobreescribir el método GetValueProvider, que el que vamos a utilizar para retornar nuestro DefaultValueProvider. Es interensante aclarar que desde la factory tenemos acceso al ControllerContext, por lo tanto podríamos pasarselo al constructor del ValueProvider para obterner datos del contexto actual (por ejemplo valores de la request, de las cooquies…).

Finalmente le avisamos a ASP.NET MVC que tenga presente nuestra factory, y para eso en el archivo Global.asax registramos la misma:

protected void Application_Start()
{
    ...
    ValueProviderFactories.Factories.Add(new DefaultValueProviderFactory());
 }

Ahora, solo resta eliminar del formulario el campo Saldo, para que no sea recuperado por las factories anteriores a la nuestra (es decir, las que obtienen los valores de los parámetros POST en este caso). Ahora al hacer el submit del formulario veremos que el valor de Saldo del cliente será el que hayamos definido en nuestro archivo de configuración:

Campo saldo recuperado por nuestro Value Provider

Campo saldo recuperado por nuestro Value Provider

Próximamente vamos a ver un poco más en profundidad el ModelBinder.

Implementando IoC en ASP.NET MVC 2 con Castle Windsor

En un post anterior hablamos sobre los beneficios de aplicar el patrón IoC en nuestros proyectos y vimos un breve ejemplo utilizando Unity de la gente de Patterns & Practices. Además comentamos que existen diferentes frameworks que nos facilitan estas tareas, uno de ellos es Castle Windsor y es el que vamos a utilizar en este caso.

Castle Project

Castle Project

En este post vamos a explicar cómo configurar IoC utilizando este framework en una aplicación web ASP.NET MVC 2.

El primer paso será descargar desde la página oficial del proyecto Castle las librerías Windsor 2.1link de la descarga.

El siguiente paso será crear una aplicación ASP.NET MVC 2 y agregar las siguientes referencias a nuestro proyecto:  Castle.Core.dll, Castle.MicroKernel.dll, Castle.Windsor.dll.

Referencias

Referencias

Para seguir con el ejemplo del post inicial, vamos a crear una interfaz denominada IRedSocialService y dos servicios que la implementen (por ejemplo TwitterService y FacebookService). La definición de la interfaz podría ser la siguiente:

public interface IRedSocialService
{
    IEnumerable ObtenerContactos();
}

La implementación de ambos servicios se las dejo a ustedes 🙂 .

A continuación vamos a configurar nuestras dependencias utilizando Windsor Container. Para ello lo que vamos hacer es realizar algunas modificaciones en nuestro archivo de configuración Web.config y separar las configuraciones propias del contenedor en otro archivo de configuración aparte que vamos a crear y llamar Castle.config.

La estructura del proyecto sería más o menos la siguiente:

Estructura proyecto

Estructura proyecto

Al archivo web.config vamos a agregarle lo siguiente:

<configuration>
<configSections>
...
<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>

<castle configSource="Castle.config"></castle>
 …
</configuration>

Qué estuvimos haciendo? En primer lugar indicando que la sección castle será utilizada por CastleSectionHandler y que es encuentra en el assemblie Castle.Windsor. En segundo lugar estamos indicando que la sección castle se encuentra dentro del archivo castle.config y que vamos a configurar a continuación.

Al archivo castle.config vamos a agregar lo siguiente:

<castle>
<components>
<component id="ServicioRedSocial"
                    type="Castle.Windsor.Logica.TwitterService, Castle.Windsor.Logica"
                    service="Castle.Windsor.Logica.IRedSocialService, Castle.Windsor.Logica" />
</components>
</castle>

Qué estuvimos haciendo? Estuvimos registrando nuestro primer elemento del contenedor. Vamos a explicar cada tag por parte:

  • id: nombre con el que queremos identificar ese elemento en particular.
  • service: la interfaz sobre la cual vamos hacer las inyecciones.
  • type: el tipo concreto que queremos que el contenedor devuelva como implementación de la interfaz definida.

Teniendo en cuenta la configuración actual, cuando solicitemos una instancia de IRedSocialService deberíamos obtener un objeto TwitterService. Pero ojo, aún falta para que esto suceda…

Ahora es turno de trabajar con nuestro controlador que llamaremos RedSocialController, y en donde vamos a definir nuestro contenedor y nuestro servicio de la siguiente manera:

private WindsorContainer contenedor;
private IRedSocialService servicio;

Ahora vamos a trabajar sobre el constructor del controlador y la acción Index :

public class RedSocialController : Controller
{
    private WindsorContainer contenedor;
    private IRedSocialService servicio;

    public RedSocialController()
    {
        this.contenedor = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
        this.servicio = contenedor.Resolve<IRedSocialService>();
    }

    public ActionResult Index()
    {
        IEnumerable contactos = servicio.ObtenerContactos();
        return View(contactos);
    }
}

Dentro del constructor del controlador creamos nuestro contenedor, indicándole que la sección castle del archivo de configuración tiene las configuraciones correspondientes. Luego seteamos nuestro servicio, pidiendo al contenedor que nos devuelva la instancia que hayamos configurado. Finalmente vamos a tener disponible nuestro servicio en cada una de las acciones de RedSocialController.

Ejecutamos y listo!

Ejemplo IoC

Ejemplo IoC

Si ahora deseamos recuperar los contactos de otra red social, solo deberemos modificar nuestro archivo de configuración y todo solucionado!

Pero porqué quedarse acá? Porqué no aprovechar algunas de las características de ASP.NET MVC y automatizar aún más nuestras inyecciones?… Comencemos entonces!

La idea ahora es hacer las inyecciones sobre los parámetros del constructor de los controladores, y evitar tener que crear en cada controlador el contenedor y luego setear los servicios. Pero cómo podemos hacer esto? …  ASP.Net MVC al crear un controlador utiliza una factory, una instancia de la clase DefaultControllerFactory que requiere que los controladores tengan el constructor por defecto. Cómo esto no nos sirve, ya que la idea es tener constructores con parámetros, podemos crear nuestra propia factory y luego especificarle a MVC que las utilice (tengamos en cuenta que deberá heredar de DefaultControllerFactory).

Entonces vamos a crear nuestra propia factory que se va a encargar de realizar las inyecciones de dependencias sobre los parámetros de nuestros controladores (y por nosotros :)). Para esto vamos a crear una clase denominada WindsorControllerFactory.

Veamos cómo queda nuestra factory:

public class WindsorControllerFactory : DefaultControllerFactory
{
    WindsorContainer container;

    public WindsorControllerFactory()
    {
        container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
        var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
                                     where typeof(IController).IsAssignableFrom(t)
                                     select t;

        foreach (Type t in controllerTypes)
            container.AddComponentLifeStyle(t.FullName, t,LifestyleType.Transient);
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
            return null;

        return (IController)container.Resolve(controllerType);
    }
}

Como vemos debemos sobre-escribir el método GetControllerInstance e inyectar las dependencias al momento de devolver el controlador – esto en tiempo de ejecución.

Finalmente debemos indicarle a MVC que utilice nuestra controller factory, para eso agregamos en nuestro archivo global.asax la siguiente línea dentro del método Application_Start():

ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory());

Finalmente volvemos a redefinir nuestro controlador de la siguiente forma:

public class RedSocialController : Controller
{
    private IRedSocialService servicio;

    public RedSocialController(IRedSocialService servicio)
    {
        this.servicio = servicio;
    }

    public ActionResult Index()
    {
        IEnumerable contactos = servicio.ObtenerContactos();
        return View(contactos);
    }
}

A diferencia del controlador anterior, este tiene definido como parámetros del constructor el tipo de interfaz que vamos a utilizar en el servicio, la cuál es inyectada por nuestra factory al momento de inicializarse el controller. También podemos ver que no es necesario crear el contenedor y setear nuestro servicio, lindo no!?