Docker para el desarrollador de asp.net (iii)

En el post anterior vimos como empaquetar y desplegar en Docker una sencilla aplicación (un hello world) en asp.net core. En este post vamos a ver como desplegar en Docker una aplicación asp.net core (con sus controladores y vistas) y también ver como lo podemos usar usando una imagen base que no tenga el SDK, solo el runtime.

¡Vamos allá!

Continúa leyendo Docker para el desarrollador de asp.net (iii)

Docker para el desarrollador asp.net (ii)

Seguimos con esta sobre el uso de Docker desde el punto de vista de un desarrollador asp.net (core). En este caso vamos a construir nuestra primera imagen Docker.

Nota: Visual Studio 2017 incorpora de serie las Docker Tools que automatizan todo lo que veremos en estos artículos. Tiempo tendremos, más adelante en esta serie, de hablar de las Docker Tools. La razón de hacerlo primero todo “manual” es porque el objetivo de esta serie es ayudarte a que entiendas Docker, no presentarte el “botón mágico” que se encarga de todo. Yo, es que soy de la vieja escuela: me gusta entender las cosas (al menos hasta donde puedo).

Continúa leyendo Docker para el desarrollador asp.net (ii)

Docker para el desarrollador asp.net (i)

Buenas! Vamos a empezar una serie de posts dedicadas a Docker desde el punto de vista de un desarrollador asp.net. Empezaremos por lo más básico pero nos iremos adentrando un poco en el mundo de Docker. El objetivo es que terminemos teniendo unos conocimientos medios que nos permitan entender que es Docker, como funciona, qué ventajas tiene y como usarlo (y cuando) en arquitecturas más complejas donde haya más de un contenedor. Pero… empecemos por el principio.

Continúa leyendo Docker para el desarrollador asp.net (i)

MVC6–Recibir un GUID en el cuerpo de la petición

Hoy me he encontrado un controlador MVC6 con la siguiente acción:

[HttpPut]
[Route("{userid:int}/faceprofile")]
public async Task<IActionResult> SetFaceProfileId(int userid, [FromBody] Guid id)

Claramente su autor esperaba que pudieramos poner un Guid en el cuerpo de la petición y eso funcionaría… Pero, ¿como debe mandarse?

Continúa leyendo MVC6–Recibir un GUID en el cuerpo de la petición

Azure Functions – Serverless Backends

Últimamente se oye bastante hablar de serverless backend. Esta expresión puede sugerir implementaciones de servidor sin… servidor. Pero no, la realidad es que dicha expresión define una arquitectura en la cual no nos preocupamos para nada del servidor. Existir, existe, pero es totalmente transparente (o casi) para nosotros.

Es una astracción superior a la que ofrece un sistema PaaS. Tomemos un ejemplo de PaaS en Azure, como las web apps. Efectivamente, con una web app tenemos un nivel de abstracción relativamente alto: nos olvidamos de instalar un servidor en una máquina virtual y nos olvidamos de muchas tareas de administración. Con muy poco esfuerzo por nuestra parte podemos tener nuestra aplicación o API HTTP desplegada en una aplicación web con capacidad de escalar según sea necesario. Pero, a pesar de esas facilidades, seguimos viendo claramente un servidor: desplegamos en la webapp, configuramos la webapp, escalamos la webapp. El servidor sigue estando presente, solo que es mucho más sencillo de configurar que el sistema equivalente en IaaS u on-premise.

En un sistema tipo serverless backend, la única tarea realmente indispensable que hay que hacer es subir código y este se ejecuta de forma casi inmediata. No hay apenas configuración. No vemos cual es el servidor subyacente que ejecuta el código. El concepto de servidor “desaparece”: es nuestro código y se ejecuta. No hay que preocuparse de nada más. PaaS vino para simplificarnos la vida respecto IaaS y el serverless backend viene para simplificarla todavía más.

En Azure este paradigma se encarna mediante las Azure Functions que son exactamente lo que su nombre indica: funciones de código que se suben a Azure y se empiezan a ejecutar.

Creando una función de Azure

La creación no podría ser más sencilla, podemos codificar nuestra función directamente desde el portal de Azure.

Lo primero que debemos hacer es agregar una Function App. No es más que un contenedor donde vamos a tener todas nuestras funciones. Para ello desde el portal de Azure pulsamos agregar un nuevo elemento, tecleamos “functions” en el buscador y nos aparecerá la opción:

clip_image002

Pulsamos el botón de Create, rellenamos los datos (básicamente el nombre de nuestra function app) y ya podemos empezar.

Con esto no hemos creado ninguna azure function, solo hemos creado su contenedor. Una vez esté creado ya lo veremos dentro del resource group que hayamos elegido:

clip_image003

Si abrimos la function app (el icono con el rayo) se nos abre la interfaz para añadir funciones directamente desde el portal de Azure:

clip_image005

Lo primero que se nos pide es que tipo de función queremos añadir. Básicamente tenemos tres tipos posibles:

1. Timer: Funciones que se ejecutan basadas en un temporizador. Se pueden ejecutar cada 5 minutos, cada día a las 15 en punto o los domingos las 8 de la mañana por poner unos ejemplos.

2. Data Processing: Funciones que se ejecutan en base a triggers lanzados por otros elementos de Azure. Hay una gran variedad de triggers disponibles tales como que se cree un fichero en un storage, que llegue un evento via service bus o un elemento nuevo en una cola de Azure, entre otros.

3. Webhook + API: Funciones que se integran con APIs externas que soporten webhooks. P. ej. Github los soporta, así que sería posible hacer una función que se ejecutara cada vez que alguien comentara una issue en GitHub.

En función del escenario elegido (y del lenguaje C# o JavaScript), veremos el código inicial de nuestra función. P. ej. la siguiente captura muestra el código para una función de tipo “Data Processing”:

clip_image007

Podemos usar el propio portal para configurar los triggers que dispararán dicha función. Para ello, pulsamos sobre la opción Integrate de la barra de la izquierda, y de forma totalmente gráfica podremos configurar los triggers de nuestra función:

clip_image009

Además del trigger podemos especificar entradas opcionales para nuestra función (p. ej. un documento en una cola de Azure, un documento de DocumentDb, …) y también salidas opcionales (fichero a escribir, mensaje a mandar,). Estas entradas y salidas se reciben como parámetros en nuestra función.

Como se ha comentado el código se escribe en el portal:

clip_image011

Desde el propio portal podemos guardar la función, lo que automáticamente la compilará. La función se guarda siempre en un fichero run.csx (para el caso de C#) o index.js (para el caso de JavaScript (NodeJS)).

Por supuesto es posible usar cualquier editor para crear no solo el fichero run.csx (o index.js) y subir luego el contenido a Azure. Al subirlo, automáticamente la función se compilará y estará lista para ejecutarse. Para subir el contenido se puede usar Git o incluso FTP.

La configuración (los triggers que disparan la función, o cada cuando se ejecuta, sus entradas y sus salidas) se guarda en un fichero json. Podemos ver su contenido si pulsamos el botón “Advanced Editor” dentro de la sección “Integrate”. La siguiente captura muestra el editor gráfico:

clip_image013

Si pulsamos sobre el botón “Advanced editor” vemos el contenido del fichero json:

clip_image015

Desplegar una Azure function es desplegar el fichero run.csx (o index.js) y su fichero json de configuración. No es necesario hacer nada más. No hay que compilar nada, en caso de ser necesario la compilación ocurre en Azure.

Webjobs y Azure functions

Azure functions es una evolución de los actuales Webjobs. Muchas de las tareas que se automatizaban en Webjobs pueden automatizarse en Azure functions. La diferencia fundamental es, básicamente, de concepto. Los Webjobs son un escenario PaaS, donde el servidor (una Webapp) es claramente explícito. El webjob se despliegua de forma tradiciona y la webapp que lo contiene se configura como cualquier otra.

Una Azure function se ejecuta a través de una webapp. Se parece mucho a los webjobs, pero esto para nosotros es totalmente transparente. A pesar de que es posible hacerlo, no necesitamos por norma general acceder a la webapp subyacente. En general, las Azure functions evolucionan los webjobs y los llevan a un nuevo nivel de simplicidad.

Resumiendo

Azure functions es la implementación del paradigma serverless backend, en el cual el servidor queda difuminado hasta casi poder ser ignorado. Una Azure function es una porción de código (realmente una función) que se ejecuta como causa de un disparador (puede ser un temporizador, una acción sobre un elemento de Azure (tal como un mensaje en un service bus) o la llegada de un webhook para integrarnos con cualquier API que los soporte). La función puede realizar cualquier operación que sea necesaria (p. ej. comprimir imágenes subidas a Azure, periódicamente limpiar una tabla en una base de datos SQL Azure o cualquier otra tarea). La ejecución de una Azure function puede realizar una tarea que actúe como disparador de otra Azure function, dando lugar a escenarios complejos.

ASP.NET MVC 5–Binding de parámetros dinámicos

Estando trabajando en un proyecto con ASP.NET MVC 5 surgió la “necesidad” (impulsada por la pereza) de tener un controlador MVC (ojo, no WebApi) que recibiese datos en JSON via POST y que devolviese una vista parcial. Hasta ahí nada raro (eso se soporta de serie desde MVC3), donde la pereza intervino es que queríamos que el parámetro del controlador fuese dynamic en lugar de un tipo en concreto. Y eso, en MVC5 no está soportado. Veamos por qué y como podemos solucionarlo 😉

Nota: Todo lo dicho en este post afecta solo a MVC5. En WebApi y en MVC6 (ASP.NET Core) las cosas funcionan distinto.

Continúa leyendo ASP.NET MVC 5–Binding de parámetros dinámicos

Algunas consideraciones sobre las structs

El otro día un tweet de Juan Quijano, animó una pequeña discusión sobre la diferencia entre clases y estructuras en .NET. Este no es el primer post que escribo al respecto, pero bueno, aprovechando la coyuntura vamos a comentar algunas de las cosas que se mencionaron en el pequeño debate que generó el tweet de Juan.

Continúa leyendo Algunas consideraciones sobre las structs

C#–Buenas prácticas en constructores

Escribir el constructor de una clase es algo que parece trivial… A fin de cuentas, el constructor se encarga de construir un objeto, ¿no? Pero la realidad es que escribir constructores no es tan sencillo como parece. ¿Qué significa “construir” un objeto? Por supuesto cada clase tendrá sus propias necesidades, pero hay una serie de guías y buenas prácticas que nos pueden ayudar a tomar ciertas decisiones. A esto va dedicado este post.

Continúa leyendo C#–Buenas prácticas en constructores

WebApi 2–Leer datos desde los headers

En un curso que he impartido sobre WebApi 2 me han comentado un escenario en el que mandaban un conjunto de datos en varias cabeceras HTTP propias y querían leer esos datos desde los controladores.

La verdad es que hay varias maneras de hacer eso en WebApi 2 y vamos a analizar algunas de ellas en este post. Eso nos servirá como excusa para recorrer algunos de los mecanismos de extensibilidad del framework.

Continúa leyendo WebApi 2–Leer datos desde los headers

Atributos con comportamiento: un mal diseño

Tarde o temprano, todo desarrollador ya se de ASP.NET MVC o WebApi necesita hacer sus propios filtros para validaciones propias de peticiones, logging, comprobación de precondiciones… En fin, lo habitual para lo que se usan los filtros, vamos.

Y tarde o temprano este desarrollador se da cuenta de que su filtro debería acceder a un determinado servicio de su aplicación: quizá necesita hacer una consulta a la bbdd, o a un determinado elemento de negocio, o acceder al sistema de logging o cualquier cosa más. Y este desarrollador, que conoce (y usa) la inyección de dependencias se encuentra con que no es posible inyectar dependencias en un filtro. Algunos desarrolladores buscaran cualquier otra alternativa, algunas mejores que otras, pero ninguna satisfactoria: crear un singleton, una clase estática o instanciar directamente el objeto en lugar de obtenerlo como una dependencia (y rompiendo cualquier abstracción realizada). Otros desarrolladores continuarán en su búsqueda. En esta fase de terquedad que nos caracteriza, pensaran “no, no es posible. Tiene que ver alguna manera”.