[Article] Novedades! .Net 5 Preview 7

Llegó la preview número 7, según lo que nos comentan desde microsoft, está el es la penúltima versión previa. Esto quiere decir que nos queda una más antes de la versión Release Candidate. Veamos que tenemos de nuevo!

Algunas recomendaciones antes de empezar, para probar esta versión debemos tener instalado Visual Studio 2019 versión 16.7. Si estamos utilizando Visual Studio Code debemos actualizar la extensión  C# Extensions la última disponible.

NET 5.0

Rendimiento

De la mano de Stephen Toub, se publicó un reporte con los detalles en las mejoras de rendimiento que ha obtenido Net 5. Les dejo el link de la publicación de Stephen con los datos, es bastante extenso, pero vale la pena. Podrán ver en detalle cambios, por ejemplo, en el Garbage Collector, JIT, Runtime, Procesamiento de texto, objetos, etc.

 Performance Improvements in .NET 5

System.Text.Json

Tenemos 2 nuevas funcionalidades en el JSON API y hay muchas más para la versión Preview 8:

  • Ignorar valores predeterminados en propiedades en el serialización. Nos ayudará a reducir la serialización y reducir la transferencia. Topic Github.
  • Manejo de referencias circulares cuando manipulamos la serialización. Topic GitHub.

Garbage Collection (GC)

Ya podemos obtener la información en detalle de las colecciones que se han utilizado recientemente a través de un nuevo método: GC.GetGCMemoryInfo. Este, nos devolverá  el objeto GCMemoryInfo que posee la información sobre la memoria del equipo, la memoria dinámica y la colecciones más reciente.

Para poder reducir la latencia del GC y el uso del CPU en general, se hizo un ajuste pequeño, espera que sea de gran impacto. Topic GitHub.

RyuJIT

RyuJIT es el generador de código de ensamblaje para .Net, apuntado a chips Intel y ARM. La mayoría de apuntadas a rendimiento:

  • Generales
    • Permitir eludir algunas comprobaciones de límites. Ver.
    • Optimizar Enum.CompareTo después de ser reescrito en C# : el rendimiento no tiene que envidiarle a la implementación de C ++. Ver.
    • Mejora en la asignación de registros para estructuras. Ver.
    • Mejoras para la eliminación redundancia Inits. Ver.
    • Mejora de duplicación de cola. Ver.
    • Las estructuras basadas en pila copian el arreglo CQ. Ver.
    • Limpieza una asignación de campo muerto luego de eliminar las cero inicializaciones redundantes. Ver.
  • ARM64
    • Implementar la mayoría de los intrínsecos «por elemento». Ver.
    • Implemente fcvtxn, fcvtxn2, sqabs, sqneg, suqadd, usqadd intrinsics – # 38010 , # 38110
    • Optimizar SpanHelpers.IndexOf (byte), SpanHelpers.IndexOf (char). Ver.
    • Optimizado SpanHelpers.IndexOfAny (byte). Ver.
    • Optimizado WithLower, WithUpper, Create, AsInt64, AsUInt64, AsDouble. Ver.
    • Optimizar AsVector, AsVector128, GetUpper, As y WithElement. Ver.

ASP.NET

Las aplicaciones Blazor WebAssembly ahora tienen target a .NET 5

En esta versión ahora podemos apuntar nuestro proyecto a la versión de .Net 5 teniendo acceso todo el conjunto de API del framework. Si bien, Blazor WebAssembly es compatible con la gran mayoría de API, todavía faltan soportar algunas funcionalidades. En este último caso, recibiremos la excepción PlatformNotSupportedException en tiempo de ejecución.

Depuración actualizada para Blazor Assembly

Cuando trabajamos con un proyecto Blazor WebAssembly en VS Code usabamos la extensión JavaScript Debugger (Nightly) para depurar. Ahora no es necesario, ha sido integrada a la herramienta. Si deseamos, podemos desinstalar el extensión, pero todavía es necesario habilitar la extensión de vista previa de depurador en javascript desde la configuración de Visual Studio Code.

Mejoras de accesibilidad de Blazor

Los componentes de entrada de Blazor integrados que derivan de InputBase ahora se procesan automáticamente cuando falla la validación aria-invalid.

Mejor Performance de Blazor

Se trabajó sobre mejoras de rendimiento en tiempo de ejecución para Blazor WebAssembly en .Net 5. Se seguirá trabajando en este tipo de mejoras. Algunas de las mejoras son:

  • Ejecución .NET runtime.
  • Serialización JSON.
  • Interoperabilidad JavaScript.
  • Representación de componentes Blazor.

Mejoras de rendimiento de autenticación de certificado

Se agregó almacenamiento en caché a la autenticación de certificados. Esto da como resultado aumento de rendimiento significativo para el manejo de estos. Se ha reportado hasta un 400% de aumento de rendimiento una vez activado el almacenamiento de cache. Impresionante!

Lo más interesante, es que no necesitamos ningún cambio radical para aprovechar esta mejora, esta funcionalidad está activa de manera predeterminada y puede ser configurada o deshabilitada si lo deseamos.

Envío de tramas HTTP/2 PING

Esta funcionalidad permite saber si una conexión inactiva sigue estando activa. En secuencias gRPC, a veces, se encuentra activas de forma intermitente. Esto no permite saber si todavia esta vivo el proceso.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                options.Limits.Http2.KeepAlivePingInterval = TimeSpan.FromSeconds(10);
                options.Limits.Http2.KeepAlivePingTimeout = TimeSpan.FromSeconds(1);
            });
            webBuilder.UseStartup<Startup>();
        });

Soporte para EndPoints en el transporte de Sockets Kestrel

Ahora es posible integrar, en linux, Systemd sin la necesidad de usar libuv. Esto es posible gracias a la nueva API que se encuentra en System.Net.Sockets.

Decodificación de encabezados personalizado sen Kestrel

Se agregó la capacidad de interpretar los encabezados con System.Text.Encoding.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                options.RequestHeaderEncodingSelector = encoding =>
                {
                    switch (encoding)
                    {
                        case "Host":
                            return System.Text.Encoding.Latin1;
                        default:
                            return System.Text.Encoding.UTF8;
                    }
                };
            });
            webBuilder.UseStartup<Startup>();
        });

Además

  • CompareAttribute podemos aplicarla a propiedades en el modelo Razor Page.
  • Los parámetros y propiedades vinculados desde el cuerpo se consideran obligatorios por defecto.
  • Se comenzaron a aplicar anotaciones nullable a los ensamblados de ASP.NET Core. 
  • Cuando la autorización utiliza el enrutamiento por endpoint ahora recibe la HttpContext. Esto permite que el middleware de autorización acceda a RouteData y a otras propiedades HttpContext que no eran accesibles a través de la clase Endpoint. Podemos obtener el la info del contexto mediante context.GetEndpoint().
  • System.Diagnostics.Activity tiene de formato predeterminado de W3C dando como resultado una mejor interoperabilidad con ASP.NET.
  • FromBodyAttribute admite configurar una opción que permita que los parámetros o propiedades se consideren opcionales:
public IActionResult Post([FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)] MyModel model) { ... }

Entity Framework

DbContextFactory

Nuevos métodos AddDbContextFactory y AddPooledDbContextFactory que permiten registrar instancias de DbContext en los contenedores de inyección de dependencia:

services.AddDbContextFactory<SomeDbContext>(b =>
    b.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test"));

Ahora los controlladores de ASP.Net pueden tener dependencias IDbContextFactory<TContext> mediante el constructor del servicio:

public class MyController
{
    private readonly IDbContextFactory<SomeDbContext> _contextFactory;

    public MyController(IDbContextFactory<SomeDbContext> contextFactory)
    {
        _contextFactory = contextFactory;
    }
}

Las instancias de DbContext pueden ser creadas y usadas a necesidad:

public void DoSomehing()
{
    using (var context = _contextFactory.CreateDbContext())
    {
        // ...            
    }
}

Algo que debemos tener en cuenta, las instancias de DbContext no se crearán de manera administrada por el proveedor de servicio, por esto, deben ser eliminadas por la aplicación.

Podemos agrupar instancias de DbContext por medio de AddPooledDbContextFactory al igual que con AddDbContextPool y no olvidarse que tienen las mismas limitaciones.

Restablecer estado de DbContext

Nos permite eliminar el tacking de todas las entidades utilizadas por medio de ChangeTracker.Clear().  Según nos comenta el equipo Entity Framework, esto no debería ser necesario si mantenemos la buena práctica de crear una instancia de corta duración para las unidades de trabajo, pero, si por alguna razón debemos hacerlo, ahora tenemos disponible esta funcionalidad.

Nuevo patrón para valores predeterminados en store-generated

En EF podíamos establecer un valor por default para una columna y algún valor de restricción determinado. Para esto se utilizaba el valor predeterminado correspondiente al tipo del CLR. Si el valor predeterminado no está en el CLR se utiliza el que está configurado en la base de datos.

Esto traía algunos problemas con los valores predeterminados en el CLR, como por ejemplo en las propiedades que eran del tipo bool. Ahora nos permite que el campo sea nullable. En el ejemplo, el campo es nullable pero la propiedad no lo es, si nunca se establece el valor en la propiedad, se tomará el valor de la base de datos.

public class Blog
{
    private bool? _isValid;

    public bool IsValid
    {
        get => _isValid ?? false;
        set => _isValid = value;
    }
}

Puntos de guardado

Para tener un mejor control de transacciones ahora podemos utilizar puntos de guardado. Podemos crearlos, liberarlo o revertirlos manualmente. Por otro lado, podemos hacer reintentos cuando ejecutamos SaveChages.

context.Database.CreateSavepoint("MySavePoint");

Partition Keys en Cosmos

Tenemos la posiblidad de incluir la Partition Key en nuestro modelo, esta se incluye en la PK del tipo de entidad y se usa para mejorar el rendimiento en las consultas.

modelBuilder.Entity<Customer>().HasPartitionKey(b => b.AlternateKey)

Configuración del cosmos

Nuevas mejoras en la conexiones de Cosmos y sus configuraciones. Hasta ahora, era necesario que endpoint y la key sean especificadaws al conectarse a la base de datos de Cosmos. Ahora podemos utilizar una cadena de conexión en su lugar.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseCosmos("my-cosmos-connection-string", "MyDb",
            cosmosOptionsBuilder =>
            {
                cosmosOptionsBuilder.WebProxy(myProxyInstance);
            });

Más cosas que podemos configurar:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseCosmos("my-cosmos-connection-string", "MyDb",
            cosmosOptionsBuilder =>
            {
                cosmosOptionsBuilder.LimitToEndpoint();
                cosmosOptionsBuilder.RequestTimeout(requestTimeout);
                cosmosOptionsBuilder.OpenTcpConnectionTimeout(timeout);
                cosmosOptionsBuilder.IdleTcpConnectionTimeout(timeout);
                cosmosOptionsBuilder.GatewayModeMaxConnectionLimit(connectionLimit);
                cosmosOptionsBuilder.MaxTcpConnectionsPerEndpoint(connectionLimit);
                cosmosOptionsBuilder.MaxRequestsPerTcpConnection(requestLimit);
            });

Scaffold-DbContext Singularización de objetos

Hasta ahora, cuando mapeamos nuestro contexto, se respetaban los mismos nombres de la las entidades de la base de datos. Por ejemplo, People o Addresses, mantenían el mismo nombre en lugar de Person o Address. Era posible configurarlo mediante un servicio de registro. Pero ahora, podemos usar el paquete Humanizer que será el servicio de pluralización predeterminado. Esto quiere decir que se aplica ingeniería inversa a los tipos de entidades dando como resultado, en caso de tener People y Addresses, Person y Address.

Conclusiones

A pesar de haber tenido menos cantidad de novedades que la anterior, están han sido bastante importantes. Las más interesantes son todas las relacionadas con la base y aumento de performance del framework. Los invito a probar esta nueva versión, hay que apurarse porque la preview 8 saldrá en poco tiempo.

Fernando Sonego

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *