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 ;)

19 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, 20 de enero de 2020
Enlaces interesantes Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 14 de enero de 2020
ASP.NET Core Las Razor Class Libraries (RCL) constituyen una interesante fórmula para crear componentes redistribuibles de interfaz de usuario para aplicaciones basadas en ASP.NET Core MVC o Razor Pages. En las bibliotecas de clases de este tipo podemos incluir controladores, view components, tag helpers o vistas y páginas Razor, elementos que estarán disponibles en las aplicaciones que las referencien, bien directamente o bien a través del paquete NuGet en el que las distribuyamos.

Sin embargo, es menos conocido el hecho de que estas bibliotecas pueden incluir también recursos estáticos como imágenes, hojas de estilo o scripts, lo que resulta bastante interesante a la hora de crear componentes totalmente autosuficientes y muy reutilizables.

En este post vamos a ver cómo crear una RCL redistribuible que definirá el tag helper <mario>, cuya inclusión en una página hará que ésta muestre el conocido personaje correteando por la pantalla, como se muestra en la siguiente captura:

Mario corriendo por la pantalla
lunes, 13 de enero de 2020
Enlaces interesantes Ahí van un buen puñado de enlaces recopilados durante las semanas anteriores. Como siempre, espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 7 de enero de 2020
Lo más visto en 2019
Estrenamos este nuevo año y década (aunque esto último es bastante más discutible) siguiendo una de las grandes tradiciones de este blog: dedicar el primer post a repasar cuál fue el contenido publicado durante los doce meses anteriores que más os llamó la atención.

Pero antes, abusando de este pequeño slice de atención que me estáis prestando en este momento, quería aprovechar para desearos un 2020 repleto de salud y alegría, tanto en el plano personal como en el profesional.

Y ahora, al turrón...
sábado, 28 de diciembre de 2019
Un reciente estudio de la consultora Garner indica que durante el desarrollo de una aplicación dedicamos más del 80% de nuestro tiempo a implementar controles de posibles fallos.

Además, este otro informe de StackOverflow obtenido tras analizar el código fuente de miles de proyectos open source, el control y tratamiento de excepciones y problemas supone más del 60% de nuestra base de código y, por tanto, aporta gran parte de la complejidad interna de las aplicaciones.

Pero, adicionalmente, estos estudios ponen al descubierto otros tres aspectos bastante interesantes:
  • Primero, que la mayoría de errores que intentamos controlar no se van a producir nunca. Son posibles a nivel de flujo de código, pero en la operativa de la aplicación no ocurrirán, por lo que podríamos decir que son problemas creados artificialmente durante el proceso de desarrollo.
     
  • Segundo, las líneas de control de errores no están exentas de problemas, por lo que muy a menudo encontraremos en ellas nuevo código de control (¿quién no ha visto try/catch anidados a varios niveles?), por lo que la bola de nieve no para nunca de crecer: código de tratamiento de errores que a su vez contiene código de tratamiento de errores, y así hasta el infinito.
     
  • Y por último, también nos encontramos con que en muchas ocasiones el código de control no hace nada. Por ejemplo, se cuentan por millones las líneas de código detectadas en Github cuyo tratamiento de excepciones consiste simplemente en la aplicación a rajatabla del Swallow Design Pattern, por ejemplo, implementando bloques catch() vacíos.
Y conociendo estos datos, ¿por qué dedicamos tanto tiempo a la gestión de errores en nuestro código? Pues básicamente porque hemos sido educados para eso. Exceptuando cuando se nos cala el coche, no hay nada que suponga un golpe al ego tan importante como cuando una de nuestras aplicaciones falla, y por eso no escatimamos recursos a la hora de evitarlo.

¿No estaría bien poder ignorar esos problemas y centrar nuestro código en aportar valor a nuestros clientes?
lunes, 23 de diciembre de 2019
Feliz Navidad! En primer lugar, quería desearos a todos unas felices fiestas; como debe ser, espero que descanséis y aprovechéis para pasar estos días disfrutando de la familia y amigos. Y ya puestos, espero también que el 2020 sea un gran año para todos.

Pero al hilo de estas fiestas, por si alguno no estáis al tanto, me ha parecido interesante aprovechar la ocasión para contaros un curioso cuento de navidad: la que se ha liado hace unos días en el repositorio de Visual Studio Code en Github, algo que algunos ya han denominado el "SantaGate".
Enlaces interesantes
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 17 de diciembre de 2019
gRPC logo
Días atrás veíamos lo sencillo que resultaba crear un servicio gRPC que hacía uso de streaming unidireccional de mensajes, en sentido servidor-cliente. Como recordaréis, en este post implementábamos un servicio generador de números al que los clientes podrían conectarse para recibir una secuencia de enteros a intervalos periódicos.

Servicio de streaming unidireccional en ejecución

Hoy vamos a complicar algo el escenario, pues veremos una opción aún más potente: la creación de streaming bidireccional, es decir, cómo cliente y servidor pueden enviar mensajes al lado opuesto de forma asíncrona, una vez establecida la comunicación entre ambos.

Para ello, implementaremos un sencillo juego, con las siguientes funcionalidades:
  • El lado cliente, una aplicación de consola, abrirá una conexión con el servicio. En ese momento, el servidor elegirá un número al azar (1-100) y lanzará un mensaje de bienvenida, que deberá ser mostrado en el lado cliente.
  • Desde el lado cliente solicitaremos al usuario un número entero, que enviaremos al servidor por el stream ascendente.
  • El servidor recibirá el número y lo comparará con el que tiene almacenado, enviando por el canal descendente el resultado de la comparación.
  • El proceso finalizará cuando el número sea encontrado.
lunes, 16 de diciembre de 2019
Enlaces interesantes
Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

miércoles, 11 de diciembre de 2019
gRPC logo
Hace bien poco hablábamos de la introducción en .NET/C# de la interfaz IAsyncEnumerable, y de las interesantes posibilidades que abría vistas a la producción y consumo de streams de mensajes.

También hace unos días dimos un repaso al soporte para la implementación de clientes y servidores gRPC lanzado con ASP.NET Core 3. En dicho post hacíamos una pequeña introducción al desarrollo de este tipo de servicios, basados en HTTP/2 y el estándar protobuf.

Como ya comentábamos entonces, a diferencia de los tradicionales servicios tipo REST (HTTP/JSON), gRPC soporta el intercambio de datos en modo streaming, tanto unidireccional como bidireccionalmente. Es decir, en el escenario más complejo podríamos abrir un canal gRPC a través del cual un cliente podría ir enviando paquetes de información de forma asíncrona, y al mismo tiempo utilizarlo para recibir un flujo de datos continuo desde el servidor.

Hoy vamos a ver cómo se combinan estas características viendo un ejemplo de implementación de un servicio gRPC que utiliza streaming unidireccional, en sentido servidor-cliente.

Para ello crearemos un servicio generador de números en streaming que funcionará de la siguiente forma:
  • Los clientes invocarán un procedimiento del servidor suministrándole un número entero inicial y un delay expresado en segundos.
  • Como respuesta, el servidor creará un stream por el que irá enviando, según la periodicidad indicada, números consecutivos partiendo del especificado en la llamada inicial.
  • El proceso finalizará, cerrando en stream, cuando el servidor haya generado 10 números, o bien cuando el cliente sea detenido.
martes, 10 de diciembre de 2019
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 3 de diciembre de 2019
.NET Core Hace poco estaba revisando un proyecto y me topé con un problema derivado de un uso extraño de los expression bodied members, y creo que es interesante comentarlo porque, aunque probablemente la mayoría no os vayáis a encontrar con esto, seguro que puede venir bien a alguien que no tenga del todo claro cómo y cuándo se debe utilizar esta sintaxis.

Pero comencemos desde el principio...
lunes, 2 de diciembre de 2019
martes, 26 de noviembre de 2019
ASP.NET CoreHace ya algún tiempo nos preguntábamos que dónde había ido a parar la directiva @helper de Razor en ASP.NET Core, y la respuesta era simple: había desaparecido.

Como recordaréis, esta directiva era bastante útil para simplificar el código de las vistas y mejorar su legibilidad, pues permitía crear funciones reutilizables que mezclaban HTML y código de servidor, como en el siguiente ejemplo:
@* File: Test.cshtml *

@Multiplication(2)
@Multiplication(3)

@helper Multiplication(int x)
{
    <h2>Multiplication table of @x</h2>
    <ul>
        @for (var i = 1; i <= 10; i++)
        {
            <li>@x * @i = @(x * i)</li>
        }
    </ul>
}
Hasta la versión 2.2, teníamos que conformarnos con apaños como los descritos en aquél post si queríamos emular lo que llevábamos tantos años utilizando con MVC 5 y anteriores. Y también entonces comentamos que había ciertas posibilidades de que en algún momento volviera a la vida, y éstas se han materializado, por fin, en ASP.NET Core 3.0.

Aunque quizás más bien habría que hablar de reencarnación...
lunes, 25 de noviembre de 2019
Enlaces interesantes Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 19 de noviembre de 2019
Entity Framework Core Hace algunos meses hablábamos del peligro que suponía la la evaluación en cliente de Entity Framework Core, una característica que, por defecto, venía activada de serie. En el post explicábamos los problemas que podían dar, cómo podíamos detectar su uso e incluso impedirlo para evitar males mayores.

Pues bien, esto ha cambiado a partir de la versión 3.0, en mi opinión, hacia una dirección bastante más correcta. Veamos en qué consisten estos cambios.
lunes, 18 de noviembre de 2019
Enlaces interesantes Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 12 de noviembre de 2019
ASP.NET Core MVCUn alumno del curso de ASP.NET Core 3 en CampusMVP, me preguntaba hace unos días qué había pasado con la llamada al método SetCompatibilityVersion() que veíamos en la plantilla de proyectos ASP.NET Core MVC y Razor Pages desde la versión 2.1:
public void ConfigureServices(IServiceCollection services)
{
   services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
Esta llamada era incluida de serie en los nuevos proyectos ASP.NET Core desde la versión 2.1, pero en la versión 3.0 ya no aparece. Y probablemente también os llame la atención a quienes ya habéis trabajado con ASP.NET Core 2.x, así que he pensado que sería interesante comentarlo por aquí.
lunes, 11 de noviembre de 2019
Enlaces interesantes Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 5 de noviembre de 2019
gRPC logo Como seguro sabréis, gRPC lleva ya algún tiempo proponiéndose como sustituto de las APIs HTTP/REST en determinados escenarios, y ASP.NET Core 3.0 incluye de serie soporte para esta tecnología.

En este post echaremos un vistazo a gRPC y su uso en la nueva versión del framework.
lunes, 4 de noviembre de 2019
martes, 29 de octubre de 2019
Fiddler Si soléis utilizar Fiddler para probar APIs, probablemente os resultará algo molesto el hecho de que al arrancarlo directamente comience a capturar todas las peticiones salientes desde vuestro equipo.

Pues bien, tras años sufriendo esto en silencio, he decidido invertir unos minutos a ver si existía una forma de ahorrarme los dichosos segundos que tardaba en desactivar la captura de tráfico cada vez que abría la herramienta.
Fiddler capturando peticiones

Y como efectivamente es posible, os dejo la forma de conseguirlo por si hay por ahí algún perezoso más al que pueda interesarle ;)

lunes, 28 de octubre de 2019
Enlaces interesantes Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 22 de octubre de 2019
.NET Core Hasta ahora, la generación o enumeración de secuencias era un proceso puramente síncrono. Por ejemplo, si queríamos recorrer un IEnumerable con un bucle foreach, cada uno de los elementos debía existir previamente en la colección o bien ser generado de forma síncrona.

Por ejemplo, en el siguiente código no teníamos una forma razonable de implementarlo si la obtención de cada uno de los valores retornados desde el método generador tuviera que ser asíncrona:
foreach (var i in GetNumbers())
{
    Console.WriteLine(i);
}

IEnumerable<int> GetNumbers()
{
    for (var i = 0; i < 1000_000_000; i++)
    {
        var a = i * 2;   // <-- Esto es una operación síncrona,
        yield return a;  //     ¿cómo haríamos si en lugar de esta operación síncrona
                         //     necesitásemos hacer una llamada asíncrona para obtenerlo?
    }
}
Aunque convertir el método GetNumbers() en asíncrono pudiera parecer una alternativa razonable, en realidad no lo es; de hecho, los resultados no llegarían al cliente hasta que hubiéramos generado todos los valores, por lo que sería peor que la primera opción en términos de rendimiento y ocupación de memoria:
foreach (var i in await GetNumbersAsync())
{
    Console.WriteLine(i);
}

async Task<IEnumerable<int>> GetNumbersAsync()
{
    var list = new List<int>();
    for (var i = 0; i < 1000_000_000; i++)
    {
        var a = await Task.FromResult(i * 2); // <-- Aquí generamos los valores usando asincronía,
        list.Add(a);                          //     pero el consumidor seguirá esperando hasta
                                              //     que los hayamos generado todos.
    }
    return list;                              // <-- Aquí retornamos la colección completa
}
En este último caso la llamada a GetNumbersAsync() se ejecutaría de forma asíncrona, es decir, daríamos la oportunidad al hilo de ejecución actual de dedicarse a otros menesteres mientras la llamada es realizada, desde el punto de vista de su consumidor es a todos los efectos como si se tratara de un método síncrono.

Pues bien, aparte de características mainstream como la implementación por defecto en interfaces, los tipos referencia anulables, índices y rangos o muchas otras, en la última versión del framework y C# 8 se ha introducido el soporte para la generación y consumo de secuencias asíncronas.
lunes, 21 de octubre de 2019
Enlaces interesantes Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

martes, 15 de octubre de 2019
.NET Core Seguimos descubriendo perlas en C# 8 que nos harán la vida algo más sencilla a los desarrolladores. En este caso, se trata de una pequeña adición al lenguaje que nos permitirá hacer más claras y concisas determinadas expresiones condicionales.

Para ponernos en situación, imaginemos que tenemos una expresión como la siguiente, donde retornamos el texto "Rojo" cuando le suministramos el valor de enumeración Color.Red, y "Desconocido" en otros casos. Algo fácil de solucionar utilizando el operador condicional ?:
enum Color { Purple, Red, Blue, Orange, Black, Pink, Gray, Green, White };
string GetColorName(Color color)
{
    var str = color == Color.Red ? "Rojo" : "Desconocido";
    return str;
}
Imaginemos ahora que la aplicación evoluciona y debemos añadir otro caso a esta condición, como el soporte para el color azul. No pasa nada, podemos seguir el mismo patrón, aunque empezaremos a notar que esto no va a escalar demasiado porque la legibilidad empieza a resentirse:
var str = color == Color.Red ? "Rojo" : color == Color.Blue ? "Azul" : "Desconocido";

lunes, 14 de octubre de 2019
Enlaces interesantes

Por si te lo perdiste...

.NET / .NET Core

ASP.NET / ASP.NET Core

martes, 8 de octubre de 2019
gRPC Como un servidor, todos los que tengáis la inmensa fortuna de utilizar en Windows un nombre de usuario con espacios o caracteres especiales como "José María Aguilar", seguro que habéis encontrado alguna vez problemas con aplicaciones o herramientas que fallan cuando intentan acceder a contenidos de la carpeta C:\Users\<Tu nombre>:

Username chungo en Windows

De hecho, llevo ya varios encontronazos de este tipo en los últimos meses (por ejemplo, con Anaconda o con el SDK de Android para Windows), y el último lo he tenido al intentar utilizar las herramientas de Protobuf para la creación de servicios gRPC que, como sabéis, es una de las novedades incluidas en .NET Core 3.

Aunque el problema lo he encontrado trabajando con Visual Studio, ciertamente este IDE tiene poco que decir al respecto; ocurre lo mismo usando línea de comandos o cualquier otro entorno que se base en el tooling oficial de gRPC para .NET.