Autor en Google+
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 ;)

16 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, 15 de noviembre de 2022
Compartir:
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.

Compartir:
martes, 25 de octubre de 2022
Compartir:
.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.

Compartir:
martes, 21 de junio de 2022
Compartir:
.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í!
Compartir:
martes, 14 de junio de 2022
Compartir:
.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.

Compartir:
martes, 22 de febrero de 2022
Compartir:
.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.
Compartir:
martes, 15 de febrero de 2022
Compartir:
.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.
Compartir:
martes, 28 de diciembre de 2021
Compartir:
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

Compartir:
martes, 21 de diciembre de 2021
Compartir:
.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.

Compartir:
martes, 19 de octubre de 2021
Compartir:
.NET Core

Hace unos días hablábamos de las directivas using globales, un interesante añadido a C# 10 que permite importar espacios de nombres en todos los archivos de código del proyecto, sin necesidad de repetir cientos de veces las mismas líneas en sus encabezados. Simplemente, si un namespace es interesante para nuestro proyecto, lo declaramos como global en algún punto y será lo mismo que si lo hubiéramos hecho en cada uno de los archivos .cs:

global using System;
global using System.Text;
global using System.Text.Json;
global using MyProject.Model;
...

Bien podían haberlo dejado aquí porque ya es una mejora sustancial respecto a lo que tenemos, pero no, el equipo de diseño de C# sigue introduciendo detalles que pueden hacernos la vida más sencilla. Es el caso de los implicit usings que, de la misma forma, acompañan a .NET 6 y C# 10.

Compartir:
martes, 5 de octubre de 2021
Compartir:

.NET CoreSeguro que estáis acostumbrados a ver y escribir las, a veces extensas, listas de directivas using encabezando vuestros archivos de código fuente C#. Aunque ciertamente los entornos de desarrollo actuales son de bastante ayuda a la hora de introducirlos e incluso a veces nos permiten colapsarlos, son unos grandes consumidores del valioso espacio vertical de nuestros monitores:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// ... (muchos using más)

namespace MyApplication
{
    public class MyClass
    {
        ...
    }
}

Pero si habéis trabajado con Razor, ya sea para crear vistas MVC/Razor Pages o bien desde Blazor, seguro que os habrán encantado los archivos tipo _ViewImports.cshtml o _Imports.razor, pues permiten introducir directivas que se apliquen a todos los archivos Razor del proyecto. 

¿No sería buena idea llevar esto mismo a nivel del lenguaje?

Compartir:
martes, 29 de junio de 2021
Compartir:
.NET Core

Me encanta que el lenguaje C# vaya introduciendo características que consiguen que cada vez tengamos que escribir menos para conseguir lo mismo, y, sobre todo, si la legibilidad posterior del código no se ve comprometida.

Uno de estos casos son los recientes target-typed new expressions, o expresiones new con el tipo del destino, que básicamente permite evitar la introducción del tipo de datos al usar el constructor de una clase, siempre que el compilador sea capaz de inferirlo por su contexto.

Vamos a echarle un vistazo en este post.

Compartir:
martes, 1 de junio de 2021
Compartir:
.NET Core

Desde C# 7 podemos emplear patrones en expresiones is o bloques switch para especificar las condiciones que deseamos comprobar, y cada nueva versión del lenguaje sigue introduciendo novedades al pattern matching, haciéndolo cada vez más sencillo y cómodo de utilizar.

En particular, C# 9 ha añadido un montón de características interesantes destinadas a facilitar el uso de patrones, pero en este post vamos a centrarnos en las dos más importantes: los combinadores de patrones y los patrones relacionales.

Compartir:
martes, 25 de mayo de 2021
Compartir:
.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
}

Compartir:
martes, 9 de marzo de 2021
Compartir:
.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.

Compartir:
martes, 24 de noviembre de 2020
Compartir:
Blazor

Hace unos días fue lanzada la nueva versión de ASP.NET Core basada en el flamante .NET 5, que incluye un buen número de novedades para los desarrolladores Blazor, algunas de ellas bastante jugosas.

En este post vamos a ver por encima las que creo que son más destacables en esta nueva entrega:

  1. .NET 5 y mejoras de rendimiento
  2. CSS Isolation
  3. JavaScript Isolation
  4. Virtualización
  5. InputRadio & InputRadioGroup
  6. Soporte para IAsyncDisposable
  7. Soporte para upload de archivos
  8. Control del foco
  9. Parámetros de ruta catch-all
  10. Protected browser storage
  11. Prerenderización WebAssembly
  12. Lazy loading de áreas de aplicación en Web Assembly
  13. Otros cambios y mejoras
¡Vamos allá!
Compartir:
sábado, 28 de diciembre de 2019
Compartir:
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?
Compartir:
martes, 26 de noviembre de 2019
Compartir:
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...
Compartir:
martes, 12 de noviembre de 2019
Compartir:
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í.
Compartir:
martes, 22 de octubre de 2019
Compartir:
.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.
Compartir:
martes, 15 de octubre de 2019
Compartir:
.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";

Compartir: