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!
martes, 25 de mayo de 2021
.NET Core

Hace algunos años hablábamos de que la forma más correcta de determinar si un objeto es nulo en C# era utilizando el operador is:

var invoice = _invoiceRepository.GetById(18);
if(invoice is null) 
{
    // Hacer algo
}

Como vimos en su momento, esta opción era mejor que utilizar una comparación directa como invoice == null porque el operador de igualdad podía ser sobrecargado y, por tanto, su comportamiento podría ser modificado, mientras que el operador is no es sobrecargable.

Sin embargo, al comenzar al usar esta fórmula, encontrábamos un pequeño inconveniente cuando queríamos determinar justo lo contrario, es decir, saber cuándo un objeto no es nulo, pues la sintaxis se volvía algo más pesada:

var invoice = _invoiceRepository.GetById(18);
if(!(invoice is null)) 
{
    // Hacer algo
}

lunes, 24 de mayo de 2021
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, 18 de mayo de 2021
Blazor

Durante la implementación de páginas o componentes Blazor en archivos .razor, es relativamente frecuente encontrarse con casos en los que nos interesa reutilizar un bloque de código Razor en más de un punto. 

Por ejemplo, observad el siguiente ejemplo:

<h1>Todo list</h1>
<h2>Pending tasks</h2>
<ul>
    @foreach (TodoItem item in TodoItems.Where(i=>!i.IsDone).OrderBy(i=>i.Priority))
    {
        <li>@item.Task, owned by @item.Owner and created at @item.CreatedAt</li>
    }
</ul>
<h2>Finished tasks</h2>
<ul>
    @foreach (TodoItem item in TodoItems.Where(i=>i.IsDone).OrderBy(i=>i.DateFinished))
    {
        <li>@item.Task, owned by @item.Owner and created at @item.CreatedAt</li>
    }
</ul>

En este componente, podemos ver claramente que estamos repitiendo los dos bloques de código encargados de mostrar los elementos de cada una de las listas, por lo que, si en el futuro quisiéramos cambiar la forma de mostrar un TodoItem, tendríamos que modificar el interior de los dos bloques. Es frecuente en estos casos optar por crear un nuevo componente que se encargue de ello, por ejemplo, llamado TodoListItem:

<li>@Item.Task, owned by @Item.Owner and created at @Item.CreatedAt</li>
@code {
    [Parameter]
    public TodoItem Item { get; set;}
}

De esta forma ya tendremos el código de renderización del TodoItem centralizado y podremos simplificar el bloque anterior eliminando la duplicidad:

<h1>Todo list</h1>
<h2>Pending tasks</h2>
<ul>
    @foreach (TodoItem item in TodoItems.Where(i=>!i.IsDone).OrderBy(i=>i.Priority))
    {
        <TodoListItem Item="item" />
    }
</ul>
<h2>Finished tasks</h2>
<ul>
    @foreach (TodoItem item in TodoItems.Where(i=>i.IsDone).OrderBy(i=>i.DateFinished))
    {
        <TodoListItem Item="item" />
    }
</ul>

Aunque conceptualmente la solución que hemos implementado es correcta, introduce un problema en nuestra aplicación: por el mero hecho de querer evitar la duplicación de código, estamos introduciendo en la página un número indeterminado de componentes, lo cual podría afectar drásticamente a su rendimiento.

Por llevarlo al extremo, imaginad que esas listas tienen miles de elementos. En este caso, en nuestra página estaríamos introduciendo miles de componentes, con lo que esto implica:

  • Deberían instanciarse miles de componentes (objetos).
  • Deberían ejecutarse los eventos del ciclo de vida de cada componente al crearlos, inicializarlos, renderizarlos, etc.
  • Mientras se encuentren en la página cada componente ocuparía memoria, ya sea en cliente (Blazor WebAssembly) o en servidor (Blazor Server).

Esto podría llegar incluso a hacer una página inutilizable, por lo que es importante disponer de otros métodos para crear y reutilizar bloques de código HTML sin necesidad de crear componentes. Esta es una de las utilidades de los render fragments.

lunes, 17 de mayo de 2021
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, 11 de mayo de 2021
15 años de Variable Not Found

Pues sí, que se dice pronto, pero hace unos días Variable Not Found cumplió quince años y, como cada aniversario, no quería faltar a la tradición de celebrarlo con vosotros.

Unas 800 semanas, 5.600 días (exceptuando vacaciones, que también las hay), intentando volcar por aquí parte de lo que voy viendo o descubriendo sobre esta profesión que tanto nos gusta. Esto ha dado para cerca de 1300 posts, que han sido consultados más de cuatro millones y medio de veces, y que cuentan con seguidores de todo el mundo, y seguimos fieles los mismos objetivos: aprender y echar una mano al que por aquí se acerque.

Y como de costumbre, aprovecharemos para comentar un poco qué tal fueron las cosas por aquí los últimos 365 días.

lunes, 10 de mayo de 2021
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, 4 de mayo de 2021
Logging

Hace unos días pasaba a un amigo una instrucción de PowerShell para visualizar en tiempo real el contenido que iba añadiéndose al final de un archivo de log en Windows, y pensé que igual podía ser útil para alguien más, así que aquí va :)

El asunto es tan simple como abrir un terminal o consola PowerShell en la carpeta donde tengamos el archivo y ejecutar la siguiente orden:

Get-content log.txt -Tail 0 -Wait

A partir de ese momento, la consola quedará bloqueada e irá mostrando en tiempo real las últimas líneas añadidas al archivo:

Ventana de consola mostrando las últimas líneas añadidas a un archivo de texto

Esta idea tan sencilla podría ser combinada en scripts que nos simplifiquen alguna tarea más; por ejemplo, si estamos en una carpeta con archivos de trazas de distintos días, es sencillo conseguir que se abra el fichero de log más reciente, de forma que no tengamos que introducir su nombre cada vez que queramos utilizarlo:

# File: ViewLog.ps1
$file = Get-ChildItem -Filter *.txt | Sort-Object LastAccessTime -Descending | Select-Object -First 1
if($file) 
{
	Get-content $file -Tail 0 -Wait
}

¡Espero que os sea útil!

Publicado en Variable not found.

lunes, 3 de mayo de 2021
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, 27 de abril de 2021

SyncfusionEn el mundo de las suites profesionales de componentes, seguro que todos habéis oído hablar de Syncfusion. Esta compañía lleva desde 2001 ofreciendo componentes y marcos de trabajo para todo tipo de entornos, con el fin de hacer la vida más sencilla a los desarrolladores: ASP.NET Core, ASP.NET MVC, Web Forms, Angular, React, Vue, Xamarin, Flutter, WinForms o WPF son sólo algunas tecnologías en las que tenemos a disposición sus soluciones.

Y claro, no podía faltar Blazor :) La biblioteca Syncfusion Blazor UI ofrece más de setenta componentes para Blazor Server y WebAssembly que cubren sobradamente las necesidades más habituales en la construcción de aplicaciones profesionales.

Aunque se trata de una solución comercial y las licencias tienen coste, la buena noticia es que existe una generosa licencia community gratuita, mediante la cual podemos tener acceso a todos los componentes siempre que seamos desarrolladores independientes o una empresa con menos de seis trabajadores e ingresemos anualmente menos 1 millón de dólares brutos.

En este post vamos a dar un primer vistazo a esta biblioteca, para tener una idea de su alcance y forma de uso.

lunes, 26 de abril de 2021
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, 20 de abril de 2021
Blazor

Cuando empezamos a estudiar Blazor WebAssembly e interiorizamos que para ejecutar .NET en el navegador es necesario llevar hasta éste el runtime y bibliotecas, tanto del propio framework como las de nuestra aplicación, una de las primeras dudas que nos asaltan es que cuánto peso tendrá eso. O dicho de otra forma, qué recursos tendrán que descargar los usuarios y qué tiempo tendrán que esperar hasta tener la aplicación en funcionamiento.

En este post vamos a intentar dar respuesta a esta pregunta, aunque con matices. Obviamente, parte de ese peso dependerá de la aplicación; si se trata de un proyecto grande, con muchos ensamblados o que usen muchos componentes externos (p.e. paquetes NuGet), el número de archivos y el tamaño de la descarga crecerá inexorablemente. Por esa razón, no podremos ver aquí números absolutos, sino los mínimos, es decir, lo que pesará una aplicación Blazor WebAssembly recién creada, con los contenidos proporcionados por la plantilla por defecto usando .NET 5.

Tampoco hablaremos de tiempos, pues son totalmente dependientes de las condiciones de red, la infraestructura en la que despleguemos la aplicación y las posibilidades del cliente. Simplemente tendremos en consideración que a más peso, mayor tiempo será necesario para llevarlo al navegador y ejecutarlo.

Ojo: lo que vamos a ver son los datos aproximados obtenidos en mi máquina de desarrollo y con la versión actual de Blazor (5.0.4). Los números exactos variarán si hacéis pruebas en vuestro entorno, aunque seguro que el espíritu de las conclusiones seguirá siendo el mismo.
lunes, 19 de abril de 2021
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, 13 de abril de 2021
.NET Core

A raíz de los posts sobre generadores de código (como éste y éste), un amigo del blog me escribió para ver si de alguna forma era posible examinar el código fuente generado para poder depurarlo con mayor facilidad.

Y en efecto, es posible. Pero en vez de responderle directamente, he pensado que sería mejor compartirlo por aquí, de forma que pueda resultar de utilidad para alguien más :)

lunes, 12 de abril de 2021
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, 6 de abril de 2021
Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

lunes, 29 de marzo de 2021
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, 23 de marzo de 2021

Como probablemente ya sabréis, NDepend es una de esas herramientas que están ahí de siempre, ayudando a desarrolladores y arquitectos a mejorar la calidad de nuestro software gracias a sus potentes y flexibles herramientas de análisis de proyectos.

Hace tiempo ya echamos por aquí un vistazo, pero creo que es interesante darle otra vuelta y refrescar conocimientos.

lunes, 22 de marzo de 2021
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, 16 de marzo de 2021
.NET Core

Como decíamos hace unos días, los generadores de código C# nos brindan la posibilidad de crear al vuelo código C# e incluirlo en nuestros proyectos en tiempo de compilación.

Por no alargar demasiado el post, vimos un sencillísimo ejemplo de implementación, pero ahora vamos a crear algo más complejo que podría ayudarnos a solucionar un problema que tendría difícil solución de no contar con esta característica del compilador.

1. Definición de objetivos

El reto al que vamos a enfrentarnos ya lo expusimos en el post anterior como un caso de uso simple de los generadores de código, así que vamos a reproducir la descripción del escenario.

Imaginemos que en nuestra aplicación tenemos clases que representan operadores matemáticos como SumOperator, MultiplyOperator, DivideOperator, SubtractOperator. Imaginad también que nos interesa tener un tipo enum Operators donde aparezca un miembro por cada operador disponible, algo como:

public enum Operators
{
    Sum,
    Multiply,
    Divide,
    Subtract
}

El problema que tiene enfocar esto de forma manual es que resultaría sencillo implementar una nueva clase operador y olvidar crear su correspondiente entrada en la enumeración Operators. Aquí es donde vienen al rescate los generadores de código :)

Lo que implementaremos hoy es un generador de código C# que creará la enumeración por nosotros en tiempo de compilación, manteniéndola sincronizada en todo momento con las clases que tengamos definidas en el proyecto. Para ello, crearemos un generador llamado OperatorsEnumGenerator que:

  • En la fase de análisis de código recopilará las clases del proyecto a compilar cuyo nombre finalice por Operator.
  • En la fase de generación de código creará el enum con los miembros registrados anteriormente.

¡Vamos allá!

lunes, 15 de marzo de 2021
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, 9 de marzo de 2021
.NET Core

Seguramente muchos coincidiremos en que una de las novedades más interesantes de la última versión del compilador de C# es lo que oficialmente han denominado C# Source Generators, o generadores de código fuente de C#.

Muy resumidamente, esta característica añade un nuevo paso en la compilación en el cual los desarrolladores podemos introducir componentes propios (generadores) que inspeccionen el código de la aplicación que está siendo compilada y generen nuevos archivos, que a su vez pueden ser compilados e incluidos en los ensamblados resultantes. Su objetivo, tal y como se declara en su documento de diseño, es posibilitar la metaprogramación en tiempo de compilación.

Veámoslo con un ejemplo donde, además de explicarlo mejor, se puede mostrar su utilidad. Imaginad que en nuestra aplicación tenemos clases que representan operadores matemáticos como SumOperator, MultiplyOperator, DivideOperator, SubtractOperator, y todos ellos heredan de una clase base Operator. Imaginad también que nos interesa tener un tipo enumerado enum Operators donde aparezca un miembro por cada operador disponible, algo como:

public enum Operators
{
    Sum,
    Multiply,
    Divide,
    Subtract
}

Muy probablemente os habéis encontrado alguna vez con un escenario similar y habéis sufrido la dificultad de mantener sincronizada la enumeración con las clases que heredan de Operator: cada vez que aparezca un operador nuevo e implementemos la clase operador que lo representa, tendremos que acordarnos de ir a Operators y añadir el miembro.

Pues bien, aunque simple, esto sería un caso de uso bastante claro para los generadores de código fuente de C#. Gracias a ellos, podríamos crear un componente generador que examine nuestro código en busca de herederos de Operator y genere al vuelo, siempre en tiempo de compilación, un archivo de código con la enumeración Operators.

A todos los efectos, es como si esa enumeración la hubiéramos escrito a mano, porque podremos usarla con normalidad, aparecerá en intellisense, etc., pero la diferencia es que será generada cada vez que compilemos el proyecto, asegurando así que siempre será correcta y completa.

lunes, 8 de marzo de 2021
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 marzo de 2021
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, 23 de febrero de 2021
.NET Core

Ya hace tiempo que se lanzó .NET 5, pero seguro que algunos os habéis dado cuenta de que cuando desde Visual Studio creamos determinados tipos de proyecto, como bibliotecas de clases o proyectos de consola, por defecto éstos utilizan como target .NET Core 3.1 en lugar de .NET 5.

No se trata de un error; desde Microsoft justifican esta decisión porque .NET 5 no es una versión LTS, y prefieren que por defecto los proyectos sean creados usando una versión con mayor tiempo de soporte, como .NET Core 3.1.

Esto tiene fácil solución, porque tras crearlo simplemente deberíamos acceder a las propiedades del proyecto o editar el archivo .csproj y modificar ajustar el target framework a nuestro antojo, pero, ¿cómo podríamos evitar tener que hacer esto cada vez?

lunes, 22 de febrero de 2021
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, 16 de febrero de 2021
Blazor

Es frecuente que alumnos de mi curso de Blazor en CampusMVP me pregunten sobre la existencia de bibliotecas de componentes que les ayuden a desarrollar aplicaciones profesionales más rápidamente, por lo que no podía pasar por alto la noticia que publicaban hace unos días los amigos de Radzen en su cuenta de Twitter:

Los componentes Radzen para Blazor son ahora open source

En efecto, ¡los componentes para Blazor de Radzen han pasado a ser open source y distribuidos bajo licencia MIT!

Para los que no los conozcan, Radzen es uno de los referentes en el mundo de las herramientas y componentes visuales para el desarrollo rápido de aplicaciones web, pero lo que nos ocupa ahora son el conjunto de más de 60 componentes visuales para Blazor Server y WebAssembly que ahora podremos utilizar de forma totalmente gratuita (bueno, aunque existen opciones para pagar por servicios de soporte profesional).

Componentes Radzen para Blazor

lunes, 15 de febrero de 2021
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, 9 de febrero de 2021
ASP.NET Core

Hoy voy a hablar de un cambio introducido en el framework hace ya algunos años, que, al menos en mi caso, pasó totalmente desapercibido en su momento y durante bastante tiempo después. Y he pensado que sería buena idea publicar sobre ello porque, como este mundo es así de grande, seguro que hay todavía algún despistado al que podría estar afectando a día de hoy y ni siquiera se ha dado cuenta :)

Como recordaréis, los atributos de validación [EmailAddress] y [Url], presentes en el espacio de nombres System.ComponentModel.DataAnnotations, los hemos utilizado durante años para asegurar que determinados valores de entrada eran direcciones de correo electrónico y URLs válidas, respectivamente:

public class Blog
{
    [Required, EmailAddress]
    public string ContactEmail { get; set; }
    [Required, Url]
    public string Url { get; set; }
}

Desde el principio de los tiempos, aún en ASP.NET "clásico", ambos atributos de validación utilizaban internamente complejas expresiones regulares para comprobar los valores, y la verdad es que funcionaban relativamente bien. Nuestras aplicaciones podían confiar en que valores que hubieran superado dichas validaciones serían, como mínimo, sintácticamente correctos y buenos candidatos a ser direcciones de correo o URLs válidas.

Pues bien, desde la llegada de NET 4.7.2, y luego en .NET Core, [EmailAddress] y [Url] ya no funcionan así. En palabras casi textuales del equipo de desarrollo, el objeto de estos dos atributos es simplemente prevenir algunos errores básicos al teclear, y no contemplar todas las posibilidades definidas en las respectivas RFC que describen la sintaxis de dichos valores.