jueves, 14 de julio de 2011
Como desarrolladores web, seguro que os habéis encontrado muchas veces con la necesidad de incluir texto de relleno en las páginas, y muy probablemente hayáis usado servicios como http://www.lipsum.com/ para generarlos.
Pues bien, hace poco he dado con Lorempixum, un interesante servicio que nos proporciona algo similar sobre el contenido gráfico: un generador de imágenes de relleno. Y es que, durante nuestro trabajo, también nos viene de fábula tener a mano un buen banco de imágenes clasificadas, con distintos tamaños, y sin problemas de licencia, listas para ser utilizadas en prototipos de sitios web.
Lorempixum permite dos vías para generar imágenes. La primera de ellas se basa en acudir al sitio web (http://www.lorempixum.com/) y utilizar el pequeño formulario que aparece para indicar los detalles de la imagen que deseamos generar.
Simplemente introduciendo o seleccionando el ancho, alto, la temática (a elegir entre las once disponibles, tales como gente, tecnología, transporte, naturaleza, etc.), y si deseamos que sea en color o escala de grises, el sistema seleccionará y generará automáticamente una imagen totalmente ajustada a nuestras pretensiones :-)
Otra posibilidad es invocar directamente al generador de Lorempixum utilizando URLs en las que introduciremos los parámetros de la imagen a generar. A continuación se muestran algunos ejemplos de llamadas, y el resultado obtenido:
Obviamente, estas direcciones podemos teclearlas directamente en el navegador para obtener las imágenes, o bien introducirlas como origen de los
En definitiva, un servicio interesante para no tener que andar por ahímendigando buscando imágenes de prueba para nuestros prototipos y demostraciones. Imágenes de calidad aceptable, justo del tamaño y temática que necesitamos, y que podemos obtener de forma muy rápida y sencilla.
Publicado en: Variable not found.
Pues bien, hace poco he dado con Lorempixum, un interesante servicio que nos proporciona algo similar sobre el contenido gráfico: un generador de imágenes de relleno. Y es que, durante nuestro trabajo, también nos viene de fábula tener a mano un buen banco de imágenes clasificadas, con distintos tamaños, y sin problemas de licencia, listas para ser utilizadas en prototipos de sitios web.
Lorempixum permite dos vías para generar imágenes. La primera de ellas se basa en acudir al sitio web (http://www.lorempixum.com/) y utilizar el pequeño formulario que aparece para indicar los detalles de la imagen que deseamos generar.
Simplemente introduciendo o seleccionando el ancho, alto, la temática (a elegir entre las once disponibles, tales como gente, tecnología, transporte, naturaleza, etc.), y si deseamos que sea en color o escala de grises, el sistema seleccionará y generará automáticamente una imagen totalmente ajustada a nuestras pretensiones :-)
Otra posibilidad es invocar directamente al generador de Lorempixum utilizando URLs en las que introduciremos los parámetros de la imagen a generar. A continuación se muestran algunos ejemplos de llamadas, y el resultado obtenido:
Imagen aleatoria en color de 200px de ancho por 100px de alto Categoría “Sports” http://lorempixum.com/200/100/sports/ | |
Imagen aleatoria en grises de 200px de ancho por 100px de alto Categoría “Sports” http://lorempixum.com/g/200/100/sports/ (La “g” indica que queremos la imagen en grises) | |
Quinta imagen en color de 200px x 100px Categoría “Fashion” http://lorempixum.com/200/100/fashion/5/ | |
Imagen aleatoria en color de 200px de ancho por 180px de alto Categoría “City” Texto sobreimpreso “Variable not found” http://lorempixum.com/200/180/city/Variable not found/ |
Obviamente, estas direcciones podemos teclearlas directamente en el navegador para obtener las imágenes, o bien introducirlas como origen de los
<img>
de nuestras páginas, por ejemplo así: <img src="http://lorempixum.com/200/180/city" alt=”Ciudad” />
En definitiva, un servicio interesante para no tener que andar por ahí
Publicado en: Variable not found.
Publicado por José M. Aguilar a las 10:15 a. m.
Hay
2 comentarios, ¡participa tú también!
Etiquetas: diseño, servicios on-line, web
martes, 12 de julio de 2011
Tratar con tipos enumerados (
Por ejemplo, hasta la fecha, Entity Framework los ha ignorado por completo (aunque que esto va a cambiar y la próxima versión de EF sí soportará enums :-)), lo cual resulta muy incómodo en el momento de crear componentes de acceso a datos, viéndonos obligados a realizar demasiadas conversiones, o incluso a veces el plantearnos otras soluciones, como el uso de constantes numéricas en su lugar para simplificar las operaciones.
Y no sólo eso, también podemos hacer referencia al identificador asignado en la enumeración; así, una petición como
Pero en realidad no se trata de un mérito del binder, ni tan siquiera del framework MVC. Internamente, el proceso de conversión de los tipos enumerados se delega a la clase
En resumen, esta flexibilidad a la hora de interpretar los valores y obtener el elemento correspondiente del enumerado es realmente potente y da mucho juego a la hora de crear en nuestras aplicaciones acciones muy expresivas y respetuosas con el protocolo HTTP sobre el que trabajamos. Sin embargo, esta potencia tiene también unas contraindicaciones que debemos conocer.
Observad que, a diferencia de lo que podríamos esperar, la excepción no hace referencia al hecho de que el miembro
Para confirmarlo, sólo tenemos que utilizar un tipo anulable en el parámetro de la acción, así:
Simplemente con esa línea ya aseguramos que la aplicación no se parará en ejecución cuando llegue un nombre incorrecto del miembro de la enumeración, simplemente deberemos controlar lo que queremos hacer en caso de que color sea nulo.
Pero un problema aún más grave tenemos cuando el valor incorrecto viene expresado en forma numérica, indicando un valor inexistente en el tipo enumerado, por ejemplo en
Y precisamente por eso decía el problema es más grave que antes, que al menos la excepción o el valor nulo en el parámetro de entrada indicaba que el valor recibido no es correcto. Si lo que nos llega es un número fuera de rango no nos enteraremos y “se colará” silenciosamente en nuestra lógica, lo que podría liar un desaguisado tremendo.
A continuación se muestra cómo podríamos gestionar en la acción la entrada de un dato incorrecto, bien sea por tratarse de un identificador inválido (que entraría un nulo) o bien un valor numérico fuera de los permitidos en la enumeración. Observad que utilizamos el método
A continuación tenemos que indicar al framework que debe utilizar este model binder para las enumeraciones. Una posibilidad sería registrar en la colección
Otra posibilidad sería utilizar los nuevos
En cualquier caso, sea cual sea la vía utilizada, una vez asociado el binder en la inicialización de la aplicación, ya controlará por nosotros la entrada de valores incorrectos para la enumeración:
Pues la respuesta es bien simple: como si se tratara de cualquier otro tipo de datos. El siguiente código muestra la generación de enlaces hacia la acción vista anteriormente utilizando el helper
Publicado en: Variable not found.
enum
en C#), a pesar de su comodidad e idoneidad en multitud de ocasiones, suele siempre una tarea pesada debido a la falta de soporte directo existente en algunas tecnologías.Por ejemplo, hasta la fecha, Entity Framework los ha ignorado por completo (aunque que esto va a cambiar y la próxima versión de EF sí soportará enums :-)), lo cual resulta muy incómodo en el momento de crear componentes de acceso a datos, viéndonos obligados a realizar demasiadas conversiones, o incluso a veces el plantearnos otras soluciones, como el uso de constantes numéricas en su lugar para simplificar las operaciones.
public enum Color
{
Rojo = 1,
Verde = 2,
Azul = 3
}
Ya centrados en ASP.NET MVC, un aspecto muy interesante del mecanismo de binding es su capacidad para trabajar de forma muy natural con estos tipos de datos, aunque esto pueda acarrear algunos problemillas. Veámoslo con un ejemplo partiendo del siguiente controlador:public class EnumController : Controller
{
public ActionResult Test(Color color)
{
return Content("Color: " + color);
}
}
Suponiendo que utilizamos la ruta por defecto, una petición dirigida a la dirección URL /enum/test?color=1
retornará por pantalla el texto “Color: Rojo”. Durante el binding, el framework ha recuperado el parámetro “color” presente en la query string (un “1”) y lo ha transformado en el elemento de la enumeración correspondiente con este valor.Y no sólo eso, también podemos hacer referencia al identificador asignado en la enumeración; así, una petición como
/enum/test?color=Verde
será capaz de interpretarlo de forma correcta, asignando al parámetro color
el valor apropiado.Pero en realidad no se trata de un mérito del binder, ni tan siquiera del framework MVC. Internamente, el proceso de conversión de los tipos enumerados se delega a la clase
EnumConverter
(presente en System.ComponentModel
), que a su vez llamará a Enum.Parse()
para obtener el valor apropiado desde el string
obtenido por el value provider desde la query string. Este método examina la cadena y en función de su contenido buscará de una u otra forma el miembro de la enumeración a retornar:- Si la cadena comienza por un dígito o los signos “-“ o “+”, interpreta que el contenido del
string
es el valor asignado al elemento, por lo que intentará obtenerlo partiendo de éste. Por eso el ejemplo anterior, cuando en la petición asignábamos acolor
el valor “1” funcionaba correctamente. - En caso contrario, se asume que la cadena contiene directamente el identificador (“Rojo”, “Verde”…), y se intenta localizar en la enumeración el elemento que coincida con el suministrado. Por esta razón el segundo ejemplo, cuando en la petición asignábamos a
color
el valor “verde” también funcionaba correctamente.
/enum/test/?color=Rojo,Verde
será también interpretada de forma correcta, introduciendo en el parámetro color la combinación (un "or" binario) de ambos valores, de la misma forma que lo sería /enum/test/?color=1,2
.En resumen, esta flexibilidad a la hora de interpretar los valores y obtener el elemento correspondiente del enumerado es realmente potente y da mucho juego a la hora de crear en nuestras aplicaciones acciones muy expresivas y respetuosas con el protocolo HTTP sobre el que trabajamos. Sin embargo, esta potencia tiene también unas contraindicaciones que debemos conocer.
¿Y qué ocurre cuando los valores que se envían a una acción no son correctos?
Pues aquí llegan los problemas, claro ;-). Si a la acción anterior enviamos una petición incorrecta introduciendo en el navegador una URL como/enum/test?color=Amarillo
veremos que se produce una excepción:Observad que, a diferencia de lo que podríamos esperar, la excepción no hace referencia al hecho de que el miembro
Amarillo
no pertenece al enum
, sino a que el parámetro color
no puede contener un nulo. Es decir, el framework utiliza los componentes descritos anteriormente para intentar la conversión, pero éstos retornan un nulo y, dada la firma de la acción, éste es un valor que no puede aceptarse.Para confirmarlo, sólo tenemos que utilizar un tipo anulable en el parámetro de la acción, así:
public ActionResult Test(Color? color)
...
Simplemente con esa línea ya aseguramos que la aplicación no se parará en ejecución cuando llegue un nombre incorrecto del miembro de la enumeración, simplemente deberemos controlar lo que queremos hacer en caso de que color sea nulo.
Pero un problema aún más grave tenemos cuando el valor incorrecto viene expresado en forma numérica, indicando un valor inexistente en el tipo enumerado, por ejemplo en
/enum/test?color=24
. Fijaos que el valor está fuera de los permitidos, sería equivalente a hacer lo siguiente desde código: Color color = (Color) 24;
Seguro que ya sabéis lo que ocurre en este caso: nada. A la hora de asignar valores a una variable de tipo enum
no se realiza de forma automática ningún tipo de comprobación que permita detectar que el valor no forma parte de los permitidos, por lo que la variable color
contendrá un bonito 24
que en el contexto de nuestro sistema no significa absolutamente nada :-(Y precisamente por eso decía el problema es más grave que antes, que al menos la excepción o el valor nulo en el parámetro de entrada indicaba que el valor recibido no es correcto. Si lo que nos llega es un número fuera de rango no nos enteraremos y “se colará” silenciosamente en nuestra lógica, lo que podría liar un desaguisado tremendo.
A continuación se muestra cómo podríamos gestionar en la acción la entrada de un dato incorrecto, bien sea por tratarse de un identificador inválido (que entraría un nulo) o bien un valor numérico fuera de los permitidos en la enumeración. Observad que utilizamos el método
IsDefined()
de la clase Enum
para comprobar si el valor suministrado es válido: public ActionResult Test(Color? color)
{
if (!color.HasValue || !Enum.IsDefined(typeof(Color), color))
throw new ArgumentOutOfRangeException("color");
return Content("Color: " + color);
}
Supongo que estaréis pensando, y con razón, que sería demasiado trabajo repetirlo estas comprobaciones en todas las acciones que acepten parámetros de tipo enum
, ¿verdad?Controlando los valores de entrada mediante un model binder personalizado
Sin duda, sería mejor idea aprovechar las posibilidades de extensión del framework y crear rápidamente un binder específico que sea capaz de liberar a nuestro controlador de realizar las tareas de comprobación de los parámetros de entrada de tipoenum
, como el siguiente:public class EnumBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = base.BindModel(controllerContext, bindingContext);
var type = bindingContext.ModelType;
if (value!=null && Enum.IsDefined(type, value))
return value;
throw new ArgumentOutOfRangeException(bindingContext.ModelName);
}
}
Como se observa en el código, se comprueba que el valor no sea nulo y que se encuentre entre los definidos en la enumeración, lanzando una excepción en caso contrario. Os dejo como deberes la implementación del binder que acepte enumeraciones de tipo flag, y parámetros de tipo anulable ;-)A continuación tenemos que indicar al framework que debe utilizar este model binder para las enumeraciones. Una posibilidad sería registrar en la colección
ModelBinders
una asociación para cada tipo de enumeración, algo así: ModelBinders.Binders.Add(typeof(Color), new EnumBinder());
Desafortunadamente, esta fórmula de registro de binders no funciona para jerarquías de clases; es decir, no podemos registrar un binder para la clase Enum
y que se aplique automáticamente para todas sus descendientes, por lo que si usamos muchas enumeraciones sería bastante tedioso registrar uno por uno los binders.Otra posibilidad sería utilizar los nuevos
ModelBinderProviders
, una característica introducida en ASP.NET MVC 3, que permiten introducir lógica en el momento de obtención de los binders y, por tanto, decidir qué binder queremos asignar a cada clase. El siguiente código podría ser un proveedor simple que conseguiría el efecto deseado:class MyModelBinderProvider: IModelBinderProvider
{
public IModelBinder GetBinder(Type modelType)
{
if (modelType.IsEnum)
return new EnumBinder();
return null;
}
}
Y su registro en el global.asax.cs sería así:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinderProviders.BinderProviders.Add(new MyModelBinderProvider());
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
En cualquier caso, sea cual sea la vía utilizada, una vez asociado el binder en la inicialización de la aplicación, ya controlará por nosotros la entrada de valores incorrectos para la enumeración:
public ActionResult Test(Color color)
{
// Podemos asegurar que "color" es un color válido
return Content("Color: " + color);
}
Generación de rutas hacia acciones en cuyos parámetros hay enums
Ya hemos visto cómo funciona el mecanismo de binding en acciones entre cuyos parámetros se encuentran enums, pero, ¿cómo tenemos en cuenta esta particularidad a la hora de generar enlaces o rutas hacia estas acciones?Pues la respuesta es bien simple: como si se tratara de cualquier otro tipo de datos. El siguiente código muestra la generación de enlaces hacia la acción vista anteriormente utilizando el helper
Html.ActionLink()
, primero de forma directa y a continuación utilizando T4MVC: @Html.ActionLink("Enlace a azul", "Test", "Enum", new {color = Color.Azul}, null)
@Html.ActionLink("Enlace a verde", MVC.Enum.Test(Color.Verde))
Como se puede observar, no hay que realizar conversiones ni ningún otro tipo de malabarismos, simplemente podemos utilizar elementos de la enumeración de forma directa cuando sean necesarios :-)Publicado en: Variable not found.
lunes, 11 de julio de 2011
Estos son los enlaces publicados en Variable not found en Facebook y Twitter desde el lunes, 04 de julio de 2011 hasta el domingo, 10 de julio de 2011. Espero que te resulten interesantes. :-)
Publicado en: Variable not found
- Genial!!! Eduard Tomàs: Binding de colecciones en ASP.NET MVC (y algunos comentarios) Fecha: 09/07/2011
- Gran post de Bruno Capuano: Pregunta “Porqué” como un niño, y mejorarás la gestión de tus proyectos.
Fecha: 09/07/2011 - Periodic table of HTML5 elements.
Fecha: 08/07/2011 - Object hierarchy of NULL
Fecha: 08/07/2011 - Óscar Sotorrío: Aportando un poco de coherencia en los controladores
Fecha: 08/07/2011 - jQuery UI MultiSelect Widget.
Fecha: 08/07/2011 - Repository, Code first & IoC in MVC3 (Vía Omar del Valle)
Fecha: 07/07/2011 - jQuery Proven Performance Tips And Tricks (Slides).
Fecha: 07/07/2011 - Gran post de Unai Zorrilla: Testing y EF 4.1.
Fecha: 07/07/2011 - CRUD Operation with ASP.NET MVC and EFCodeFirst Part-2.
Fecha: 06/07/2011 - Managing data in web applications with HTML5 Web Storage, by Rachel Appel.
Fecha: 06/07/2011 - Elijah Manor: "ASP.NET WebGrid - Get the Most out of WebGrid in ASP.NET MVC" ASP.NET MVC
Fecha: 06/07/2011 - Elijah Manor: "MVC Filters - Easily Add Performance Counters to Your MVC Application" ASP.NET MVC
Fecha: 06/07/2011 - jQuery 1.6.2 syntax error? You may be the victim of SEO.
Fecha: 06/07/2011 - Eduard Tomàs: Los materiales de la charla inaugural de #CatDotNet ya disponibles! ;-)
Fecha: 06/07/2011 - Real World Accessibility: HTML5, ARIA and the Modern Web.
Fecha: 06/07/2011 - Tangle: explorable explanations made easy. Vía Andrés Nieto
Fecha: 06/07/2011 - ¿Cargar jQuery desde un CDN o desde servidor? por Carlos Benítez .
Fecha: 06/07/2011 - Bin Deploy ASP.NET MVC 3 Application With SQLCE 4.0 & Entity Framework.
Fecha: 05/07/2011 - Custom Errors in ASP.NET MVC: It couldn't be simpler, right?
Fecha: 05/07/2011 - Second Nug: Evento "La revolución de las consultas... LINQ. "
Fecha: 05/07/2011 - JavaScript language advanced Tips & Tricks.
Fecha: 05/07/2011
Publicado en: Variable not found
miércoles, 6 de julio de 2011
ASP.NET MVC viene acompañado de serie por un buen número de subtipos de
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
Así, nuestro
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:
Por tanto, lo único que necesitamos para crear nuestro tipo de resultado personalizado es crear una clase que herede de
Lo que vale la pena leer está prácticamente al final de la porción de código, el método
Descargar proyecto de demostración.
Espero que os resulte interesante.
Publicado en: Variable not found.
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: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 tipoActionResult
, 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 claseZipResult
, 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 flamanteActionResult
, 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")
);
}
Para 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
.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. :-)
Publicado en: Variable not found
- C#/.NET Little Wonders: The Nullable static class.
Fecha: 01/07/2011 - jQuery 1.6.2 Released (y ya en #nuget).
Fecha: 01/07/2011 - Swiffy, herramienta en Google Labs para convertir Flash a HTML5.
Fecha: 30/06/2011 - Elijah Manor: "Manual Validation with Data Annotations" by K. Scott Allen
Fecha: 30/06/2011 - Jorge Serrano (MVP): Declaración de los using ¿dentro o fuera del namespace?
Fecha: 30/06/2011 - Eduard Tomàs: Helper.LabelFor
parametrizable en ASP.NET MVC -
Fecha: 30/06/2011 - Phil Haack: What's the diff between a ValueProvider and ModelBinder and how do I send JSON to them?
Fecha: 30/06/2011 - Google Web Fonts. Cientos de fuentes optimizadas para la web.
Fecha: 29/06/2011 - Introducción a las pseudo clases de CSS3.
Fecha: 29/06/2011 - The history of ASP.NET MVC, so far, by Simone Chiaretta.
Fecha: 29/06/2011 - 30 (New) Google Ranking Factors You May Over- or Underestimate.
Fecha: 29/06/2011 - 5 Little-Known Web Files That Can Enhance Your Website
Fecha: 29/06/2011 - Tips to Design a Website for Mobile
Fecha: 29/06/2011 - 10 HTML Entity Crimes You Really Shouldn’t Commit
Fecha: 29/06/2011 - Webcast de Hadi Hariri sobre ASP.NET MVC y arquitecturas REST.
Fecha: 29/06/2011 - Ref returns and ref locals, by Eric Lippert
Fecha: 27/06/2011 - Phil Haack: ASP.NET MVC 3 Documentation now released in 9 languages other than English
Fecha: 27/06/2011 - José Manuel Alarcón: "Direcciones MAC y cómo obtener información detallada sobre tarjetas de red con .NET."
Fecha: 27/06/2011 - Guide to CSS support in email.
Fecha: 27/06/2011 - ASP.NET MVC Project Awesome, jQuery Ajax helpers (controls) .
Fecha: 27/06/2011 - EFMVC: Demo web app using ASP.NET MVC 3, Razor, EF Code First and Unity 2.0.
Fecha: 27/06/2011 - jQMvc project: jQuery Mobile Extensions for ASP.NET MVC.
Fecha: 27/06/2011
Publicado en: Variable not found
lunes, 4 de julio de 2011
Hace 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:
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!
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!De pronto se me quitaron el calor, el sueño, e incluso las ganas de playa. ¡Vaya sorpresa! :-)))
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.
[…]
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!