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

17 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!
Mostrando entradas con la etiqueta novedades. Mostrar todas las entradas
Mostrando entradas con la etiqueta novedades. Mostrar todas las entradas
martes, 12 de marzo de 2024
Blazor

Los que llevamos muchos años programando con ASP.NET/ASP.NET Core y todos los frameworks que han ido surgiendo en su ecosistema, estamos familiarizados con el concepto de "contexto HTTP".

Materializado en forma de objeto de tipo HttpContext, el contexto HTTP es una de las piezas fundamentales de la infraestructura de ASP.NET Core, y nos permite acceder a información sobre la petición HTTP que se está procesando, como los encabezados, el cuerpo de la petición, las cookies, etc., así como base para la generación de la propia respuesta a través de su propiedad Response. En muchos escenarios, se trata de un recurso imprescindible para procesar la petición de la forma adecuada, por lo que estamos acostumbrados a usarlo cuando es conveniente.

Sin embargo, cuando saltamos a Blazor, pronto nos llama la atención que HttpContext no está disponible. Y si lo pensamos, esto tiene bastante sentido en los dos modos de renderización clásicos:

  • En Blazor WebAssembly, dado que el código .NET se ejecuta directamente en el cliente, no existen peticiones que procesar y, por tanto, no existe HttpContext. Se trata de una abstracción que sólo existe en el backend.

  • En Blazor Server, aunque el código se está ejecutando en el servidor, tampoco tenemos disponible HttpContext porque realmente no existen peticiones: el lado cliente y servidor se comunican mediante un canal websockets implementado con SignalR, que es por donde viajan ascendentemente las acciones realizadas por el usuario y descendentemente las actualizaciones del DOM de la página.

Con la llegada de Blazor 8, ha tomado relevancia el nuevo modo de renderizado, llamado Server-Side Rendering (SSR) o renderización en el lado servidor, que ya vimos por aquí hace algún tiempo.

Como ya sabemos, el funcionamiento de Blazor SSR es similar al de otros frameworks de backend puros, como MVC o Razor Pages: el servidor recibe la petición, la procesa y genera una respuesta HTML que se envía al cliente. En este escenario, durante el proceso del componente Blazor sí existe un contexto HTTP.

martes, 5 de marzo de 2024
Blazor

En Blazor es posible acceder a valores de parámetros de la query string exclusivamente desde componentes de tipo página, es decir, aquellos definidos con la directiva @page.

Para ello, bastaba con declarar una propiedad pública y decorarla con los atributos [Parameter] y [SupplyParameterFromQuery]. Por ejemplo, si desde una página quisiésemos obtener el valor del parámetro term de la query string, podríamos hacerlo de la siguiente forma:


@page "/search"

<p>Searching term: @Term</p>

@code {

    [Parameter]
    [SupplyParameterFromQuery]
    public string Term { get; set; }
}

Sin embargo, como sabéis, esto no funcionaba si intentábamos acceder así a estos parámetros desde componentes que no fueran páginas, es decir, que no fueran instanciados por el sistema de routing.

martes, 13 de febrero de 2024
Blazor

Como seguramente sabréis, Blazor es la gran apuesta de Microsoft para el desarrollo de aplicaciones web con .NET. Sólo hay que ver la cantidad de novedades que han introducido en la última versión para darse cuenta de que están poniendo toda la carne en el asador y, de alguna forma, está convirtiéndose en la opción preferida para el desarrollo de este tipo de aplicaciones.

Pues bien, es un placer anunciaros que, tras varios meses de preparación, hace unos días hemos puesto en marcha el nuevo curso de desarrollo de aplicaciones Web con Blazor en .NET 8, como siempre, en CampusMVP.

Ha sido un trabajo duro, porque esta última versión ha venida cargada de novedades (sobre todo en lo relativo al nuevo modelo unificado propuesto por las Blazor Web Apps) y hemos tenido que revisar en profundidad y reescribir parte del contenido del curso, rehacer ejemplos y regrabar material audiovisual, todo con el objetivo de seguir siendo el mejor y más completo curso de Blazor del mercado.

En este post voy a intentar responder a las siguientes preguntas:

martes, 30 de enero de 2024
C#

Hace ya algunos años, con la llegada de C# 9, los records nos mostraron otra forma de crear objetos distinta a los clásicos constructores. Ya entonces, y únicamente en aquél ámbito, se comenzó a hablar de primary constructors, pero no ha sido hasta C# 12 cuando se ha implementado de forma completa esta característica en el lenguaje.

En este post vamos a ver de qué se trata, cómo podemos utilizarlos y peculiaridades que hay que tener en cuenta.

martes, 19 de diciembre de 2023
C#

Poco a poco vamos haciéndonos con las novedades de C# 12, y en esta ocasión nos centraremos en una nueva sintaxis que proporciona una forma concisa y rápida para declarar los elementos de una colección.

Ya os adelanto que si sois de los que siempre han envidiado otros lenguajes por la facilidad con la que se declaran los elementos de un colección o array, estáis de enhorabuena ;) Porque, sin duda, hay formas de hacerlo menos verbosas que las que hemos tenido hasta ahora en C#:

// JavaScript:
let numbers = [1, 2, 3];

// Python:
numbers = [1, 2, 3]

// PHP:
$array = [1, 2, 3];

// Rust:
let array = [1, 2, 3];

En C# 11 y anteriores, la creación de un array es normalmente más farragosa, porque de alguna forma u otra requiere que especifiquemos que se trata de un nuevo array y, si la inferencia no lo permite, el tipo de los elementos que contendrá:

// Forma verbosa y redundante:
int[] arr1 = new int[3] { 1, 2, 3 };

// Forma clásica, usando 'var' y especificando número y tipo elementos:
var arr2 = new int[3] { 1, 2, 3 };

// Dejamos que el compilador detecte el número de elementos:
var arr3 = new int[] { 1, 2, 3 };

// Dejamos que la inferencia de tipos determine el tipo de los elementos:
var arr4 = new [] { 1, 2, 3 };

// O bien, la más concisa, usando la sintaxis con llaves (sólo válida para arrays):
int[] arr5 = { 1, 2, 3 };

martes, 28 de noviembre de 2023
Blazor

Como sabéis, hasta ahora, los componentes Blazor podían ejecutarse en dos tipos de hosting distintos, Blazor Server y Blazor WebAssembly. Aunque cada uno tiene sus escenarios ideales de uso, ambos enfoques conseguían lo mismo, implementar Single Page Applications en C#, sin necesidad de utilizar JavaScript (bueno, o al menos, minimizando radicalmente su uso):

  • Con Blazor Server, se mantiene en el servidor una copia del DOM de cada usuario conectado, de forma que C# puede manipularlo directamente. Luego, mediante una conexión websockets, se sincronizan los cambios con el cliente.
  • Blazor WebAssembly lleva al navegador el runtime de .NET, las bibliotecas base y los ensamblados de la aplicación, por lo que todo se ejecuta directamente en el lado cliente gracias a WebAssembly.

Estas dos formas de ejecutar componentes son muy apropiadas cuando se trata de elementos interactivos, capaces de responder a eventos de usuarios y con capacidad de actualizar el contenido de la página. Sin embargo, son muy poco eficientes cuando se trata de páginas estáticas que no requieren interacción con el usuario:

  • Para poder mostrar en el navegador un contenido, en Blazor Server hay que esperar a que el lado cliente descargue la página contenedora, un archivo JavaScript y se establezca la conexión websockets con el servidor, tras lo cual se enviará el contenido de la página.

  • En Blazor WebAssembly, el cliente debe descargar la página contenedora, los ensamblados y todo el entorno de ejecución de .NET y lanzarlo todo sobre WebAssembly. En este momento se puede mostrar el contenido de la página.

martes, 17 de octubre de 2023
.NET

Sabemos que está feo y no sea especialmente recomendable en muchos casos, pero hay veces en las que es totalmente necesario acceder a miembros privados de una clase. Por ejemplo, sería un requisito  imprescindible si fuéramos a implementar un serializador o deserializador personalizado, o necesitásemos clonar objetos, o simplemente realizar pruebas unitarias a una clase que no ha sido diseñada para ello.

Para conseguirlo, siempre hemos utilizado los mecanismos de introspección de .NET, conocidos por todos como reflexión o por su término en inglés reflection. Por ejemplo, imaginemos una clase como la siguiente, virtualmente inexpugnable:

public class BlackBox
{
    private string _message = "This is a private message";
    private void ShowMessage(string msg) => Console.WriteLine(msg);
    public override string ToString() => _message;
}

Aunque a priori no podemos hacer nada con ella desde fuera, usando reflexión podríamos acceder sin problema a sus miembros privados, ya sean propiedades, campos, métodos o cualquier tipo de elemento, como podemos ver en el siguiente ejemplo:

var instance = new BlackBox();

// Obtenemos el valor del campo privado _message:
var field = typeof(BlackBox)
    .GetField("_message", BindingFlags.NonPublic | BindingFlags.Instance);
var value = field!.GetValue(instance);

// Ahora llamamos al método privado ShowMessage():
var method = typeof(BlackBox)
    .GetMethod("ShowMessage", BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(instance, [value]);

// Al ejecutar, se nuestra en consola: "This is a private message"

Sin embargo, de todos es sabido que la reflexión es un mecanismo muy lento, a veces farragoso en su implementación y, sobre todo, incompatible con tree-shaking, que es como se suele llamar la técnica que usan los compiladores de eliminar del código final todas las clases, métodos y propiedades que no se utilizan en el código final. Esta técnica va tomando cada vez más relevancia conforme los compiladores son capaces de crear directamente ejecutables nativos puros, porque permiten reducir de forma considerable el peso de los artefactos creados.

Por esta razón, en .NET 8 se ha incluido una nueva fórmula para acceder a miembros privados, mucho más eficiente y amistosa con AOT, porque se lleva a tiempo de compilación algo que antes obligatoriamente se resolvía en tiempo de ejecución.

martes, 26 de septiembre de 2023
.NET

Seguro que más de una vez habéis tenido que construir una abstracción sobre DateTime para poder controlar apropiadamente la obtención de la fecha/hora actual y otras operaciones relacionadas con el tiempo.

Suelen ser bastante útiles cuando creamos pruebas unitarias de métodos que dependan del momento actual. Por ejemplo, ¿cómo testearíamos de forma automática que las dos líneas de ejecución del siguiente método DoSomething() funcionan correctamente? Sería imposible salvo que ejecutásemos las pruebas a una hora determinada, algo que se antoja complicado 😉

public class MyClass
{
    public string DoSomething()
    {
        var now = DateTime.Now;
        return now.Second == 0
            ? "A new minute is starting"
            : "Current second " + now.Second;
    }
}  

Sin duda, una forma mejor y más test friendly sería contar con una abstracción sobre el proveedor de tiempos capaz de retornar la fecha y hora actual, por ejemplo:

public interface IDateTimeProvider
{
    DateTime GetCurrentDateTime();
}

De esta forma, podríamos reescribir la clase MyClass de forma que recibiera por inyección de dependencias nuestro proveedor IDateTimeProvider. Así sería realmente sencillo crear un par de pruebas unitarias que, suministrando los valores correctos a través de esta dependencia, podrían recrear los escenarios a cubrir:

public class MyClass
{
    private readonly IDateTimeServices _dateTimeServices;
    public TimeHelpers(IDateTimeServices dateTimeServices)
    {
        _dateTimeServices = dateTimeServices;
    }
    public string DoSomething()
    {
        var now = _dateTimeServices.GetCurrentDateTime();
        return now.Second == 0
            ? "A new minute is starting"
            : "Current second " + now.Second;
    }
}  

Aunque hacerlo de esta manera en nuestras aplicaciones es lo ideal, hay partes que se quedarían fuera de esta posibilidad, como las bibliotecas de terceros que de alguna forma dependan de las funcionalidades proporcionadas por DateTime.

Por esta razón, .NET 8 va a introducir una abstracción que nos permitirá gestionar estos escenarios de forma más homogénea y generalizada en aplicaciones y componentes .NET. 

Os presento la clase abstracta TimeProvider 😁

martes, 18 de abril de 2023
Entity Framework

Versión tras versión, Entity Framework Core sigue introduciendo novedades que lo hacen cada vez más potente y atractivo para los desarrolladores. Sin ir más lejos, EF7, la última entrega disponible, incorporó bastantes mejoras en términos de rendimiento, soporte para columnas JSON, mapeo TPC, mapeo a procedimientos almacenados y muchas otras.

Pero una de las novedades que me resultó más interesante, quizás por ser muy esperada, fue la posibilidad de realizar borrados y actualizaciones de forma masiva sin tener que recurrir a lanzar directamente comandos SQL. O dicho de otra forma, con EF7 podremos ejecutar sentencias DELETE y UPDATE sobre la base de datos sin abandonar LINQ :)

martes, 21 de marzo de 2023
C#

El pattern matching de C# proporciona la capacidad de analizar expresiones para ver si cumplen determinados "patrones" o presentan características determinadas. Podéis ver algunos ejemplos interesantes en el post Un vistazo a los patrones relacionales y combinadores.

Aunque ya los tengo bastante interiorizados y hago uso de ellos cuando toca, todavía no se me ha dado el caso de necesitar los patrones de listas, introducidos hace unos meses en C# 11. Así que no está de más echarles un vistazo para cuando se dé la ocasión 😉

martes, 17 de enero de 2023
ASP.NET Core

Desde la llegada de ASP.NET Core, hace ya algunos años, muchos hemos echado de menos el filtro [OutputCache] de ASP.NET MVC "clásico". Aunque el nuevo framework ofrece alternativas interesantes para gestionar la caché tanto en el lado cliente como en el servidor, ninguna aportaba las funcionalidades que este filtro nos ofrecía.

Como recordaréis, a diferencia de las opciones ofrecidas actualmente por ASP.NET Core, como el filtro [ResponseCache] o el middleware ResponseCaching, que básicamente se regían por los encabezados presentes en peticiones y respuestas HTTP, el filtro [OutputCache] es una solución de caché residente exclusivamente en el servidor. En este caso, la decisión de si el resultado a una petición se almacena o no se realiza completamente desde la aplicación, de forma totalmente independiente a encabezados o requisitos procedentes del lado cliente.

En ASP.NET Core 7 este filtro ha vuelto a la vida en forma de middleware, que ofrece sus funcionalidades con dos sabores distintos:

  • Con anotaciones aplicables a endpoints implementados con Minimal API.
  • Como filtro, aplicable a controladores y acciones MVC.

Echémosles un vistazo.

martes, 13 de diciembre de 2022
C#

Otra de las novedades del flamante C# 11 viene a romper una limitación histórica: la ausencia de tipos genéricos en la definición de atributos.

Hasta esta versión del lenguaje, cuando necesitábamos introducir referencias a tipos de datos en un atributo, debíamos pasar obligatoriamente por el uso de un System.Type y el verboso operador typeof(). Además de incómodo, no había forma de limitar los tipos suministrados, dando lugar a errores en tiempo de ejecución que bien podrían haber sido resueltos el compilación con las herramientas apropiadas.

Dicho así quizás sea difícil de entender, pero veámoslo con un ejemplo.

martes, 15 de noviembre de 2022
C#

La llegada de C#11 viene acompañada de un buen número de novedades, algunas de ellas bastante jugosas, como los raw string literals o el nuevo modificador "file" que ya hemos ido viendo por aquí.

En esta ocasión, vamos a echar el vistazo a otra de las novedades que pueden resultar de bastante utilidad en nuestro día a día: los miembros requeridos.

martes, 25 de octubre de 2022
.NET

Modificadores de visibilidad habituales como internal, public o private nos acompañan desde los inicios de C#, permitiéndonos definir desde dónde queremos permitir el acceso a los tipos que definimos en nuestras aplicaciones. Así podemos indicar, por ejemplo, que una clase pueda ser visible sólo a miembros definidos en su mismo ensamblado, que pueda ser utilizada desde cualquier punto, o que un tipo anidado sólo pueda verse desde el interior de su clase contenedora.

Pues bien, C# 11 traerá novedades al respecto ;)

Disclaimer: lo que vamos a ver aquí es válido en la RC2 de .NET 7, pero aún podría sufrir algún cambio para la versión final, prevista para noviembre de 2022.

martes, 21 de junio de 2022
.NET

De casualidad me he topado con un interesante cambio que .NET 5 introdujo en los componentes de serialización y deserialización System.Text.Json y que, al menos para mí, pasó totalmente desapercibido en su momento. Por eso, he pensado que quizás sea buena idea dejarlo por aquí, por si hay algún despistado más al que pueda resultar útil.

Como seguro sabéis, al usar los componentes de System.Text.Json para serializar o deserializar una clase, utilizamos el atributo [JsonIgnore] para marcar las propiedades que queremos que sean ignoradas al convertir desde y hacia JSON.

Por ejemplo, dada la siguiente clase:

class User
{
    public int Id { get; set; }
    public string Email { get; set; }
    [JsonIgnore]
    public string Token { get; set; }
}

En ella estamos indicando expresamente que la propiedad Token debe ser ignorada, por lo que ésta no aparecerá si serializamos un objeto a JSON:

var user = new User { Id = 42, Email = "john@server.com", Token = "ABCDEF"};
Console.WriteLine(JsonSerializer.Serialize(user));

// Result:
{"Id":42,"Email":"john@server.com"}

Y lo mismo ocurre en sentido contrario:

var jsonStr = "{ \"Id\": 42, \"Email\": \"john@server.com\", \"Token\": \"ABCDEF\"}";
var user = JsonSerializer.Deserialize<User>(jsonStr);
// ¡user.Token es nulo aquí!
martes, 14 de junio de 2022
.NET

Visual Studio sigue introduciendo novedades versión tras versión, y es fácil que algunas de ellas nos pasen desapercibidas y tardemos algún tiempo en conocerlas, o incluso en verles la utilidad. Un ejemplo lo tenemos en los breakpoints temporales y dependientes, dos nuevos tipos de puntos de interrupción añadidos en la versión 2022 que pueden venirnos bien a la hora de depurar aplicaciones.

En este post vamos a echarles un vistazo, por si hay algún despistado más que no se haya dado cuenta de estas novedades.

martes, 22 de febrero de 2022
.NET

Aún no hemos terminado de asimilar las novedades de C# 10, cuando ya empiezan a llegar noticias de lo que encontraremos en la próxima versión, C# 11, que si todo va bien se lanzará en noviembre de este año.

Una de las que más me ha llamado la atención de momento es la llegada de raw string literals, una característica que mejorará bastante la posibilidad de escribir constantes de cadena multilínea en nuestro código.

Veamos en qué consiste.

Disclaimer: la nueva versión de C# está aún en desarrollo, y detalles de los que veamos aquí podrían cambiar antes de lanzarse definitivamente.
martes, 15 de febrero de 2022
.NET

Seguimos descubriendo novedades aparecidas con .NET 6, y ahora le toca el turno a la nueva clase PeriodicTimer, una fórmula para la ejecución de tareas periódicas en contextos asíncronos que evita el uso de los clásicos callbacks a los que nos tenía acostumbrados el framework.

Como recordaréis, .NET dispone de un buen número de formas de implementar temporizadores, o timers, para ejecutar tareas en intervalos periódicos. El más conocido probablemente sea el clásico System.Threading.Timer, en el que especificábamos el callback o método que debía ejecutarse en cada intervalo de tiempo mediante un delegado (en el siguiente ejemplo, mediante una lambda):

var timer = new System.Threading.Timer(o =>
{
    Console.WriteLine("Hey! " + DateTime.Now.ToLongTimeString());
}, null, 0, 1000);

Console.ReadKey();
Hey! 12:25:51
Hey! 12:25:52
Hey! 12:25:53
Hey! 12:25:54
Hey! 12:25:55
_

Pero también existía System.Timers.Timer, que nos permitía lograr algo parecido, aunque esta el callback lo implementábamos mediante una suscripción al evento Elapsed del objeto:

var timer = new System.Timers.Timer(1000);
timer.Elapsed += (sender, eventArgs) =>
{
    Console.WriteLine("Hey! " + DateTime.Now.ToLongTimeString());
};
timer.Start();
Console.ReadKey();

Existían algunas fórmulas más específicas para plataformas concretas, como las clases System.Windows.Forms.Timer, System.Web.UI.Timer u otras. Sin embargo, todas coincidían en varias cosas:

  • Utilizaban callbacks de alguna u otra forma, lo que implica un cierto riesgo de leaks de memoria y problemas con los tiempos de vida de objetos cuando la cosa se complica.
  • Los callbacks no permitían código asíncrono, lo que podía llevarnos a luchar contra los engorrosos escenarios de ejecución de código asíncrono en entornos síncronos (async-over-sync).
  • Podían darse casos de superposición u overlapping entre las distintas ejecuciones, cuando éstas tardaban en completarse más que el intervalo de definido en el timer.
martes, 28 de diciembre de 2021
NET

Hace ya mucho tiempo que C# inició un interesante camino para conseguir reducir la cantidad de código necesario para hacer cosas frecuentes, introduciendo la capacidad de hacer implícitas determinadas construcciones y, por tanto, ahorrándonos tiempo y pulsaciones de teclas innecesarias.

En esta línea, todos recordaréis el tipado implícito, que tanto debate abrió en el lanzamiento de C# 3, hace ya casi quince años:

// Antes de C# 3
List<string> strings = new List<string>();

// Usando tipado implícito
var strings = new List<string>();

Bastante tiempo después, ya con C# 10, el lenguaje nos regaló una nueva característica que iba en la misma dirección, las expresiones new con el tipo destino. Éstas permitían construir objetos usando tipado implícito, aunque esta vez en el lado derecho de las expresiones:

// Antes de C# 10
public class MyClass
{
    private Invoice invoice = new Invoice(123);
    private Dictionary<string, Person> people = new Dictionary<string, Person>();
    ...
}

// Ahora
public class MyClass
{
    private Invoice invoice = new (123);
    private Dictionary<string, Person> people = new ();
    ...
}

También en C# 10 nos hemos encontrado con los using globales y using implícitos, características ambas que nos permiten economizar esfuerzos evitando la introducción repetitiva de directivas para la importación de namespaces en el código.

Pues bien, aquí viene la siguiente vuelta de tuerca :) Unas semanas atrás, Immo Landwerth (Program manager de .NET en Microsoft) sorprendía a todos con esta afirmación sobre una de las características principales del próximo C# 11:

Immo Landwerth announcing implicit dots

martes, 21 de diciembre de 2021
.NET

Parece que uno de los objetivos de C#10 es eliminar código de los archivos de código fuente de C#, simplificando su codificación y lectura. Lo hemos visto con la introducción de características como directivas using globales o los using implícitos: en ambos casos se ahorraba espacio en vertical sustituyendo los using declarados individualmente en cada archivo por directivas aplicadas de forma global al proyecto, bien de forma explícita o implícita.

En cambio, los espacios de nombre con ámbito de archivo o namespace declarations permiten ahorrar espacio en horizontal, evitando un nivel de indentación en el código que la mayoría de las veces es innecesario.