Espero que te resulten interesantes. :-)
- Kristof Claes: Registering a namespace for all Razor views
Fecha: 10/03/2011 - Lanzado Google Chrome 10.
Fecha: 10/03/2011 - Creating PDF Documents with ASP.NET and iTextSharp.
Fecha: 10/03/2011 - José Manuel Alarcón: "Internet Information Server (IIS) Express y Visual Studio 2010 SP1"
Fecha: 10/03/2011 - MSDN Online: Visual Studio 2010 SP1 is now available for MSDN Subscribers.
Fecha: 09/03/2011 - John Katsiotis: Just blogged and uploaded a nuget package - Linked-In OAuth Library
Fecha: 09/03/2011 - Elijah Manor: "ASP.NET Sprites with MVC & Razor Helpers!"
Fecha: 09/03/2011 - Introducing Data Annotations Extensions.
Fecha: 09/03/2011 - Generating EF Code First model classes from an existing database. Via Scott Guthrie
Fecha: 09/03/2011 - DotNetCurry: "Output Caching Actions Gotcha in ASP.NET MVC 3"
Fecha: 09/03/2011 - David Ebbo: Using a custom build of MVC 3 ASP.NET MVC
Fecha: 09/03/2011 - campusMVP: ¡¡Acabamos de superar las 100.000 lecturas de nuestros artículos y libros en Scribd!! :-))
Fecha: 09/03/2011 - Interesante: Nuget package explorer.
Fecha: 09/03/2011
Publicado en: Variable not found
Publicado por José M. Aguilar a las 11:21 p. m.
Etiquetas: enlaces
Esta semana he vuelto a encontrar un ejemplo, creo que bastante ilustrativo, del fenómeno. La captura de pantalla pertenece a la herramienta gratuita Bulk Rename Utility, una utilidad imprescindible cuando necesitamos renombrar de forma masiva archivos en un directorio.
Funcionalmente, ninguna pega, más bien todo lo contrario: es potentísima, e incluso una vez la has utilizado un poco resulta hasta fácil de manejar.
Ahora bien, a nivel de interfaz la primera impresión es una auténtica agresión al usuario. De hecho, hasta los propios autores se lo toman con filosofía, como podemos leer en el primer párrafo del tutorial de su web:
“You've installed the software, you've launched it, and you now see a million and one controls and boxes on the screen. The first thing to do is DO NOT PANIC!”Pero vaya, como ya decía años atrás, el que esté libre de pecado que tire la primera piedra ;-)
Publicado en: Variable not found.
Publicado por José M. Aguilar a las 12:18 p. m.
Etiquetas: antipatrones, desarrollo, diseño, interfaces
Resulta que si utilizamos Internet Explorer en cualquiera de sus versiones todo funciona correctamente y a toda velocidad, pero la carga de páginas, imágenes y scripts en local se eterniza si estamos utilizando Firefox o Google Chrome.
Al parecer, en ambos casos se trata de un problema con la resolución de nombres del equipo en IPv6, que no es capaz de traducir de forma eficiente el nombre localhost. En Firefox se puede arreglar a nivel de aplicación, pero si queremos que todo vaya bien en Chrome habrá que modificar la configuración global del equipo.
Solución en Firefox
Si sólo queremos corregir este problema en Firefox, debemos abrir la aplicación y teclear en su barra de direcciones “about:config”. Tras ello, lo primero será confirmar nuestra decisión de acceder a la configuración de la aplicación en la pantalla donde se nos informa de los mil y un peligros a los que nos exponemos al hacerlo.A continuación en el filtro teclead “ipv6”, lo que provocará que en la lista de parámetros del sistema se quede únicamente el que nos permitirá desactivar la resolución de nombres, llamado network.dns.disableIPv6. Pues bien, en ese punto, simplemente hay que modificar su valor a true, haciendo doble clic sobre la fila:
A partir de ese momento, y una vez reiniciada la aplicación, ya podremos acceder con Firefox a nuestras aplicaciones en local a toda velocidad.
Solución en Chrome y Firefox
El truco anterior no funcionará con Chrome, donde no he visto cómo desactivar la resolución de nombres en IPv6. Sin embargo, se puede corregir el problema editando editando el archivo hosts, disponible en la carpeta \Windows\System32\drivers\etc, que debe quedar como el siguiente:Es decir, dejamos comentada con la almohadilla (#) la línea que resuelve localhost como “::1” (IPv6) y descomentamos la que lo resuelve como 127.0.0.1 (IPv4). Eso sí, ojo que poder salvar este archivo modificado debéis abrirlo con el bloc de notas o similar como administrador del sistema, en caso contrario no tendréis permisos de escritura. Una vez salvado el archivo, el problema habrá desaparecido.
Además, en este caso, dado que el cambio sobre el archivo hosts afecta a toda la máquina, también Firefox volverá a la normalidad, matando dos pájaros de un tiro, y haciendo innecesaria la utilización del primer método descrito :-)
Fuente:
Publicado en: Variable not found.
Publicado por José M. Aguilar a las 11:46 a. m.
Etiquetas: desarrollo, productividad, trucos, vs2010
Espero que te resulten interesantes. :-)
- Phil Haack: Defining default content for Razor Layout sections using a cool technique, Razor Delegates!
Fecha: 06/03/2011 - Francisco Charte: Hoy se cumplen 30 años del lanzamiento del Sinclair ZX81
Fecha: 05/03/2011 - ¿Todavía un 12% de IE6? IE6CountDown
Fecha: 05/03/2011 - jsFiddle: editor online de javascript/html/css.
Fecha: 04/03/2011 - Alternativas a Reflector
Fecha: 04/03/2011 - Gran serie sobre EF y Oracle, by Javier Torrecilla.
Fecha: 04/03/2011 - Vídeos en español sobre LightSwitch, by Jorge Serrano.
Fecha: 04/03/2011 - Html5 web storage in esence.
Fecha: 03/03/2011 - Llega EntityFramework 4.1. Post del equipo de desarrollo (en) - Vía Pablo Núñez
Fecha: 03/03/2011 - A smarter EF include method, by Nick Berardi.
Fecha: 28/02/2011 - Charles Vallance: Blogged: ASP.NET MVC 3 Email Validation with Unobtrusive jQuery Validation ASP.NET MVC
Fecha: 28/02/2011 - Phil Haack: Templated Razor delegates. A cool hidden gem of Razor.
Fecha: 28/02/2011
Publicado en: Variable not found
App_GlobalResources
para ir componiendo los interfaces.De esta forma, los literales de texto de las vistas son sustituidos por expresiones que, ya en tiempo de ejecución, son tomadas del archivo de recursos correspondiente al idioma actual:
Sin embargo, recientemente me he encontrado con un escenario en el que, para facilitar el mantenimiento de los contenidos de las vistas, me resultaba mucho más cómodo disponer de versiones distintas de las mismas en sus correspondientes archivos Razor (.cshtml), y seleccionar en tiempo de ejecución cuál de ellas debía ser enviada en función de la cultura del usuario. Eso sí, en caso de no existir una vista específica para la cultura actual, era necesario retornarla en el idioma por defecto.
Así, en este caso, asumiremos que las vistas localizadas se llamarán siempre de la forma {vista}_{idioma}. Por ejemplo, la traducción al inglés de la vista “about” estará definida en el archivo “about_en.cshtml” (usando Razor), al francés en “about_fr.cshtml”, y así sucesivamente. Por simplificar, utilizaremos sólo los dos primeros caracteres del idioma, aunque podrían ser referencias culturales completas, como “about_es-es.cshtml”.
Una vez definida la nueva convención, sólo nos falta implementar en el controlador el mecanismo de selección de vistas en función de la cultura actual. En un primer acercamiento, podríamos implementarla directamente sobre las acciones, como en el siguiente ejemplo:
public ActionResult About()
{
string currentLang = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
var viewResult = ViewEngines.Engines.FindView
(ControllerContext, "About_" + currentLang, null);
if (viewResult.View == null)
return View("About_es");
return View("About_" + currentLang);
}
Aunque funcionalmente es correcto, es fácil ver que la introducción de esta lógica contaminaría bastante el código del controlador, además de atentar contra el principio DRY en cuanto tuviéramos varias acciones en las que introducirlo. Obviamente, debemos encontrar otra solución más apropiada y elegante a esta cuestión.Y como siempre, en ASP.NET MVC existen multitud de fórmulas para resolver problemas de este tipo. En este post vamos a ver dos de ellas: extendiendo el conjunto de ActionResults, y mediante filtros personalizados.
Usando ActionResults
Empezando por el final, el resultado que vamos a lograr es el que podemos ver en el siguiente código de controlador:public ActionResult About()
{
return LocalizedView();
}
LocalizedView()
no es sino un método rápido para instanciar un LocalizedViewResult
, cuya implementación veremos a continuación. La lógica que incluye utilizará los motores de vistas para buscar una vista compuesta por el nombre indicado como parámetro (por defecto el nombre de la acción actual) y la cultura establecida en el hilo de ejecución; de no encontrarse, se mostrará la vista correspondiente a la cultura por defecto.El código de este ActionResult es el siguiente:
public class LocalizedViewResult : ViewResult
{
private string _defaultCulture;
public LocalizedViewResult(string defaultCulture)
{
_defaultCulture = defaultCulture;
}
public override void ExecuteResult(ControllerContext context)
{
string currentCulture = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
if (string.IsNullOrWhiteSpace(ViewName))
{
ViewName = context.RouteData.GetRequiredString("action");
}
var viewResult = ViewEngines.Engines.FindView(context, this.ViewName + "_" + currentCulture, null);
if (viewResult.View == null)
ViewName += "_" + _defaultCulture;
else
ViewName += "_" + currentCulture;
base.ExecuteResult(context);
}
}
Como se puede observar, el método
ExecuteResult()
obtiene el idioma actual y comprueba si existe una vista que siga la convención de nombrado que hemos definido previamente (vista_idioma.cshtml). Si se encuentra, se anexa al nombre original de la vista el sufijo del idioma; en caso contrario se actúa de la misma forma, pero utilizando el nombre por defecto.Por último, para hacer más rápido su uso desde las acciones, necesitamos implementar el método
LocalizedView()
en una clase base de la que deberíamos heredar nuestros controladores:public class ControladorBase: Controller
{
public LocalizedViewResult LocalizedView(string viewName = null, object model = null,
string master = null, string defaultLang = "es")
{
if (model != null)
{
ViewData.Model = model;
}
return new LocalizedViewResult(defaultLang)
{
ViewName = viewName,
MasterName = master,
ViewData = ViewData,
TempData = TempData,
};
}
}
Obviamente, el método
LocalizedView()
sólo podría ser utilizado desde controladores descendientes de ControladorBase
. Si preferís no heredar de un controlador base, siempre podríais crearlo como método extensor de Controller
, aunque entonces deberíais invocarlo con el this
por delante, y queda algo menos elegante.Las siguientes acciones muestran posibles usos de esta implementación. Como se puede observar, son bastante explícitas y dejan clara su intencionalidad:
public ActionResult Prueba()
{
return LocalizedView("About");
}
public ActionResult About()
{
return LocalizedView();
}
Usando filtros
Los filtros presentan una solución bastante menos intrusiva al problema y, para mi gusto bastante mejor, puesto que no obligaría a modificar la implementación tradicional de las acciones. Para hacernos una idea, lo que pretendemos conseguir es lo siguiente:[LocalizedView]
public ActionResult About()
{
return View();
}
El simple hecho de decorar una acción con el atributo LocalizedView
provocará que el retorno de la acción sea analizado, y se ejecute la lógica de selección de vistas ya descrita anteriormente. Además, el hecho de ser un filtro hace posible su aplicación a controladores completos, o incluso su aplicación global registrándolo en la inicialización de la aplicación.El código del filtro personalizado es el siguiente:
public class LocalizedViewAttribute : ActionFilterAttribute
{
private string _defaultLang;
public LocalizedViewAttribute(string defaultLang = "es")
{
_defaultLang = defaultLang;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var viewResult = filterContext.Result as ViewResultBase;
if (viewResult != null)
{
if (string.IsNullOrWhiteSpace(viewResult.ViewName))
{
viewResult.ViewName = filterContext.RouteData.GetRequiredString("action");
}
string currentLang = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
var v = ViewEngines.Engines.FindView(
filterContext.Controller.ControllerContext,
viewResult.ViewName + "_" + currentLang, null
);
if (v.View == null)
viewResult.ViewName += "_" + _defaultLang;
else
viewResult.ViewName += "_" + currentLang;
}
base.OnResultExecuting(filterContext);
}
}
En el código se puede observar que en primer lugar se comprueba que el resultado de la acción sea de tipo ViewResultBase
; en caso contrario, es decir, cuando la acción no retorne una vista, simplemente se ejecutará la lógica por defecto. A continuación, ya asumiendo que la acción retorna una vista, puede observarse la aplicación de la convención de nombrado cuando el nombre de la misma sea nulo, tomándolo de la acción actual. Finalmente, tras comprobar la existencia o no de la vista localizada, se modifica el valor de la propiedad
ViewName
del resultado, que identifica la vista que finalmente será enviada al cliente.Desde el punto de vista de la implementación de las acciones queda prácticamente igual de claro que usando la técnica del
ActionResult
, pero en cambio, ésta requiere menos andamiaje. A continuación, dos posibles ejemplos de uso de este atributo:[LocalizedView]
public ActionResult About()
{
return View();
}
[LocalizedView("en")]
public ActionResult Prueba()
{
return View("About");
}
Publicado en: Variable not found.
Publicado por José M. Aguilar a las 9:47 a. m.
Etiquetas: asp.net, aspnetmvc, desarrollo, localizacion, trucos
Espero que te resulten interesantes. :-)
- AvanadeSpain Empleo: ¿Quieres trabajar con Windows Mobile en Sevilla? Ponte en contacto con nosotros
Fecha: 25/02/2011 - campusMVP: en todos los navegadores el fantástico JSON On-Line Viewer (Si usas IE9 ponlo en modo compatibilidad)
Fecha: 25/02/2011 - Buen post! RT Eduard Tomàs: [BlogPost] Rendering de vistas parciales de MVC3 y Razor
Fecha: 25/02/2011 - Scott Guthrie: Nice post about a new DataAnnotations library on NuGet - enable even easier validation in ASP.NET MVC:
Fecha: 24/02/2011 - MongoDB con Norm, por Marc Rubiño.
Fecha: 24/02/2011 - jQuery 1.5 Cheat sheet.
Fecha: 24/02/2011 - ASP.NET MVC custom data annotation validator. Server and Client, by K. Scott Allen
Fecha: 24/02/2011 - campusMVP: 10 plugins de jQuery que te ayudarán a mejorar tus formularios
Fecha: 24/02/2011 - Phil Haack: Changing the base type of a Razor view to add your own properties
Fecha: 21/02/2011
Publicado en: Variable not found