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

18 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, 23 de diciembre de 2024
Enlaces interesantes 591, christmas edition

Aquí van los enlaces recopilados durante la semana pasada, en lo que será ya la última entrega del año. Volveremos a las tareas de recolección la primera semana de enero, semana arriba o semana abajo  (¡soy malo para esto de las estimaciones!😉).

Esta edición incluye enlaces a casi 50 contenidos que me han llamado la atención, aunque me gustaría resaltar especialmente algunos de ellos.

En primer lugar un gran repaso de CampusMVP a los CWE Top 25 de 2024 o, en otras palabras, a los principales agujeros de seguridad que dejamos por detrás los desarrolladores al crear nuestras aplicaciones. Algunos de ellos seguro que los conoces ya, como inyección SQL o XSS, pero hay muchas más perversidades que debemos conocer y evitar. 

Muy interesante, como siempre, los resultados publicados por JetBrains sobre el estado del ecosistema de desarrolladores del año que está a punto de terminar, obtenidos de una encuesta a más de 23.000 developers de todo el mundo. Aquí encontraréis información valiosa sobre los proyectos en los que más trabajamos, qué lenguajes son los más utilizados en distintas áreas, qué herramientas son las preferidas, o si seguimos pensando que la IA nos va a quitar el trabajo a todos los desarrolladores antes de acabar totalmente con la humanidad, o si en cambio es una gran aliada 😉

Por último, también me parece destacable los anuncios que Microsoft ha dejado caer hace unos días: la disponibilidad de un nuevo plan gratuito de GitHub Copilot para los usuarios de Visual Studio y Visual Studio Code. Bueno, obviamente tiene sus limitaciones, pero es un buen punto de partida para los que aún no habéis podido probarlo o no tenéis acceso a licencias superiores.

Por último, aprovecho también para desearos a todos unas muy felices fiestas. Disfrutad de la mejor compañía posible y pasadlo bien, pero eso sí, sin excesos, que luego vienen los arrepentimientos... 😉

Por si te lo perdiste...

.NET Core / .NET

martes, 17 de diciembre de 2024
Programador rupestre

A principios de siglo, con un C# aún bastante primitivo, las propiedades que almacenaban datos en una clase teníamos que definirlas siempre usando un backing field, es decir, un campo privado que almacenaba el valor, y accediendo a él mediante métodos getter y setter. Es decir, algo así:

public class Customer
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
    ...
}

Esto cambió en 2007 con la llegada de las propiedades automáticas, una maravilla para nuestros cansados dedos, que desde entonces usamos en la mayoría de ocasiones. Gracias a ellas, podemos definir una propiedad sin tener que implementar sus métodos accesores ni su campo privado correspondiente, porque el compilador se encargaba de crearlos por nosotros. De esta forma, código anterior quedaba así:

public class Customer
{
    public string Name { get; set; }
    ...
}

En realidad, se trataba sólo de un azucarillo sintáctico. Por detrás, el compilador está generando el campo privado y transformando nuestro código para utilizarlo; de hecho, el código generado de la clase anterior es algo así (algo simplificado para que se pueda leer mejor):

public class Customer
{
    private string <Name>k__BackingField;

    public string Name
    {
        get { return <Name>k__BackingField; }
        set { <Name>k__BackingField = value; }
    }
}

Aunque obviamente usar propiedades automáticas es mucho más cómodo que la opción anterior, tiene un inconveniente: no tenemos forma de acceder al campo generado por el compilador, algo que puede resultar interesante si nos interesa realizar algún tipo de validación o lógica adicional en el getter o setter más allá de simplemente devolver o asignar el valor.

Por ejemplo, imaginemos que queremos que el nombre de nuestro cliente siempre esté en mayúsculas. Con una propiedad automática, simplemente no podemos hacerlo, y tendremos que recurrir a las verbosas propiedades tradicionales con backing fields.

Y aquí es donde entran en escena las propiedades semiautomáticas...

lunes, 16 de diciembre de 2024
Enlaces interesantes 590

Esta semana la cosecha ha sido especialmente prolífica y traemos más de 70 enlaces a contenidos que creo que vale la pena echar un vistazo, como siempre, categorizados por área de interés: .NET, ASP.NET Core, Azure, patrones y buenas prácticas, acceso a datos, inteligencia artificial, programación web (HTML, CSS, Javascript...), herramientas de desarrollo, .NET MAUI y otros.

Como vengo haciendo últimamente, me gustaría destacar el gran post de José Manuel Alarcón sobre técnicas de carga especulativa en páginas web que te ayudarán a mejorar el rendimiento de las aplicaciones.

Muy bueno también el deep dive de Ricardo Peres sobre los tokens de cancelación de tareas, a veces unos grandes desconocidos.

Por último, dos avisos a navegantes: primero, David Grace nos recuerda que en .NET 9, los proyectos de APIs ya no incorporan por defecto Swagger y propone algunas alternativas, y, segundo, Steve Smith alerta de los peligros de usar eventos de .NET en aplicaciones ASP.NET Core y aporta opciones para conseguir lo mismo.

Todo esto, y mucho más, a continuación...

Por si te lo perdiste...

.NET Core / .NET

martes, 10 de diciembre de 2024
Boyscout dudando

Aunque un día más tarde de lo normal debido al puente, aquí van los tradicionales enlaces recopilados durante la semana pasada. Como es habitual, la mayoría de los enlaces son a contenidos en inglés,  pero también hay algunos en español que me gustaría destacar en esta ocasión.

Por una parte, Jose Manuel Alarcón explica cómo clonar superficialmente un repositorio GIT (shallow clone) para obtener sólo los últimos commits y ahorrar tiempo y espacio en disco.

También muy interesante el post de Braulio Díez, donde reformula la clásica regla del Boy Scout y, quitándole algo de épica romántica, nos recuerda que a veces no siempre es buena idea tocar donde no debemos, o hacerlo de cualquier forma.

Y ahora, vamos a por el resto...

Por si te lo perdiste...

.NET Core / .NET

martes, 3 de diciembre de 2024
Imagen decorativa de la barra de tareas de Windows

Hoy me voy a salir un poco de las temáticas habituales para compartir un pequeño truco que llevaba buscando desde hace meses, pero que hasta ahora no había tenido tiempo de investigar.

Como seguro os ocurre a muchos de vosotros, tengo un par de cuentas de Gmail (personal y profesional) y estoy habitualmente saltando de una a otra para gestionar los correos y calendarios. He intentado durante bastante tiempo usar herramientas de escritorio de Windows para gestionar el mail y la agenda de ambas cuentas, pero no he conseguido dar con ninguna que me convenciera del todo, así que he llegado a la conclusión de que realmente la mejor interfaz para Gmail o Google Calendar está en la web.

Pero por otro lado, no me gusta usarlas directamente desde el navegador, así que la opción de instalarlas como aplicaciones web progresivas (PWA) me parecía la mejor solución. Basta con acudir a la página que queremos instalar, por ejemplo https://mail.google.com, abrir el menú de Chrome, acceder a la opción "Enviar, guardar y compartir > Instalar página como aplicación..." y listo. Durante el proceso, incluso se nos pregunta si queremos anclar la aplicación a la barra de tareas, así que podremos tener muy a mano un acceso directo a la aplicación.

El problema es que, al instalarlas, se abren siempre con el usuario de Google que tengamos configurado como por defecto. En la práctica, la aplicación anclada se abrirá siempre con la misma cuenta, que es aquella con la que nos logamos primero en el navegador. Y esto es un problema si queremos tener acceso rápido a varias cuentas, como es el caso.

lunes, 2 de diciembre de 2024
Representación de un millón de tareas ejecutándose concurrentemente

Es lunes, así que vamos a por los enlaces interesantes de la semana. Quizás algo más escasos que otras veces, probablemente debido a la festividad de acción de gracias del otro lado del charco, pero aún así tenemos una buena colección 🙂 

Esta semana, me ha llamado la atención a una interesante pregunta: ¿cuánta memoria necesitarías para ejecutar un millón de tareas concurrentes? Así a ojo es imposible saberlo, pero hay quien ha hecho la prueba con muchos lenguajes, y vemos que C# no sale nada mal parado.

También es un must read el post "¿Y qué trae de nuevo Angular 19?", donde Jose Manuel Alarcón se ha tomado la molestia de recopilar todas las novedades y explicarlas con gran detalle.

Por último, mi descubrimiento de la semana: los bloques de alertas en Markdown. Markdown es mi formato favorito para escribir un montón de cosas (entre otras, los posts de este blog) y era algo que desconocía y me ha parecido bastante interesante y práctico.

Y ahora, a por el resto de enlaces. ¡Espero que los disfrutes! 😊

Por si te lo perdiste...

.NET Core / .NET

martes, 26 de noviembre de 2024
Página principal de source.dot.net

Cuando estamos usando alguna clase de .NET en nuestro código, a veces tenemos interés o necesidad de ver qué hace por dentro, para lo que nos gustaría tener acceso rápido a su código fuente. Aunque los IDEs modernos disponen en muchos casos de herramientas o extensiones que lo permiten, está bien saber que hay otras fórmulas sencillas para conseguirlo muy rápida y cómodamente.

Hace poco me he topado con una de ellas, que me ha parecido muy útil y quería compartirla con vosotros, por si hay alguien más que aún no la conoce: la página https://source.dot.net.

lunes, 25 de noviembre de 2024
Enlaces interesantes

Una semana más, vamos con los contenidos interesantes que he ido encontrando por la red. Esta vez, entre los más de 50 enlaces de la entrega, me gustaría destacar tres de ellos.

En primer lugar, el trabajazo de José Manuel Alarcón para resumir todas las novedades de .NET 9 en un único y magnífico artículo. Si queréis poneros al día en unos minutos, no os lo perdáis

También me ha resultado interesante el post sobre Web Share, una API JavaScript que desconocía, sencillísima de utilizar, relativamente bien soportada en los navegadores, y que puede sernos útil para facilitar la compartición de contenido en nuestras aplicaciones web.

Por último, a modo de homenaje porque durante años ha sido una valiosa fuente de contenidos e información para muchos, me gustaría destacar la semi-despedida de CodeProject, un sitio que si lleváis unos añitos en esto seguro que habéis visitado más de una vez para consultar algunos de sus casi 66.000 artículos técnicos para desarrolladores. Aunque de momento seguirá en línea en modo de sólo lectura, de alguna forma, el post CodeProject is changing anuncia el fin de una era. 

Y ahora, vamos con el resto de contenidos que, como siempre, espero que os resulten interesantes.

Por si te lo perdiste...

.NET Core / .NET

martes, 19 de noviembre de 2024
Nuevos métodos LINQ en .NET 9

Me encanta LINQ. Bueno, ciertamente la sintaxis de consultas integrada en el lenguaje no la uso desde hace muchísimos años, pero los métodos de extensión que proporciona son una maravilla para recorrer y operar sobre colecciones de datos en memoria o almacenados en sistemas externos.

LINQ ha sido uno de los objetivos de .NET 9. Además de mejorarlo internamente y optimizar su rendimiento (en algunos casos, considerablemente), se han incluido tres nuevos métodos, CountBy(), AggregateBy() e Index(), que amplían las posibilidades que teníamos hasta el momento, simplificando la escritura de código y aumentando su legibilidad en algunos escenarios.

Vamos a verlos en detalle.

lunes, 18 de noviembre de 2024
Alan Turing echándose las manos a la cabeza

Como todos los lunes, vamos con los enlaces a contenidos interesantes que he ido encontrando por la red.

Esta semana se ha publicado .NET 9, por lo que tenemos bastantes contenidos relacionados con el lanzamiento y novedades que encontramos en la nueva versión.

Aparte, me ha llamado la atención el post "Understanding LLMs from Scratch Using Middle School Math" de Rohit Patel, que explica cómo funcionan los modelos de lenguaje de gran tamaño (LLMs) de forma sencilla, sin grandes complicaciones matemáticas. Muy recomendable para comprender lo que se cuece bajo el capó de estas tecnologías tan fascinantes.

Y en la sección "hay gente pa tó", me ha parecido curioso el artículo "HTML: The Programming Language", una implementación de un lenguaje Turin completo con sintaxis HTML. Muy útil no parece, pero desde luego es original 😉

Por si te lo perdiste...

.NET Core / .NET

martes, 12 de noviembre de 2024
Un armario simulando ser la caché de nivel 1, con usuarios accediendo a ella. También hay camiones transportando contenidos al nivel 2

Hace unas semanas estuvimos echando un vistazo a HybridCache, la alternativa de .NET 9 al sistema de caché distribuida que apareció con .NET Core años atrás. Como vimos entonces, HybridCache aporta una serie de ventajas respecto a su predecesor, como la protección contra estampidas, la caché multinivel, invalidación por etiquetas, y otras mejoras.

Sin embargo, también introduce algunos inconvenientes que debemos tener en cuenta si queremos sacarle el máximo partido. En esta ocasión, nos centraremos en la penalización debido a excesiva deserialización de objetos de la caché local, un detalle que puede pasar desapercibido pero que puede tener un impacto significativo en el rendimiento de nuestra aplicación.

lunes, 11 de noviembre de 2024
Enlaces interesantes

Con el horno aún humeante, aquí van los enlaces que hemos estado cocinando durante la semana pasada. Espero que estén en su punto y os resulten de provecho 😉 

Especialmente destacable el repaso de José Manuel Alarcón a los eventos que podemos usar en JavaScript para detectar que la página actual deja de estar activa, ante la próxima desaparición del evento 'unload'.

Y si queréis experimentar una buena explosión mental, no os perdáis el post sobre Quines, programas cuya salida es su propio código fuente. Un auténtico desafío para mentes inquietas hartas de programación tradicional y algo de tiempo libre😆

Por si te lo perdiste...

.NET Core / .NET

martes, 5 de noviembre de 2024
Ordenador con Tareas ejecutándose en paralelo

La clase Task de .NET dispone de algunos métodos estáticos para trabajar con colecciones de tareas de forma sencilla. Uno de ellos es Task.WhenAll(), que nos permite esperar a que todas las tareas que le pasemos como argumento se completen, o Task.WhenAny() para esperar a que finalice sólo alguna de ellas.

Sin embargo, hasta ahora no existía una forma sencilla y directa de procesar las tareas conforme se fueran completando. O bien esperábamos a que todas finalizaran con Task.WhenAll(), o bien teníamos que crear un bucle que fuera esperando la finalización de la siguiente tarea con Task.WhenAny(), saliendo cuando todas hubieran acabado.

Afortunadamente, .NET 9 ha añadido el nuevo método llamado Task.WhenEach() que lo pone más fácil, permitiéndonos detectar sobre la marcha la finalización de las tareas conforme va ocurriendo. Esto nos facilita el proceso de sus resultados secuencialmente, en el orden en el que se completan y sin esperar a que acaben todas.

Vamos a verlo, pero para entenderlo mejor, primero vamos a recordar las opciones que teníamos antes de la llegada de este método.

lunes, 4 de noviembre de 2024
Enlaces interesantes

Ya tenemos aquí los enlaces recopilados durante la semana pasada 🙂

Aunque hay bastante chicha, me ha llamado especialmente la atención que cumpla 21 años una herramienta que sigue siendo imprescindible en el cinturón de muchos de nosotros: Notepad++. ¡Felicidades a Don Ho y los más de 350 colaboradores que lo hacen posible!

Por si te lo perdiste...

.NET Core / .NET

martes, 29 de octubre de 2024
Piezas de un puzzle sugiriendo que todo va encajando en .NET

Seguimos analizando las novedades de .NET 9, y en esta ocasión le toca el turno a la actualización en miembros de clases parciales de C# 13.

Las clases o tipos parciales de C# están con nosotros casi desde los inicios de .NET, desde los tiempos de C# 2.0. Como sabemos, éstas permiten dividir la implementación de un tipo en varios archivos. Su existencia se debía a varios motivos:

  • Permitir a los desarrolladores trabajar en clases de forma concurrente sin bloquearse (recordemos que por aquellos tiempos aún pululaban por ahí infames sistemas de control de código fuente como SourceSafe).
  • Trocear clases extensas para facilitar su comprensión y mantenimiento.
  • Y, el que es más importante, posibilitar el uso sencillo de herramientas de generación de código que, de alguna forma, tuvieran que completar la implementación de código del usuario.

Acompañando a las clases parciales, se introdujo también el soporte para métodos parciales. Aunque su uso era limitado y podía depararnos algunas sorpresas, eran útiles para comunicar de forma segura distintos fragmentos de la clase. Básicamente, consistía en que una porción de una clase podía definir un método e invocarlo desde su código, delegando a otras porciones su implementación. Si no se implementaba en ninguna otra parte, simplemente no se generaba el código de la invocación.

Veamos un ejemplo del uso de estas características:

// Archivo: Ejemplo.Main.cs
public partial class Ejemplo
{    
    // El método parcial se declara sin implementación...
    partial void Log(string msg);

    public void RealizarAlgo()
    {
        hacerAlgoComplejo();
        Log("¡Ojo!"); // Usamos el método
                    // parcial declarado antes
    }
}

// Archivo: Ejemplo.Log.cs
public partial class Ejemplo
{
    partial void Log(string msg)
    {
        Console.WriteLine(msg);
    }
}

Pues bien, casi dos décadas más tarde, los tipos parciales van a recibir algunas actualizaciones interesantes en C# 13, posibilitando que, además de métodos, puedan definirse propiedades parciales.

lunes, 28 de octubre de 2024
Enlaces interesantes

Aquí tenéis los enlaces recopilados durante la semana. 

En esta ocasión, creo que como mínimo vale la pena echar un vistazo a lo nuevo de Anthropic, que sorprende especialmente con computer use, una vuelta de tuerca más para la automatización de tareas con nuestro ordenador. Es increíble que hace sólo unos meses, todas estas novedades que van apareciendo sólo podrían haber cabido en la ciencia ficción...

También muy interesante el movimiento de JetBrains, facilitando el uso gratuito de sus IDEs WebStorm y Rider para proyectos no comerciales 🙂

¡Que los disfrutéis!

Por si te lo perdiste...

.NET Core / .NET

martes, 22 de octubre de 2024
Imagen decorativa sugiriendo sistemas de almacenamiento en la nube

Una de las novedades más destacables de .NET 9 es, sin duda, el nuevo sistema de caché híbrida (Hybrid cache), una puesta al día del sistema de caché distribuida que nos acompaña desde las primeras versiones de .NET Core, y al que iban haciendo falta ya algunas mejoras.

Este nuevo sistema está construido encima de la infraestructura de caching existente (Microsoft.Extensions.Caching), añadiendo mejoras que hacen que su uso sea más sencillo y contemplando de serie funcionalidades que antes nos veíamos obligados a implementar manualmente.

Vamos a echarle un vistazo a sus principales características :)

Disclaimer: lo que vamos a ver a continuación está basado en .NET 9 RC2, por lo que todavía es posible que haya cambios en la versión final.

lunes, 21 de octubre de 2024
Enlaces interesantes

Como todos los principios de semana, aquí va la lista de enlaces recopilados durante los últimos siete días. Hay bastantes cosas que me han llamado la atención en esta ocasión; entre otros, he descubierto que Visual Studio incluye un visualizador de JWT integrado, el atributo [OverloadResolutionPriority] de .NET 9/C#13, y también me he preguntado cuántos son muchos índices en una tabla SQL 😕

Por si te lo perdiste...

.NET Core / .NET

martes, 15 de octubre de 2024
.NET 9 apareciendo en el horizonte

Cada vez que llega una nueva versión del framework, todos estamos ansiosos por conocer las novedades, especialmente las más espectaculares. Sin embargo, a veces hay pequeñas mejoras que, sin ser revolucionarias, nos pueden resultar útiles en algunos escenarios.

El modificador params permite especificar que un método o función acepta un número variable de argumentos, como en el siguiente ejemplo, donde vemos una función Sum() que puede ser invocada con cualquier número de valores:

// Declaración de la función:
int Sum(params int[] values) 
{
    return values.Sum();
}

// Ejemplos de uso:
Console.WriteLine(Sum(1)); // Enviamos un único valor -> "1"
Console.WriteLine(Sum(1, 2, 3, 4, 5)); // Enviamos cinco valores -> "15"
Console.WriteLine(Sum()); // No enviamos elementos, se recibirá un array vacío -> "0"
Console.WriteLine(Sum([1, 2, 3])); // Aquí pasamos un array directamente -> "6"

Hasta ahora, el parámetro param sólo podía ser un array, lo que limitaba un poco su uso. Por ejemplo, no podríamos llamar a la función Sum() pasándole directamente un List<int> o un IEnumerable<int> sin convertirlos antes a array porque fallarían en tiempo de compilación, al no tratarse de un int[], que es el tipo del parámetro esperado.

¿Qué ha cambiado?

lunes, 14 de octubre de 2024
Enlaces interesantes

Aquí tenemos la recopilación de enlaces de la semana. Entre ellos, me han llamado especialmente la atención los datos que muestra Trevor I. Lasn en su artículo sobre el factor edad en el mundo tecnológico, probablemente porque estoy en el 15% del que habla, los desarrolladores que vuelan ya por encima de los 45 tacos 😆

Y aparte, como siempre, un poco de ASP.NET Core, datos, IA, programación web y otros temas que espero que os resulten interesantes 🙂

Por si te lo perdiste...

.NET Core / .NET

martes, 8 de octubre de 2024
Imagen de una fábrica creando GUIDs

Probablemente, todos hemos usado en algún momento el método Guid.NewGuid() de .NET para generar identificadores únicos globales. Y muchos hemos sufrido con el problema que supone su (pseudo) aleatoriedad, principalmente cuando necesitamos ordenarlos... sobre todo si su destino final es acabar siendo el campo clave de una base de datos relacional.

Pero pocos éramos conscientes de que el método Guid.NewGuid() de .NET retorna un GUID versión 4, y que existen otras versiones de UUID (¡hasta 8!) que pueden resultar más beneficiosas en determinados escenarios.

lunes, 7 de octubre de 2024
Enlaces interesantes

Una semana más, aquí tenéis los enlaces recopilados durante la semana pasada, con mucho protagonismo de los últimos lanzamientos de OpenAI que, si usáis sus APIs o planeáis hacerlo, seguro que os interesarán: la API realtime y el prompt caching

Por si te lo perdiste...

.NET Core / .NET

martes, 1 de octubre de 2024
Imagen decorativa mostrando una jeringa inyectando algo en un circuito

Como sabemos, una forma habitual de registrar servicios en el contenedor de dependencias de .NET consiste en indicar al framework la implementación de la interfaz o clase abstracta que debe ser utilizada cuando se solicite una instancia de la misma. Por ejemplo, en el siguiente código, que podría pertenecer a la inicialización de una aplicación ASP.NET Core, se registra la implementación FriendDbRepository para la interfaz IFriendRepository con un ámbito scoped o por petición:

builder.Services.AddScoped<IFriendRepository, FriendDbRepository>();

Hecho esto, podríamos solicitar una instancia de IFriendRepository en cualquier parte de nuestra aplicación que admita inyección de dependencias, como los controladores, manejadores Minimal API, otras dependencias, etc. El inyector encargará de proporcionarnos una instancia de FriendDbRepository allá donde la necesitemos:

public class FriendsController: Controller
{
    public FriendsController(IFriendRepository friendRepository)
    {
        // ... Aquí la tenemos!
    }
}

O bien, podríamos obtenerla directamente desde la colección de servicios:

public void DoSomething(IServiceProvider services)
{
    var repo = services.GetRequiredService<IFriendRepository>();
    ...
}

Como vemos en ambos casos, la única forma disponible para identificar el servicio que deseamos obtener es utilizar su tipo, o muy habitualmente, la abstracción (interfaz o clase abstracta) a la que está asociado.

Pero eso cambió con la llegada de .NET 8...

lunes, 30 de septiembre de 2024
Enlaces interesantes

Una semana más, comparto la recopilación de enlaces a contenidos que me han parecido interesantes.

De esta tirada, me quedo con "Las interfaces describen qué, las implementaciones describen cómo", un gran título para el artículo de Steve Smith sobre conceptos que todos deberíamos tener claros.

Por si te lo perdiste...

.NET Core / .NET

martes, 24 de septiembre de 2024
.NET

Acercándose el lanzamiento de .NET 9 el próximo mes de noviembre, podemos ver ya algunas de las novedades que traerá la nueva versión, con las que podemos jugar desde hace algunos meses instalando las previews que van apareciendo cada mes.

En esta ocasión vamos a ver algunas novedades más interesantes que se han añadido a la biblioteca de serialización JSON oficial, conocida por todos como System.Text.Json:

¡Vamos a ello!

Nota: Este artículo está basado en .NET 9 RC1, por lo que algunas de las características descritas podrían cambiar en la versión final.

1. Opciones de personalización de la indentación

Hasta .NET 8, las opciones de personalización relativas al indentado de JSON generado era bastante limitada. De hecho, sólo podíamos decidir si lo queríamos indentar o no usando la propiedad WriteIndented de JsonOptions:

var obj = new
{
    Name = "John",
    Age = 30,
    Address = new { Street = "123 Main St", City = "New York" }
};

var jsonOptions = new JsonSerializerOptions()
{
    WriteIndented = true, // Queremos indentar el JSON
};

Console.WriteLine(JsonSerializer.Serialize(obj, jsonOptions));

El resultado será siempre un JSON indentado a dos espacios como el siguiente:

{
  "Name": "John",
  "Age": 30,
  "Address": {
    "Street": "123 Main St",
    "City": "New York"
  }
}

En .NET 9 disponemos de dos nuevas propiedades para personalizar la indentación del JSON generado. La propiedad IndentCharacter permite especificar el carácter a utilizar (espacio o tabulador, exclusivamente), y mediante IndentSize podemos indicar el número de caracteres a utilizar en cada nivel de indentación.

var jsonOptions = new JsonSerializerOptions()
{
    WriteIndented = true,
    IndentCharacter = '\t',
    IndentSize = 2
};

Console.WriteLine(JsonSerializer.Serialize(obj, jsonOptions));

En este caso, el resultado será así (2 tabuladores por nivel de indentación):

{
                "Name": "John",
                "Age": 30,
                "Address": {
                                "Street": "123 Main St",
                                "City": "New York"
                }
}

2. Singleton de opciones de serialización y deserialización para la web

ASP.NET Core utiliza una configuración por defecto para serializar y deserializar objetos JSON, que ahora está disponible de forma pública en la propiedad JsonSerializerOptions.Web.

El objeto retornado es un singleton JsonSerializerOptions de sólo lectura, que estará disponible en cualquier punto de la aplicación.

Por defecto, este objeto está configurado de la siguiente manera:

  • PropertyNameCaseInsensitive está establecido a true, por lo que la deserialización de propiedades es insensible a mayúsculas y minúsculas.
  • JsonPropertyNamingPolicy tiene el valor JsonNamingPolicy.CamelCase, así que las propiedades se serializan en formato camelCase, el habitual en JavaScript y JSON.
  • NumberHandling es JsonNumberHandling.AllowReadingFromString, así que será posible deserializar números que vengan especificados como texto.

Un ejemplo de utilización de este objeto sería el siguiente:

var obj = new
{
    Name = "John",
    Age = 30,
    Address = new { Street = "123 Main St", City = "New York" }
};

Console.WriteLine(JsonSerializer.Serialize(obj, JsonSerializerOptions.Web));

// Resultado:
// {"name":"John","age":30,"address":{"street":"123 Main St","city":"New York"}}

Dado que el objeto es de sólo lectura, no podemos modificar sus propiedades. Si necesitásemos algún tipo de cambio en la configuración, podríamos crear una configuración nueva partiendo de él, e introducir las modificaciones deseadas, por ejemplo:

var jsonOptions = new JsonSerializerOptions(JsonSerializerOptions.Web)
{
    WriteIndented = true,
    IndentCharacter = '\t',
    IndentSize = 2
};

3. Soporte de anotaciones de anulabilidad

En .NET 8 y versiones anteriores, System.Text.Json no respetaba las anotaciones de anulabilidad de C# en las propiedades de los tipos de referencia. Por ejemplo, si tenemos una propiedad de tipo referencia que no puede ser nula como en el siguiente caso, podemos ver que el siguiente código deserializará sobre ella un valor nulo sin problema:

var myFriend = JsonSerializer.Deserialize<Friend>("""{ "Name": null }""");
Console.WriteLine(myFriend.Name ?? "Unknown"); // Muestra "Unknown"

// Friend tiene un campo "Name" que no puede ser nulo
public record Friend (string Name);

A partir de .NET 9, podemos indicar opcionalmente a System.Text.Json que respete la anulabilidad de propiedades, es decir, si una propiedad no es anulable, al deserializarla no podremos establecerla al valor nulo.

Esto podemos conseguirlo simplemente estableciendo a true la propiedad RespectNullableAnnotations de las opciones de deserialización:

var opt = new JsonSerializerOptions() { RespectNullableAnnotations = true };
var myFriend = JsonSerializer.Deserialize<Friend>("""{ "Name": null }""", opt);
Console.WriteLine(myFriend.Name ?? "Unknown"); // Lanza una excepción

Según la documentación, otra posibilidad es hacerlo de forma global para todo el proyecto, añadiendo la siguiente configuración en el archivo .csproj:

<ItemGroup>
  <RuntimeHostConfigurationOption 
     Include="System.Text.Json.JsonSerializerOptions.RespectNullableAnnotations" 
     Value="true" />
</ItemGroup>

Supongo que, debido a que aún estamos jugando con versiones preview del compilador, esta última opción no conseguí que me funcionara.

Otra cosa que he visto curiosa es que el siguiente código, a mi entender, debería lanzar una excepción, pero no lo hace:

var opt = new JsonSerializerOptions() { RespectNullableAnnotations = true };

var myFriend = JsonSerializer.Deserialize<Friend>("{ }", opt);
Console.WriteLine(myFriend.Name ?? "Unknown"); // Muestra "Unknown"

En principio, si la propiedad Name hemos dicho que no era anulable, ¿no debería lanzar una excepción al deserializar un objeto que no especifica su valor? Pues no, y parece ser que se trata de un comportamiento esperado; hay un interesante hilo al respecto en GitHub discutiendo el por qué de esta decisión, aunque en el siguiente apartado veremos que existe en algunos casos existe una forma alternativa de evitar esta situación.

Por último, la propiedad RespectNullableAnnotations también afecta a la serialización, de forma que si una propiedad no anulable tiene un valor nulo al ser serializada, se lanzará una excepción:

var opt = new JsonSerializerOptions() { RespectNullableAnnotations = true };

var myFriend = new Friend(null);
Console.WriteLine(JsonSerializer.Serialize(myFriend, opt)); // Lanza una excepción

4. Comprobación de parámetros obligatorios del constructor

En .NET 8 y anteriores, los parámetros del constructor del tipo a deserializar eran tratados como siempre como opcionales. Por esta razón, el código siguiente no provoca errores:

var myFriend = JsonSerializer.Deserialize<Friend>("""{ }""");
Console.WriteLine(myFriend.Name ?? "Unknown"); // Muestra "Unknown"

public record Friend(string Name);

En .NET 9, es posible indicar al deserializador que queremos respetar los parámetros requeridos del constructor, de forma que si no pueden ser satisfechos se lanzará una excepción. Esto se consigue con el nuevo flag RespectRequiredConstructorParameters en las opciones de deserialización:

var opt = new JsonSerializerOptions() { RespectRequiredConstructorParameters = true };

var myFriend = JsonSerializer.Deserialize<Friend>("""{ }""", opt);
Console.WriteLine(myFriend.Name ?? "Unknown"); // Lanza una excepción

La excepción, de tipo JsonException es bastante clara en su texto de descripción: 'JSON deserialization for type 'Friend' was missing required properties including: 'Name'.'.

Como en el caso anterior, este comportamiento puede ser también configurado de forma global para todo el proyecto, añadiendo la siguiente configuración en el archivo .csproj:

<ItemGroup>
  <RuntimeHostConfigurationOption 
      Include="System.Text.Json.JsonSerializerOptions.RespectRequiredConstructorParameters" 
      Value="true" />
</ItemGroup>

Y como en el caso anterior, tampoco he conseguido que me funcione de esta forma 😆 Esperemos que las siguientes preview o la versión final lo solucionen.

5. Descripción de tipos .NET usando JSON Schema

La nueva clase estática JsonSchemaExporter expone el método GetJsonSchemaAsNode(), que permite obtener el esquema JSON de un tipo .NET en forma de objeto JsonNode.

Su uso es muy sencillo, simplemente pasamos las opciones a utilizar para serializar el esquema, y el tipo del que queremos obtenerlo. Observad el siguiente ejemplo:

var schema = JsonSchemaExporter.GetJsonSchemaAsNode(
    JsonSerializerOptions.Default, 
    typeof(Friend)
);
Console.WriteLine(schema);

public record Friend(string Name, string? nickName, int Age = 20);

El resultado que obtendremos es una descripción del tipo, siguiendo el estándar JSON Schema, que en este caso sería algo así:

{
  "type": [
    "object",
    "null"
  ],
  "properties": {
    "Name": {
      "type": "string"
    },
    "nickName": {
      "type": [
        "string",
        "null"
      ]
    },
    "Age": {
      "type": "integer",
      "default": 20
    }
  },
  "required": [
    "Name",
    "nickName"
  ]
}

Conclusión

En este artículo hemos visto algunas de las novedades que traerá la nueva versión de .NET 9 en la biblioteca de serialización JSON oficial, System.Text.Json. Aunque no son cambios revolucionarios, sí que son mejoras que facilitarán la vida a los desarrolladores que trabajamos con JSON en nuestras aplicaciones.

¡Espero que os haya resultado interesante!

lunes, 23 de septiembre de 2024
Enlaces interesantes

Vamos con la recopilación de enlaces de la tercera semana de septiembre, donde, como es habitual,  podemos ver un poco de todo: algunos lanzamientos, características de C#, uso de herramientas de telemetría y monitorización, rendimiento en ASP.NET Core, frontend, y más.

Como reflexión, es curioso ver que la IA está presente en cada vez más áreas del desarrollo. Y aparte, me quedo con lo poco que se suelen usar los operadores implícitos de C#, cuando realmente pueden hacer nuestro código más limpio...

Por si te lo perdiste...

.NET Core / .NET

martes, 17 de septiembre de 2024
ASP.NET Core

Una pregunta que me hacen con cierta frecuencia los alumnos de mi curso de ASP.NET Core en CampusMVP es que por qué, al ejecutar una aplicación de este tipo, Visual Studio les muestra un mensaje como el siguiente, no se lanza el navegador y no pueden acceder a la aplicación:

Ventana de error con mensaje: No se puede conectar al servidor web 'https'. El servidor webya no funciona

Generalmente la respuesta es bastante sencilla: Visual Studio nos está informando de que el servidor web no ha sido lanzado al ejecutar la aplicación.

lunes, 16 de septiembre de 2024
Enlaces interesantes

Tras unas semanas de merecido descanso, volvemos a la carga con el blog, inaugurando lo que, más o menos, debería ser su temporada número 18. Como de costumbre, intentaremos seguir la serie semanal de enlaces de interés y escribiendo sobre trucos, novedades y características de C#, .NET, ASP.NET Core, Blazor, JavaScript, o cualquier cosa que se ponga por delante y que considere que puede ser de utilidad para la comunidad.

Y para empezar con buen pie, lo haremos con la recopilación número 576 de enlaces que, como de costumbre, espero que os resulten interesantes. Especialmente destacable, además del lanzamiento de .NET 9 RC1, es el esperado post "Performance improvements in .NET 9" del gran Stephen Toub, todo un clásico cuando se va acercando una nueva versión del framework. Sencillamente imprescindible si queréis estar a la última.

Por si te lo perdiste...

.NET Core / .NET

jueves, 11 de julio de 2024
MVP

Hago una ligera interrupción de mis vacaciones blogueras para compartir con todos vosotros que, por decimocuarto año consecutivo, he sido reconocido por Microsoft como Most Valuable Professional (MVP) en la categoría .NET ¡¡Hurra!! 😀

Aunque ya debería estar acostumbrado, siempre es un honor y un privilegio recibir este galardón que, de alguna forma, reconoce mis aportaciones a la comunidad de desarrolladores, esa comunidad con la que sigo estando en deuda por lo que he recibido de ella durante tanto tiempo.

Muchas gracias al equipo de Microsoft que hace esto posible, con nuestra querida Cristina González a la cabeza, por la dedicación y esfuerzo que ponen en este programa. Muchas gracias también a todos los compañeros MVPs que hacen que esta comunidad sea tan especial.

Y, por supuesto, agradeceros a todos vosotros, queridos amigos y amigas, por seguir ahí, porque vuestras visitas, lecturas y comentarios son los que me animan a seguir compartiendo experiencias y conocimientos en este pequeño rinconcito de la web.

¡Nos vemos a la vuelta!

Publicado en Variable not found.

martes, 9 de julio de 2024
Foto: Atardecer en la playa en Costa Ballena, por Eugenio Sánchez. Original: foro.ojodigital.com

Queridos amigos, queridas amigas: como todos los años por esta época, me complace informaros de que voy a dejar el blog a merced de los vientos durante unas semanas para disfrutar de un (merecidísimo) descanso.

Volveremos a la carga, supongo que a mediados de septiembre (o antes, o después, ya iremos viendo) 🙂

Feliz verano a todos y que disfrutéis de las vacaciones. ¡Nos vemos a la vuelta!

Publicado en: www.variablenotfound.com.
lunes, 8 de julio de 2024
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, 2 de julio de 2024
C#

Cuando en un bucle for necesitamos más de una variable de control, lo habitual es inicializarlas fuera del bucle y luego usarlas en su interior, por ejemplo, como en el siguiente código:

int j = 0;
for (int i = 0; i < 10 && j < 100; i++)
{
    Console.WriteLine($"i = {i}, j = {j}");
    j+= 10;
}
lunes, 1 de julio de 2024
martes, 25 de junio de 2024
Blazor

Blazor ha venido en ASP.NET Core 8 cargadito de novedades, aunque probablemente la más destacable sea la introducción de las Blazor Web Apps como modelo de proyecto que unifica los distintos modos de renderizado de componentes. Aunque se trata de un cambio positivo, la realidad es que ha complicado algunas cosas que antes, con unos modelos de proyecto más sencillos, eran más fáciles de implementar.

Un ejemplo claro lo tenemos en las páginas de error 404 (not found): con este nuevo modelo unificado no hay una fórmula trivial o integrada de serie en el framework para implementar esta funcionalidad, tan habitual en nuestras aplicaciones.

En este post vamos a ver un posible enfoque para conseguir que si un usuario introduce una ruta inexistente en el navegador o bien pulsa un enlace interno que no exista, podamos mostrarle una página de error 404 totalmente personalizada, implementada como componente Blazor, e integrada en nuestra Blazor Web App.

lunes, 24 de junio de 2024
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET