martes, 24 de octubre de 2017

Conexión con Azure IoT Hub mediante .Net

Vamos a tomar un primer contacto con Azure IoT Hub, para lo que ‘trastearemos’ con el portal de Azure y, posteriormente, crearemos unas aplicaciones que publican información en el IoT Hub y que consumen esa misma información.

Primero un poco de información…

¿Qué es el Azure IoT Hub?

La definición oficial sería:

El Centro de IoT de Azure es un servicio totalmente administrado que permite la comunicación bidireccional confiable y segura entre millones de dispositivos de Internet de las cosas (IoT) y un back-end de soluciones. Uno de los mayores desafíos que plantean los proyectos de IoT es cómo conectar dispositivos al back-end de la solución de manera segura y confiable. Para abordar este desafío, el Centro de IoT:

  • Ofrece una mensajería confiable de gran escala de dispositivo a nube y de nube a dispositivo.
  • Habilita las comunicaciones seguras con las credenciales de seguridad de cada dispositivo y el control de acceso.
  • Incluye bibliotecas de dispositivos para las plataformas y los lenguajes más populares.

Ante esta definición, poco más se puede añadir, básicamente estamos hablando de un servicio diseñado para trabajar con datos y dispositivos del Internet de las Cosas, que al estar integrado en Azure proporciona de serie cuestiones básicas como el escalado, disponibilidad, almacenamiento… Previo pago, por supuesto.

Al turrón

Crear un centro de IoT

Lo primero que tenemos que hacer para trabajar con el IoT Hub es, como podéis imaginar, crear una instancia de IoT Hub en Azure. Para esto tendremos que seguir lo siguientes pasos:

  1. Iniciar sesión en el Portal de Azure
  2. En la barra de la derecha, seleccionamos “Nuevo”, “Internet de las cosas”, “IoT Hub”

    image
  3. En el panel de nuevo “Centro de IoT”, indicamos los datos del Hub, como el nombre (que tiene que ser único), el plan de precios, el grupo de recursos y la ubicación.
    En este punto es importante indicar que el nombre del Hub es público, por lo que lo suyo es NO utilizar ninguna información confidencial o importante para el nombre del Hub. De igual manera, al menos para pruebas, es conveniente utilizar el mismo Grupo de Recursos para todas las pruebas que hagamos con IoT, con el objetivo de poder eliminar todos los recursos de un plumazo a la que terminemos las pruebas. Al rellenar la información en este panel, nos quedaría algo como esto:

         image


    Al darle al botón “Crear”, comenzará la creación del Hub, le cuesta un poquillo, así que paciencia…
    ¡OJO! Sólo se puede tener un IoT Hub en el plan de precios gratuito por suscripción de Azure
  4. Una vez creado el Hub, si accedemos a él veremos información fundamental, como el “Nombre de host” así como el acceso al resto de propiedades del Hub, el vistazo general a toda la información disponible os lo dejo a vosotros, para poder implementar las aplicaciones de prueba tendremos que apuntarnos el “Nombre de host” y luego accederemos a “Directivas de acceso compartido”

         image

  5. En la página de “Directivas de acceso compartido” nos interesa especialmente la directiva “iothubowner”, si hacemos clic en su nombre podremos acceder a información importante, como por ejemplo la “Cadena de conexión” que utilizaremos para conectar con el Hub. Como utilizaremos luego ese valor, lo apuntamos por ahí

         image

Con esto ya hemos terminado la primera parte, no ha sido tan difícil…

Crear una identidad de dispositivo

A ver, el IoT Hub está diseñado para trabajar con dispositivos de IoT, pero una de las condiciones que tendremos que tener en cuenta es que NO podremos conectar un dispositivo a IoT Hub hasta que tenga una entrada en el registro de identidades. Lo que vamos a hacer en esta entrada es implementar un programita de consola que generará una clave y un identificador de dispositivo únicos con el que el dispositivo tendrá que identificarse al enviar mensajes a IoT Hub, el término que yo he visto más frecuentemente es “Mensajes de dispositivo a la nube

  1. En Visual Studio creamos una nueva aplicación de consola (versión mínima del Framework 4.5.1)

         image

  2. Añadimos al proyecto el paquete de NuGet “Microsoft.Azure.Devices”
  3. Creamos en la clase “Program” el método que se encargará de añadir un dispositivo al IoT Hub:

    image

    En este método utilizamos un campo de tipo “RegistryManager” definido en la clase para añadir el dispositivo o devolverlo desde el IoT Hub si ya existe.

    image

    Este objeto lo inicializamos en el método “Main”, en el que además realizamos la llamada al método “AddDeviceAsync”

    image

    Como podemos ver, estamos generando la instancia del gestor mediante una cadena de conexión (copiada desde el portal de Azure) definida en la clase.

         image

  4. Si ejecutamos la aplicación, estaremos dando de alta un dispositivo en el IoT Hub, y tendremos que apuntar la clave que se genera para el mismo:

         image

Si ahora accedemos al IoT Hub en el portal de Azure, haciendo clic en “Device Explorer” podemos observar que aparece una entrada para nuestro dispositivo, con la información necesaria para conectar con él, así como la posibilitad de deshabilitar el dispositivo:

image

Crear una aplicación de dispositivo

Para seguir entendiendo un poco cómo trabajar con el IoT Hub vamos a implementar una aplicación de consola que simulará un dispositivo enviando mensajes al IoT Hub.

  1. En Visual Studio creamos una nueva aplicación de consola (versión mínima del Framework 4.5.1)

         image

  2. Añadimos al proyecto el paquete de NuGet “Microsoft.Azure.Devices.Client”
  3. Creamos en la clase “Program” el método que se encargará de enviar mensajes al IoT Hub:

    image

    En este método utilizamos un campo “_deviceClient” definido en la clase, junto con el resto de información necesaria para la comunicación.

         image
        
    La inicialización del cliente y la llamada al método “SendDeviceToCloudMessagesAsync” las incluiremos en el método “Main”

    image

Si ahora ejecutamos este nuevo programa, veremos que se están enviando una serie de mensajes al IoT Hub, pero así “a bote pronto” no seremos capaces de ver esos mensajes, salvo que vayamos al IoT Hub en el portal de Azure y seleccionemos la operación “Metrica”

image

Crear una aplicación de recepción de mensajes

Para terminar con los ejemplos de esta entrada, vamos a implementar una aplicación de consola (sí, otra más) que estará escuchando los mensajes que se reciben en el IoT Hub. Como buen ejemplo no va a tener en cuenta minucias como seguridad, rendimiento y demás,  pero servirá de aproximación.

Los mensajes del IoT Hub se van a poder leer porque este servicio expone de manera nativa un endpoint compatible con el Event Hub de Azure, aquí podemos ver cómo servicios de Azure interactúan entre sí.

  1. En Visual Studio creamos una nueva aplicación de consola (versión mínima del Framework 4.5.1)

    image

  2. Añadimos al proyecto el paquete de NuGet “WindowsAzure.ServiceBus”
  3. Creamos en la clase “Program” el método que se encargará de recibir los mensajes del IoT Hub:

    image

    En este método utilizamos un EventHubClient con el que conectaremos al Event Hub de Azure. Este campo se define en la clase:

    image

    Y se instancia en el método “Main” haciendo uso de la cadena de conexión y el endpoint especificados:

    image

Si ahora configuramos Visual Studio para que al lanzar la ejecución se ejecuten realmente los dos proyectos de consola que hemos implementado (envío de mensajes y recepción de mensajes), veremos como conforme se van enviando mensajes al IoT Hub estos son detectados o recibidos en el otro programa:

image

Conclusiones

Como habréis visto, se trata de una primera aproximación al mundo del IoT Hub, con ejemplos en .Net de cómo trabajar con él, las posibilidades son realmente infinitas. Para finalizar me gustaría destacar la integración nativa entre el IoT Hub y el Event Hub, que sirve como “pista” de cómo funcionan los servicios de Azure interactuando entre ellos, entiendo que será raro el proyecto de Azure en el que sólo utilicemos un servicio, lo más frecuente va a ser elegir las piezas del ‘puzle’ que necesitamos y configurar las conexiones entre ellas, si no las proporcionan de manera nativa.

Esta entrada está basada en este artículo de Microsoft [acceso] y el código y demás está cogido de ahí, sin permiso de M$…

viernes, 20 de octubre de 2017

Herramienta imprescindible: Azure Storage Explorer

Cuando trabajamos con cuentas de almacenamiento de Azure, lo más lógico o normal es que en un momento dado necesitemos acceder a dichas cuentas para ver su contenido.

Desde el propio Portal de Azure no tenemos forma de ver la información almacenada en las cuentas de almacenamiento (o yo no lo he encontrado todavía) pero eso no quiere decir que no podamos hacerlo… Me consta que existen varias herramientas que permiten acceder a la información, pero ésta que os comento me ha parecido muy interesante:

El Azure Storage Explorer (en versión preliminar todavía) es una aplicación independiente que permite trabajar fácilmente con datos de Azure Storage en Windows, macOS y Linux

Esta herramienta proporciona varias maneras de conectar con las cuentas de almacenamiento. Por ejemplo, podemos:

  • Conectar con las cuentas de almacenamiento asociadas a las suscripciones de Azure.
  • Conectar con las cuentas de almacenamiento y los servicios que se comparten desde otras suscripciones de Azure.
  • Conectar con el almacenamiento local, y administrarlo, mediante el Emulador de Azure Storage.

Además, permite trabajar con cuentas de almacenamiento en nubes de Azure globales y nacionales:

En la siguiente captura podemos ver cómo tenemos acceso a las suscripciones de Azure que tengamos asignadas:

image

Y como muestra, el contenido de una cuenta de almacenamiento de tipo “Table”

image

Como podemos ver en la captura anterior, además de acceder a los datos podemos también generar consultas, ver estadísticas de la tabla e incluso manipular los datos.

Detalle de las consultas:

image

En definitiva, una herramienta imprescindible para gestionar el “Storage” en Azure. Como comento, me consta que hay más herramientas que ofrecen esta funcionalidad, pero ésta me ha parecido clara, sencilla y útil.

Enlace a la aplicación [aquí] y… con el código en GitHub [acceso]

lunes, 9 de octubre de 2017

ASP.NET CORE–Validadores

Una de las características que tenemos disponible en aplicaciones ASP.NET desde hace más tiempo del que puedo recordar es el uso de validadores (Validators) para automatizar, en mayor o menor medida, las validaciones que siempre tenemos que realizar cuando enviamos información de un formulario al servidor.

Con la llegada de JQuery y sus extensiones JQuery.Validation y JQuery.Validation.Unobtrusive, la funcionalidad que proporcionan estos validadores mejoró en sus capacidades, ya que de manera automática (hasta donde yo sé) son capaces de realizar las validaciones en cliente antes de hacer el envío o post al servidor, haciendo que el rendimiento de la aplicación web no se resienta.

Reconozco que a mí no me habían gustado nunca, ya que les veía poca funcionalidad, poca flexibilidad y… bueno, que no me convencían. He decidido darles otra oportunidad en el ámbito de ASP.NET Core, porque lo cierto es que al final es muy probable que nos ahorren tiempo.

Primero quiero empezar con una captura de los validadores estándar que podemos encontrar en una aplicación ASP.Net Core:

image

Bastante feo, ¿no?

¿Cómo funcionan?

En el post sobre localización [acceso] ya estuvimos hablando sobre los DataAnnotations así que aquí no trabajaremos con localización, de momento una pequeña explicación de cómo funciona el sistema de validadores en ASP.NET Core.

Modelo:

En el modelo especificamos qué condiciones tiene que cumplir la propiedad para ser válida:

image

En el ejemplo anterior estamos indicando que la propiedad Email es obligatoria y que tiene que ser una dirección de correo ‘bien formada’. Estos atributos (normalmente en el namespace System.ComponentModel.DataAnnotations) se encargan automáticamente de realizar validaciones sobre los valores introducidos en la vista. Cuando el envío llega al controlador, la propiedad IsValid del ModelState indicará si los valores son correctos o no:

image

Aquí podemos ver que si el modelo no es valido, directamente vuelve a cargar la página, en la que veremos los validadores aplicados como se ven en la primera captura.

He dicho antes que los validadores se ejecutan en el cliente, pero en esta pequeña explicación sólo he hablado de la parte de servidor, lo he hecho así para poder hablar de la propiedad IsValid ya que nos puede servir también para operaciones avanzadas con el modelo una vez que estamos en la parte del servidor.

Cliente:

Para poder ejecutar esos validadores en el cliente tenemos que utilizar las librerías de Javascript JQuery.Validation y JQuery.Validation.Unobtrusive, que por suerte tenemos ya disponibles cuando creamos un proyecto de ASP.NET Core en Visual Studio:

image

Además, si entramos a la vista donde utilizamos los validadores, veremos al final de la misma como los scripts necesarios se incluyen mediante una vista parcial:

image

Esto es interesante ya que si queremos incluir nuestros propios scripts de validación, si añadimos la referencia en esta vista parcial, los tendremos disponibles automáticamente en el resto de vistas donde se utilicen los validadores estándar.

Para poder utilizar los validadores tenemos que añadirlos en la vista (tiene sentido ¿no?)

image

Como podemos ver, tenemos varios atributos asp-xxx que gestionan la validación:

  • asp-validation-summary define una sección con todos los errores encontrados.
  • asp-validation-for especifica una sección donde se mostrarán los errores encontrados para la propiedad del modelo indicada (en este ejemplo Email)

¿Cómo podemos saber que la validación funciona sólo en cliente?

Esta es fácil, basta con poner un punto de ruptura en la acción del controlador y ejecutar el proyecto, si ponemos valores incorrrectos en el formulario y hacemos el Post, veremos que NO llega ninguna petición al controlador, porque no llegaremos al punto de ruptura. De hecho, si alguna vez llegáis al servidor sin que se hayan evaluado las validaciones de cliente, tenéis un problema.

¿Esto es todo?

hasta ahora, todo lo que hemos visto es el comportamiento estándar de los validadores, pero siguen quedando como ‘feuchos’. Gracias a Bootstrap podemos hacer alguna adaptación que quede un poco más elegante, algo como esto (con iconos en las cajas):

image

Peeero, si queremos algo más avanzado, como mostrar los errores en una ventana modal (algo bastante habitual por otra parte) es cuando empiezan nuestros problemas.

Al turrón

Lo primero que hacemos es crear una vista parcial en la que ponemos el código del ‘esqueleto’ de la ventana modal que queremos mostrar:

image

A continuación incluimos esta vista parcial en la vista deseada (podríamos añadirla también en el _Layout para tenerla disponible en todas las vistas de la aplicación si nos interesa)

image

Lo siguiente que tenemos que hacer es preparar un script para que ‘capture’ el submit del formulario a validar y si hay errores muestre una ventana modal. El script en cuestión podría ser algo como esto (se trata de un ejemplo, no seáis muy duros):

image

En esta función lo que hacemos es codificar el submit del formulario, lanzamos las validaciones que tenga configuradas, y si hay algún error en esas validaciones, mostramos la ventana modal evitando que se continúe con el envío del formulario. En este ejemplo nos quedamos sólo con el último error detectado, pero creo que como ejemplo es suficiente.

Por supuesto este script tendremos que añadirlo en la página, si no, pues no se iba a ejecutar…

Si a continuación probamos el funcionamiento, tendremos esto:

image

Como podéis ver en la captura se siguen mostrando los errores de los validadores por defecto, si queremos evitarlo basta con quitar los validadores de la vista, ya que en las pruebas realizadas parece que no es necesario que estén físicamente en la página para que se realice la validación.

Conclusión

Me da la sensación de que interceptar las validaciones que se realizan por defecto puede acabar dándonos algún problemilla, pero lo cierto es que si queremos hacer algo diferente a los mensajes por defecto esta sería la aproximación que yo recomendaría.

martes, 3 de octubre de 2017

ASP.NET CORE–Localización de aplicaciones

Una de las mayores ventajas que nos proporciona la plataforma ASP.NET Core es la facilidad con la que podemos acceder a ‘las tripas’ de las llamadas que se realizan, así como el soporte por defecto de inyección de dependencias.
Combinando estas y otras características, tenemos una sustancial mejora a la hora de gestionar comportamientos como el del multiidioma, localización y globalización de aplicaciones.

Introducción

La localización en ASP.NET Core es bastante similar a como funciona en ASP.NET 4.X. Por defecto definimos una serie de archivos de recursos .resx, uno para cada cultura que soportamos. Entonces podemos referenciar los recursos por clave y, dependiendo de la cultura actual, se obtiene el valor apropiado del archivo de recursos que corresponda.
Mientras el concepto de un archivo .resx por cultura se mantiene en ASP.NET Core, la manera en la que los recursos se utilizan ha cambiado significativamente. En la versión anterior, cuando añadíamos un archivo .resx a nuestra solución, se generaba automáticamente un archivo “designer” que proporcionaba acceso a los recursos de una manera directa (static strongly typed access) mediante llamadas del tipo “Resources.MyTitleString”.
En ASP.NET Core, los recursos se acceden a través de dos abstracciones, IStringLocalizer y IStringLocalizer<T>, que se ‘preparan’ cuando son necesarias mediante la “inyección de dependencias”. Estos interfaces proporcionan un indexador que permite acceder a los recursos por clave. Si no existe un recurso para la clave especificada, el sistema utiliza la propia clave como valor del recurso.
La idea detrás de esta nueva aproximación es permitir que la aplicación se diseñe desde el principio para ser “localizable” sin que sea necesario crear todos los archivos de recursos al inicio. Así podemos simplemente utilizar los valores por defecto como claves y añadir los distintos archivos de recursos a posteriori.
Indudablemente se trata de una opción muy interesante, pero lógicamente tiene un problema relativamente serio, ya que al no tener acceso ‘tipado’ a los recursos se puede dar el caso de que sin querer cambiemos uno de esos literales / claves y entonces perdemos el vínculo con su recurso. Entiendo que es muy probable que al final cojamos costumbre de trabajar de esta manera, aunque me da la sensación de que también es muy posible que tengamos ‘dificultades’ para detectar en un momento dado qué tenemos traducido y qué no… Lo mejor entiendo que será aprovechar las ventajas de la nueva gestión de la localización, pero trabajando desde el principio con los archivos de recursos necesarios en la aplicación.

Al turrón

Todo esto es muy bonito (o lo parece) pero, ¿cómo se hace?

Añadir localización a una aplicación

El primer paso es añadir los servicios de localización a nuestra aplicación. En este caso, como estamos trabajando con una aplicación MVC, configuraremos también localización para las Vistas e incluso para los “DataAnnotations”. En ASP.NET Core añadimos estos servicios en el método “ConfigureServices” de la clase “Startup
image
En la captura anterior podemos observar cómo añadimos los servicios de localización para los tres elementos que hemos comentado; como punto interesante indicar que al especificar un “ResourcesPath” le estamos diciendo al motor dónde se ubicarán los archivos de recursos (en este caso en una carpeta “Resources”.
Al añadir estos servicios tenemos la posibilidad de inyectar las abstracciones que hemos comentado en la parte de la introducción, así como una especialización de ellas que permite trabajar con vistas “IViewLocalizer”.
Con estas instrucciones ya podríamos utilizar localización en nuestra aplicación, pero el sistema nos queda cojo ya que no hemos hecho nada para que las peticiones a la aplicación utilicen la cultura…
Para manipular estas peticiones configuraremos el middleware “RequestLocalizationMiddleware”. Este middleware utiliza una serie de proveedores para determinar la cultura actual, estos proveedores de definen en el método “ConfigureServices” de la clase “Startup
image
En la captura anterior tenemos un ejemplo de cómo generar una lista con las culturas que ‘soporta’ la aplicación y aplicar una cultura por defecto. Una vez aplicada esta configuración tenemos que añadir el middleware de localización, que se hace en el método “Configure” de la clase “Startup”.
image
Lo que hacemos en este método es obtener el servicio que hemos registrado anteriormente y lo utilizamos para indicar que lo queremos utilizar para la localización de las peticiones.

Utilizar localización en controladores y servicios

Cuando necesitemos acceder a texto localizado en servicios o controladores, lo primero que tendremos que hacer es inyectar In “IStringLocalizer<T>” en la clase y utilizar el indexador proporcionado para obtener el valor del texto:
image
Como ya hemos explicado, en el constructor del controlador inyectamos la dependencia para el “localizer” y en la “acción” Index accedemos al recurso “Título de la aplicación en castellano”. Si ahora accedemos a la página de inicio de la aplicación, veremos que aparece el texto que hemos utilizado como ‘índice’ (como hemos comentado antes, si no existe una entrada con la clave indicada, dicha clave se utiliza como texto ‘de vuelta’:
image
Ahora sería buen momento para añadir el archivo de recursos para un idioma adicional… Si partimos del hecho de que el idioma por defecto de nuestra aplicación será el castellano y viendo cómo funciona la localización en ASP.NET Core, podríamos asumir que NO necesitamos archivo de recursos para castellano, por lo que directamente crearemos el archivo de recursos para el resto de culturas configuradas, por ejemplo como se ve en las capturas anteriores, inglés.
En la parte de configuración hemos indicado que los archivos de recursos van en una carpeta “Resources”, que ASP.NET Core intenta encontrar en el raíz de nuestra aplicación, con lo que tendremos que crear dicha carpeta. a continuación, el sistema de ‘localización’ buscará el archivo de recursos correspondiente a la clase en la que estamos (HomeController), para ello por convención buscará una carpeta “Controllers” y dentro de ella el archivo de recursos (HomeController.en.resx), o también puede buscar un archivo de recurso con un nombre según este patrón: Controllers.HomeController.en.resx. Yo recomiendo la primera estructura de carpetas, lo que nos lleva a esta captura:
image
En esta carpeta crearemos el archivo de recursos (HomeController.en.resx) y en él añadiremos la entrada correspondiente a la clave que hemos utilizado anteriormente:
image
Como veréis, Visual Studio se “queja” de la clave que hemos utilizado, incluso es posible que aparezca un error en el panel de “Error List” pero por lo visto se trata de un problema del propio Visual Studio y no afecta a la compilación del proyecto. Sí, es un inconveniente…
image

Utilizar localización en Vistas

En el caso de las vistas, en lugar de ‘inyectar’ un “IStringLocalizer<T>” haremos lo propio con un “IViewLocalizer”. Este componente utiliza un patrón idéntico al que hemos visto en el caso anterior para encontrar los archivos de recursos, pero utilizando la estructura de vistas existente. por ejemplo para crear un archivo de recursos para una vista “Index.cshtml” que está en una carpeta “Home” tendríamos la siguiente estructura de carpetas:
image
Dentro de esta carpeta crearemos un archivo de recursos con el mismo nombre que la vista, como por ejemplo Index.en.resx:
image
La inyección del “IViewLocalizer” se realiza en la vista con la instrucción @inject”:
image
Como podemos ver en la captura, necesitamos importar el namespace para el interfaz, y con la instrucción @inject” generamos una propiedad “Localizer” mediante la cual accedemos al recurso.
image

Utilizar localización en ViewModels

Otro de los puntos que normalmente queremos localizar serán literales de posibles mensajes de error o advertencia que mostramos en las clases del “ViewModel”, por ejemplo a través de atributos de “DataAnnotation”. El mecanismo es análogo a los que hemos explicado anteriormente, el archivo de recursos estará en una subcarpeta de este estilo: “Resources/ViewModels/HomeViewModel.en.resx” y el uso en atributos iría así:
image
En el ejemplo vemos qué claves queremos localizar, el sistema los mapeará de manera automática.
image

Permitir a los usuarios elegir una cultura

Hasta ahora hemos estado hablando de localizar una aplicación ASP.NET Core, pero todo esto no sirve de nada si no disponemos de un mecanismo que permita al usuario cambiar el idioma de la aplicación… Hombre, sí que sirve si lo que queremos es basarnos en el idioma del navegador, pero ya que tenemos una aplicación multiidioma, pues vamos a aprovechar, ¿no?
El middleware que hemos configurado para activar la localización (recuerda, el RequestLocalizationMiddleware) ofrece un mecanismo extensible de proveedores de ‘cultura’ y además viene con tres proveedores por defecto:
  • QueryStringRequestCultureProvider: Especificar la cultura en la QueryString, por ejemplo ?culture=en
  • AcceptLanguageHeaderRequestCultureProvider: Especificar la cultura en el encabezado de la petición (mediante Accept-Language)
  • CookieRequestCultureProvider: Especificar la cultura mediante una Cookie.
En esta entrada vamos a probar el tercer proveedor, ya que parece que tiene más sentido utilizar cookies para este tema, ¿verdad?
Para permitir al usuario cambiar de idioma vamos a crear el equivalente a un control de usuario ascx en ASP.NET Core (o así lo entiendo yo) así que utilizaremos una vista parcial, _SelectLanguagePartial.cshtml en la carpeta Shared de las vistas:
image
En la captura anterior hay mucha tela que cortar, pero por intentar resumir un poco los pasos, tendríamos:
  1. Inyectamos el objeto para la localización (IViewLocalizer)
  2. Inyectamos el objeto donde hemos almacenado las opciones de la localización (IOptions<RequestLocalizationOptions>)
  3. Obtenemos la cultura de la petición, así como las distintas culturas que tenemos disponibles, estas últimas en una lista de objetos SelectListItem para poder utilizarlas en un combo con el que el usuario podrá cambiar el idioma de la aplicación (toda la sección HTML de la parte inferior)
Una vez diseñada la vista parcial tenemos que añadirla en las páginas deseadas (normalmente querremos el cambio de idioma en todas las páginas, así que podemos utilizar la vista _Layout.cshtml), para añadirla utilizaremos el método HTML.PartialAsync:
image
Para terminar, necesitamos implementar el código de controlador que realizará el cambio de idioma, acción “SetLanguage” del controlador “HomeController” como se puede ver en la captura del control de cambio de idioma.
image
En este código podemos ver cómo añadimos la cookie por defecto para el idioma en la colección de la respuesta y como (en este ejemplo) establecer un año de validez a la cookie.
¿Cómo queda el control de cambio de usuario?
Pues en esta ocasión quedaría así:
image
Si cambiamos el idioma en el combo y hacemos clic en “Guardar”, podemos ver cómo los literales se cogen de los distintos archivos de recursos.

Conclusiones

A ver, es mucho más sencillo ‘localizar’ aplicaciones en ASP.NET Core, pero, no por ser más sencillo estamos ‘aprueba’ de errores, algunos de los más típicos:
  1. Clave del recurso incorrecta (o modificada): Como este sistema no requiere que los archivos de recursos estén generados, y no tenemos tipado fuerte, se puede dar el caso de que al corregir, por ejemplo, una falta ortográfica en uno de los textos, se nos olvide modificar el texto también en los archivos de recursos… Resultado, no hay traducción.
  2. Ruta de los archivos de recursos: Por convención, el acceso a los archivos de recursos se realiza en función del Namespace de las clases donde vamos a utilizarlos, es un poco raro, pero si en algún momento veis que no está cogiendo traducciones, revisad por favor la ruta del archivo de recursos (y por supuesto como he puesto en el punto anterior, el nombre de la clave)
Creo que todavía tiene margen de mejora, pero lo cierto es que olvidarnos de establecer el CurrentCulture, la Cookie y demás, resulta ummm, cómodo.

Nota final

Si alguien se lo está preguntando, no he hecho ninguna prueba con el comportamiento de este mecanismo con controles tipo “Kendo”… No me chilléis, por favor.