Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
miércoles, 6 de julio de 2011
ASP.NET MVCASP.NET MVC viene acompañado de serie por un buen número de subtipos de ActionResult que podemos utilizar como retorno de nuestras acciones (FileResult, ContentResult, ViewResult, RedirectResult, etc…) y que cubren la mayoría de escenarios de uso frecuente al desarrollar aplicaciones para este framework.

Pero sin duda, lo mejor de todo es lo fácilmente que podemos extender este conjunto para lograr resultados muy potentes, reutilizables y respetuosos con el patrón.

En este post vamos a ver cómo crear en unos minutos un nuevo tipo de resultado para nuestras acciones llamado ZipResult, que nos permitirá generar al vuelo archivos en formato comprimido .ZIP, en cuyo interior podremos añadir los ficheros que queramos.

Así, nuestro ZipResult recibirá una serie nombres de archivo, los comprimirá, y los retornará al usuario empaquetados en un único fichero .ZIP. A nivel de código, su uso será así de simple:
public ActionResult DescargarArchivos()
{
    return new ZipResult("c:\\archivo1.dat", "c:\\archivo2.dat");
}
¡Vamos allá!

1. Creación de zips desde .NET

Desde la llegada de Nuget, nada ha vuelto a ser lo mismo. En unos segundos, sólo abriendo la herramienta de gestión de paquetes, seleccionando la opción “online” y haciendo una búsqueda sobre el término “zip” tenemos acceso a la oferta de paquetes relacionados con el mismo:

Resultado de búsqueda de "zip" en Nuget

Como podemos ver, existen muchas opciones para tratar con archivos .zip que tenemos al alcance de un clic. En este caso vamos a usar DotNetZip, una potente biblioteca open source que nos ofrece todo lo que necesitamos en este proyecto y mucho más ;-), pero a diferencia de otras, es bastante más sencilla y cómoda de utilizar.

Y como muestra el siguiente método, que recibe una lista de rutas de archivo y los comprime sobre un fichero .zip:
public void Comprime(IEnumerable<string> files)
{
    using (ZipFile zf = new ZipFile())
    {
        zf.AddFiles(_files, false, "");
        zf.Save(@"d:\prueba.zip");
    }
 
}
El código es bastante conciso y fácil de comprender; creamos un nuevo archivo zip, representado por la instacia del tipo ZipFile, llamamos a su método AddFiles() suministrándole la colección de rutas de los ficheros a comprimir, y salvamos el resultado al disco. El segundo parámetro de AddFiles() se usa  para indicar si se respetan las rutas originales de los archivos y el tercero especifica el nombre de carpeta donde se almacenarán dentro del fichero .zip.

2. Creación de ActionResults personalizados

Aunque estrictamente hablando no tendría por qué ser así, la práctica totalidad de las acciones en ASP.NET MVC retornan un objeto de tipo ActionResult, como en el siguiente ejemplo:
public ActionResult About()
{
    return View();
}
La clase abstracta ActionResult se define en el espacio de nombres System.Web.Mvc de la siguiente forma:
public abstract class ActionResult
{
    public abstract void ExecuteResult(ControllerContext context);
}
Cuando una acción retorna un subtipo de ActionResult, el framework se encarga de invocar a su método ExecuteResult() para que envíe el resultado al cliente. Por ejemplo, en el caso de un ViewResult (el retorno generado por el método View() del controlador), su método ExecuteResult() es el responsable de ponerse en contacto con el motor de vistas para generar el HTML, y retornar el marcado al cliente; un RedirectResult, en cambio, sólo se encargará de retornar una redirección (temporal o permanente).

Por tanto, lo único que necesitamos para crear nuestro tipo de resultado personalizado es crear una clase que herede de ActionResult e implementar en ella el método ExecuteResult(). En la práctica, normalmente encontraremos en este método la lógica de generación del resultado, establecimiento de encabezados de la respuesta (content-type, content-disposition, status code, etc.), y el envío a través del canal de salida de la información deseada.

3. ZipResult, el ActionResult que retorna archivos .zip

A continuación se muestra el código de la clase ZipResult, que se encarga de retornar al cliente un archivo comprimido en formato .zip en cuyo interior se encontrarán todos los archivos indicados en el momento de su instanciación.

Lo que vale la pena leer está prácticamente al final de la porción de código, el método ExecuteResult(), que es el que realmente realiza el trabajo de comprimir y enviar al cliente el archivo resultante:
public class ZipResult : ActionResult
{
    private IEnumerable<string> _files;
    private string _fileName;
 
    public string FileName
    {
        get
        {
            return _fileName ?? "archivo.zip";
        }
        set { _fileName = value; }
    }
 
    public ZipResult(params string[] files)
    {
        this._files = files;
    }
 
    public ZipResult(IEnumerable<string> files)
    {
        this._files = files;
    }
 
    public override void ExecuteResult(ControllerContext context)
    {
        using (ZipFile zf = new ZipFile())
        {
            zf.AddFiles(_files, false, "");
            context.HttpContext
                .Response.ContentType = "application/zip";
            context.HttpContext
                .Response.AppendHeader("content-disposition", "attachment; filename=" + FileName);
            zf.Save(context.HttpContext.Response.OutputStream);
        }
    }
 
} 
Observad que el método ExecuteResult() es prácticamente idéntico al Comprime()  que mostrábamos más arriba para ver lo fácil que resultaba comprimir archivos con DotNetZip. Sólo le estamos añadiendo los encabezados para la respuesta HTTP, y estamos haciendo que el archivo sea salvado directamente sobre el stream de salida en lugar de hacerlo en disco.

4. Uso desde el controlador

Y para utilizar nuestro flamante ActionResult, lo único que debemos hacer es instanciarlo desde la acción, suministrarle las rutas hacia los archivos que deseamos comprimir y retornarlo como resultado:
public ActionResult Descargar()
{
    return new ZipResult(
        Server.MapPath("~/Archivos/fich1.txt"),
        Server.MapPath("~/Archivos/fich2.txt"),
        Server.MapPath("~/Archivos/fich3.txt")
    );
}
Demo de ZipResultPara que podáis verlo en vivo y en directo, he colgado en SkyDrive una demo algo más completita en la que es posible elegir los archivos de una carpeta, que son comprimidos y retornados por ZipResult.

image Descargar proyecto de demostración.

Espero que os resulte interesante.

Publicado en: Variable not found.
martes, 5 de julio de 2011
Estos son los enlaces publicados en Variable not found en Facebook y Twitter desde el lunes, 27 de junio de 2011 hasta el lunes, 04 de julio de 2011. Espero que te resulten interesantes. :-)
Y no olvides que puedes seguir esta información en vivo y en directo desde Variable not found en Facebook, o a través de Twitter.

Publicado en: Variable not found
lunes, 4 de julio de 2011
MVP 2011Hace unos días recibí una alegría que necesito compartir con todos vosotros de forma urgente :-)

El escenario era el siguiente: toda la familia metida en el coche a las cinco de la tarde, rumbo a la costa para pasar el fin de semana, un calor de narices, una morriña siestera bastante importante y muchas ganas de llegar a la playa.

Decidimos parar en una estación de servicio para tomar un café que nos permitiera continuar la marcha en condiciones razonables. Como de costumbre, aprovecho para revisar el correo electrónico desde el móvil por si ha surgido alguna emergencia de última hora, y me encuentro con esto:
Asunto: ¡Enhorabuena MVP de Microsoft 2011!

Estimado/a Jose Maria Aguilar,

Enhorabuena. Nos complace presentarle el programa de nombramiento MVP de Microsoft de 2011. Este nombramiento se concede a los líderes excepcionales de la comunidad técnica que comparten de forma activa su experiencia de alta calidad y de la vida real con otras personas. Le agradecemos especialmente la contribución que ha realizado en las comunidades técnicas en el área de ASP.NET/IIS a lo largo del pasado año.

[…]
De pronto se me quitaron el calor, el sueño, e incluso las ganas de playa. ¡Vaya sorpresa! :-)))

Para el despistadillo que aún no lo sepa, el MVP es un galardón que concede Microsoft a personas de la comunidad técnica que dedican parte de su tiempo a compartir con otros usuarios sus conocimientos y experiencias sobre productos y tecnologías de esta compañía. Si estás interesado en saber más sobre ello, aquí puedes leer sobre el programa MVP.

Es para mí un honor y un privilegio el poder entrar a formar parte de este grupo, y sólo espero estar a la altura de esta distinción. Intentarlo, lo intentaré, os lo aseguro ;-)

Gracias a todos los que lo habéis hecho posible.

¡Nos vemos!
miércoles, 29 de junio de 2011
ASPNETMVCHace unos días, el gran David Ebbo publicaba un proyecto experimental llamado “Razor Generator”, un conjunto de herramientas destinadas a precompilar las vistas Razor que he visto bastante interesante y que creo que vale la pena comentar.

Aunque ya aquí hemos hablado varias veces sobre la compilación de vistas, el enfoque de este nuevo proyecto es bastante diferente, pues permite generar clases en C# partiendo de las vistas, lo que permite, por ejemplo:
  • distribuir vistas compiladas en una DLL, facilitando así el despliegue,
  • evitar la distribución de los archivos .cshtml y, por tanto, la posibilidad de que sean modificados fácilmente,
  • al disponer de una clase que genera la vista, podemos realizar pruebas unitarias que comprueben su contenido de forma muy sencilla (puedes ver un ejemplo aquí),
  • reducir drásticamente el tiempo de arranque de la aplicación ASP.NET MVC en producción, dado que no es necesario compilar las vistas en ese momento,
  • … y, por supuesto, comprobamos su corrección sintáctica en tiempo de compilación.
El proyecto consiste, por una parte, en una extensión para Visual Studio 2010 que instala la herramienta de generación de código llamada “RazorGenerator”. Es posible descargarla tanto desde la galería online como utilizando el administrador de extensiones del IDE.

Razor generator

Estableciendo la herramienta personalizada
Una vez descargada esta extensión, si deseamos generar la clase asociada a una vista simplemente debemos acudir a las propiedades del archivo, y establecer a “RazorGenerator” su herramienta personalizada, como puede observarse en la captura de pantalla adjunta.

A partir de ese momento, cada vez que modifiquemos la vista (el archivo .cshtml), se generará de forma automática el fichero de código .cs con la clase correspondiente, de forma que al compilar el proyecto ya éstas se estarán incluyendo en el ensamblado resultante.

La siguiente parte del proyecto de David es un ViewEngine especialmente diseñado para la ocasión, que en lugar de utilizar las vistas disponibles en el sistema de archivos del servidor, intenta localizar las clases compiladas correspondientes.

Para facilitar la tarea e instalar de forma correcta este ViewEngine, simplemente hemos de utilizar Nuget para montar el paquete “PrecompiledMvcViewEngine”:

PM> Install-Package PrecompiledMvcViewEngine
Attempting to resolve dependency 'WebActivator (≥ 1.4)'.
Successfully installed 'WebActivator 1.4.1'.
Successfully installed 'PrecompiledMvcViewEngine 1.0'.
...

Bien, pues lo curioso del tema es que este paquete podemos instalarlo directamente sobre un proyecto de biblioteca de clases e introducir en él todas las vistas de nuestra aplicación. Estableciendo la herramienta personalizada de todas ellas a “RazorGenerator”, tendremos las vistas compiladas y para utilizarlas únicamente será necesario referenciar esta biblioteca desde el proyecto MVC principal. Y obviamente, ya no tendremos que distribuir las vistas de /Views, puesto que se estarán utilizando las versiones compiladas :-)

Puedes ver un completo paso a paso sobre cómo precompilar las vistas en el blog de David Ebbo.

Aunque todavía es pronto y quizás no sea buena idea utilizar estos componentes el producción, la precompilación de vistas con este enfoque aporta un gran número de ventajas directas ya comentadas, y lo que es mejor, deja entrever interesantes utilidades como la posibilidad de conseguir plugins o áreas fácilmente reutilizables de una aplicación a otra simplemente copiando los ensamblados al proyecto. A ver si un día de estos tengo un rato y hago alguna pruebilla al respecto y os comento mis conclusiones.

Publicado en: Variable not found.
martes, 28 de junio de 2011
Estos son los enlaces publicados en Variable not found en Facebook y Twitter desde el lunes, 20 de junio de 2011 hasta el lunes, 27 de junio de 2011. Espero que te resulten interesantes. :-)
Y no olvides que puedes seguir esta información en vivo y en directo desde Variable not found en Facebook, o a través de Twitter.

Publicado en: Variable not found
miércoles, 22 de junio de 2011
AUGESEl próximo miércoles 29 de junio de 2011, a las 19:30 horas en el horario peninsular español, AUGES (ASP.NET User Group España) nos ofrece, para cerrar la temporada hasta después de verano, un eventazo online de los que no os podéis perder.

En primer lugar por el ponente, que no podía ser otro que el gran Hadi Hariri, evangelista técnico de JetBrains, Microsoft MVP, ponente internacional, y un auténtico fenómeno donde los haya.

En segundo lugar por el tema: arquitecturas REST. Ha llegado el momento de comprender, de la mano de un experto, en qué consiste y cómo implementar este tipo de sistemas utilizando ASP.NET MVC.
Título: Arquitecturas REST con ASP.NET MVC

Descripción: Crear arquitecturas REST con ASP.NET MVC es más que decorar acciones con verbos. Se trata de aprovechar el protocolo HTTP en todo su potencial. Al hacerlo, podemos crear aplicaciones robustas y escalables, no solo desde el punto de vista de rendimiento sino también en términos de mantenibilidad. ASP.NET MVC nos ofrece un gran potencial para crear arquitecturas REST que pueden ser consumidas por otros sistemas así como personas, reduciendo la cantidad de esfuerzo. Te esperamos en este evento si quieres aprender de que trata REST realmente y cómo podemos crear un sencillo pero potente sistema con ASP.NETMVC.

Ponente: Hadi Hariri- Technical Evangelist en JetBrains.
Información y registro gratuito: https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032488451&EventCategory=4&culture=es-ES&CountryCode=ES

Publicado en: Variable not found.