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!
lunes, 21 de marzo de 2011
Web Camps 2011: Make Web, not WarDurante las próximas semanas estaré de gira participando como ponente en los Web Camps que se celebrarán en cinco ciudades del país, bajo el lema “Make Web Not War”.

En estos eventos, como se puede ver en la agenda, se tratarán temas relacionados con tecnologías y desarrollo para la web:
  • Migración a HTML5
  • IE9 para desarrolladores
  • Buenas prácticas en la detección de navegadores
  • El poder de los CMS
  • ASP.NET MVC 3
El itinerario previsto es:
  • Barcelona, 22 de marzo
  • Valencia, 24 de marzo
  • Bilbao, 29 de marzo
  • Sevilla, 31 de marzo (hey, juego en casa! ;-))
  • Madrid, 5 de abril
Si estáis interesados en asistir, sólo tenéis que ir a la web oficial de la gira, e inscribiros en la ciudad más cercana. En la misma página encontraréis información sobre los horarios y ubicación exacta del evento.

¡Espero veros por allí! :-)

Publicado en: Variable not found.
domingo, 20 de marzo de 2011
Estos son los enlaces publicados en Variable not found en Facebook y Twitter desde el lunes, 14 de marzo de 2011 hasta el domingo, 20 de marzo 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: www.variablenotfound.com.
martes, 15 de marzo de 2011
ASP.NET MVCComo sabemos, en MVC 2 y MVC 3 el atributo [DisplayName] nos permite especificar en cada propiedad de las entidades del Modelo un nombre descriptivo que, entre otras cosas, es utilizado como etiqueta en formularios si empleamos el helper Html.LabelFor().

Así, dada una clase del Modelo como la siguiente:
public class Persona
{
    [DisplayName("Nombre completo")]
    public string Name { get; set; }
 
    [DisplayName("Edad actual")]
    public int Age { get; set; }
}
si implementamos una vista de edición sobre ella similar a la mostrada a continuación, vemos el resultado que obtendríamos en tiempo de ejecución:

Vista de edición y resultado en tiempo de ejecución
Este mecanismo resulta muy cómodo y útil la mayoría de las veces, sin embargo, cuando estamos desarrollando sitios multiidioma, rápidamente vamos a encontrarnos con que este enfoque no es suficiente, puesto que asocia una única descripción textual a la propiedad independientemente de la cultura activa.

A diferencia de otros atributos como las anotaciones de validación, DisplayName no incorpora ninguna forma para indicar una referencia hacia el recurso localizado, es decir, identificar el tipo (la clase) que representa al archivo de recursos (.resx) donde se encuentra la traducción del término, así como la propiedad o clave en la que lo encontraremos. Por ejemplo, el data annotation [Required] permite hacerlo de la siguiente forma:
[Required(
    ErrorMessageResourceName="NombreObligatorio", 
    ErrorMessageResourceType=typeof(Resources.Textos)
)]
public string Name { get; set; }
Ahora bastaría con crear la carpeta App_GlobalResources un archivo de recursos llamado “Textos.resx” (obviamente el nombre puede ser cualquiera, siempre que coincida con el referenciado en el parámetro ErrorMessageResourceType anterior), e introducir en él la clave “NombreObligatorio” con su correspondiente valor. Para añadir la traducción al inglés, bastaría con hacer lo mismo sobre el archivo Textos.en.resx, y así sucesivamente.

Archivos de recursos

Afortunadamente, a partir de ASP.NET MVC 3 podemos utilizar la anotación Display, disponible en System.ComponentModel.DataAnnotations a partir de la versión 4 del framework, de la siguiente forma:
[Display(Name="Nombre", ResourceType=typeof(Resources.Textos))]
public string Name { get; set; }
Como podréis intuir, el parámetro Name indica la clave del recurso incluido en la clase especificada en ResourceType.

Sin embargo, el uso de este atributo requiere que los elementos del archivo de recursos sean de acceso público, y no interno, como son por defecto cuando creamos los .resx en App_GlobalResources. Si no tenemos en cuenta este aspecto, podemos encontrarnos con un error como el siguiente:

Cannot retrieve property 'Name' because localization failed.  Type 'Resources.Textos' is not public or does not contain a public static string property with the name 'Nombre'.

Ante este error, tenemos varias fórmulas para conseguir acceso a los recursos localizados:
  • la primera de ellos a lo bestia, accediendo a la clase generada desde el archivo de recursos (por ejemplo Textos.Designer.cs) y cambiando los modificadores de la clase y sus miembros de “internal” a “public”. Obviamente, este cambio sólo nos vale hasta que se vuelva a generar el código , cosa que ocurrirá al modificar o añadir nuevas cadenas de texto, por lo que no es nada recomendable.
  • otra, sacar los recursos de la carpeta App_GlobalResources y moverlos a cualquier otra carpeta del proyecto (por ejemplo, /Recursos). Tras ello, en las propiedades del archivo .resx podemos modificar la “Herramienta personalizada” y establecerla a “PublicResXFileCodeGenerator” para asegurar su acceso público.
  • una última sería crear ensamblados satélite, lo cual requiere la añadir un nuevo proyecto de biblioteca de clases en la solución, en el que introduciremos exclusivamente los archivos de recursos localizados.
Pero si ninguna de ellas nos convence, o bien estamos todavía trabajando con MVC 2 y .NET 3.5SP1, todavía tenemos otra posibilidad:

[LocalizedDisplayNameAtribute]

Es realmente sencillo implementar un atributo que nos permita conseguir algo parecido a lo descrito anteriormente. Simplemente heredando de DisplayNameAttribute y sobrescribiendo su propiedad DisplayName podemos hacer que su valor sea tomado desde los recursos de la aplicación:
public class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
    private readonly string _resourceName;
    public LocalizedDisplayNameAttribute(string resourceName)
    {
        _resourceName = resourceName;
    }
 
    public override string DisplayName
    {
        get { return Resources.Textos.ResourceManager.GetString(_resourceName); }
    }
}
Archivos de recursosObservad que para simplificar la sintaxis de uso y su implementación, estamos asumiendo que los recursos se encuentran en Resources.Textos, la clase generada automáticamente a partir del archivo Textos.resx.

De esta forma, ahora decoraremos las propiedades del modelo no con el texto que queremos que aparezca en pantalla, sino con la clave del recurso, y dado que la clase de recursos está definida en el atributo, no será necesario indicarla:
public class Persona
{
    [LocalizedDisplayName("Nombre")]
    public string Name { get; set; }
 
    [LocalizedDisplayName("Edad")]
    public int Age { get; set; }
}
Y por si os resulta de interés, he dejado un proyecto de demostración de este atributo en Skydrive.

Publicado en: Variable not found.
domingo, 13 de marzo de 2011
Estos son los enlaces publicados en Variable not found en Facebook y Twitter desde el lunes, 07 de marzo de 2011 hasta el domingo, 13 de marzo 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, 9 de marzo de 2011
Hace muchos, pero muchos, años ya comenté por aquí un buen ejemplo de lo que ocurre cuando un desarrollador diseña el interfaz de usuario de una aplicación. También, ya más recientemente, profundizaba en este curioso tema en el post titulado Indicios de que tu interfaz de usuario fue creado por un programador.

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.

Bulk rename utility
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.
martes, 8 de marzo de 2011
Explorer-Firefox-ChromeYoy a comentar un problema que llevaba arrastrando meses, y que es realmente sencillo de solucionar. En este caso, se trata de un inconveniente muy molesto que encontramos cuando estamos depurando sitios web desde Visual Studio utilizando el servidor integrado (Cassini), en Windows 7.

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.

about:configSolució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:

Deshabilitando la resolución de nombres para IPv6

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:

Archivo hosts

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.