0

Asp.Net 7 Preview 7

Como no podía ser menos, tenemos novedades también de ASP.Net. Tenemos muchísimas novedades entre ellas: Nueva página de carga de Blazor WebAssembly, Modificadores get/set/after del enlace de datos de Blazor, Mejoras en la virtualización de Blazor, Pase el estado usando NavigationManager, Compatibilidad adicional con, System.Security.Cryptography en WebAssembly, Plantillas Angular y React actualizadas
Rendimiento de transcodificación gRPC JSON, La autenticación utilizará un esquema único como DefaultScheme, Compatibilidad con IFormFile/IFormFileCollection para solicitudes autenticadas en API mínimas, Nuevo servicio de detalles de problemas, sctualizaciones de middleware de diagnóstico y Nuevas interfaces HttpResults.

Nueva página de carga de Blazor WebAssembly

En Blazor WebAssembly tenemos una nueva interfaz de usuario de carga que muestra el progreso de la carga de la aplicación. Es excelente.

Esta nueva pantalla de carga implementa con HTML y CSS en la plantilla de Blazor WebAssembly mediante dos nuevas propiedades personalizadas de CSS (variables) proporcionadas por Blazor WebAssembly:

  • –blazor-load-percentage: el porcentaje de archivos de aplicaciones cargados.
  • –blazor-load-percentage-text: el porcentaje de archivos de aplicaciones cargados.

Con estas variables CSS, podemos configurar la interfaz de usuario de carga que coincida con el estilo de nuestras aplicaciones Blazor WebAssembly.

Modificadores get/set/after del enlace de datos de Blazor

Tenemos una potente función de enlace de datos para crear enlaces bidireccionales entre elementos de la interfaz de usuario o parámetros de componentes con objetos .NET. En .NET 7, ahora podemos ejecutar fácilmente la lógica asíncrona después de que se haya completado un evento de enlace utilizando el nuevo modificador @bind:after:

<input @bind="searchText" @bind:after="PerformSearch" />

@code {
    string searchText;

    async Task PerformSearch()
    {
        // ... do something asynchronously with 'searchText' ...
    }
}

Después de que se detecten cambios en el texto de búsqueda, el método asíncrono PerformSearch se ejecutará automáticamente.

También es más sencillo configurar el enlace para los parámetros de los componentes. Los componentes pueden admitir el enlace de datos bidireccional definiendo un par de parámetros para el valor y para una devolución de llamada que se llama cuando cambia el valor. Los nuevos modificadores @bind:get y @bind:set ahora hacen que sea trivial crear parámetros de componentes que se vinculen a un elemento de interfaz de usuario subyacente:

<input @bind:get="Value" @bind:set="ValueChanged" />

@code {
    [Parameter] public TValue Value { get; set; }
    [Parameter] public EventCallback<TValue> ValueChanged { get; set; }
}

Los modificadores @bind:get y @bind:set siempre se usan juntos. El modificador @bind:get especifica el valor al que vincularse y el modificador @bind:set especifica una devolución de llamada que se llama cuando cambia el valor.

Mejoras en la virtualización de Blazor

El componente Virtualize de Blazor representa un elemento espaciador para definir la altura vertical de la región de desplazamiento. De forma predeterminada, usamos un elemento div como este:

<div style="height: 12345px"></div>

En algunos casos, es posible que el elemento principal no permita elementos div secundarios. Por ejemplo, el elemento principal podría ser tbody, que solo permite elementos secundarios tr. Para estos casos, podemos usar el nuevo parámetro SpacerElement para configurar el elemento espaciador que usa Virtualize:

<tbody>
  <Virtualize SpacerElement="tr">...</Virtualize>
</tbody>

Pase el estado usando NavigationManager

Ahora podemos pasar el estado al navegar en las aplicaciones mediante NavigationManager.

navigationManager.NavigateTo("/orders", new NavigationOptions { HistoryEntryState = "My state" });

El mecanismo permite una comunicación sencilla entre diferentes páginas. El estado especificado se inserta en la pila del historial del navegador para que se pueda acceder a él más tarde mediante la propiedad NavigationManager.HistoryEntryState o la propiedad LocationChangedEventArgs.HistoryEntryState al escuchar eventos de cambio de ubicación.

Compatibilidad adicional con System.Security.Cryptography en WebAssembly

.NET 7 ahora permite más algoritmos criptográficos aprovechando SubtleCrypto cuando es posible y recurriendo a una implementación de .NET cuando no se puede usar SubtleCrypto. Es esta preview los siguientes algoritmos ahora son compatibles con WebAssembly:  SHA1, SHA256, SHA384, SHA512, HMACSHA1, HMACSHA256, HMACSHA384, HMACSHA512, Aes (only CBC mode is supported), Rfc2898DeriveBytes (PBKDF2), HKDF.

Rendimiento de transcodificación gRPC JSON

gRPC JSON transcoding is a new feature in .NET 7 for turning gRPC APIs into RESTful APIs.

Se mejoró el rendimiento y el uso de la memoria al serializar mensajes. La transcodificación gRPC JSON serializa los mensajes gRPC en un formato JSON estandarizado. Antes de esta versión, la transcodificación requería un JsonConverter personalizado para personalizar la serialización JSON.  Se reemplaza JsonConverter con la nueva función de personalización de contratos de System.Text.Json.

Los resultados de referencia a continuación comparan la serialización de mensajes gRPC antes y después de usar la personalización del contrato:

Un contrato personalizado y el serializador de alto rendimiento de System.Text.Json mejoran drásticamente el rendimiento y las asignaciones.

La autenticación utilizará un esquema único como DefaultScheme

Para simplificar la autenticación, cuando solo hay un único esquema de autenticación registrado, se utilizará automáticamente como DefaultScheme, esto elimina la necesidad de especificar DefaultScheme en AddAuthentication() en este caso. Este comportamiento se puede desactivar a través de:

AppContext.SetSwitch("Microsoft.AspNetCore.Authentication.SuppressAutoDefaultScheme")

Compatibilidad con IFormFile/IFormFileCollection para solicitudes autenticadas en API mínimas

En la Preview 1 vino con soporte para manejar cargas de archivos en Minimal API usando IFormFile e IFormFileCollection. En esta preview se agregó soporte para solicitudes de carga de archivos autenticados a API mínimas mediante un encabezado de autorización, un certificado de cliente o un encabezado de cookie.

Nuevo servicio de detalles de problemas

Nuevo servicio de detalles de problemas basado en la interfaz IProblemDetailsService para generar respuestas de detalles de problemas en nuestra aplicación.

Para agregar, usaremos el método de extensión AddProblemDetails en IServiceCollection.

builder.Services.AddProblemDetails();

Luego podemos escribir una respuesta de detalles del problema desde cualquier capa en su aplicación llamando a IProblemDetailsService.WriteAsync. 

httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;

if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
    return problemDetailsService.WriteAsync(new { HttpContext = httpContext });
}

return ValueTask.CompletedTask;

Podemos personalizar las respuestas (incluidas las respuestas generadas automáticamente para los controladores de API) mediante ProblemDetailsOptions:

builder.Services.AddProblemDetails(options =>
{
    options.CustomizeProblemDetails = (context) => 
    {
       context.ProblemDetails.Extensions.Add("my-extension", new { Property = "value" });
    };
});

Por otro lado, podemos crear nuestra propia implementación IProblemDetailsWriter para personalizaciones avanzadas:

public class CustomWriter : IProblemDetailsWriter
{
    // Indicates that only responses with StatusCode == 400
    // will be handled by this writer. All others will be
    // handled by different registered writers if available.
    public bool CanWrite(ProblemDetailsContext context) 
        => context.HttpContext.Response.StatusCode == 400;

    public Task WriteAsync(ProblemDetailsContext context)
    {
        //Additional customizations

        // Write to the response
        context.HttpResponse.Response.WriteAsJsonAsync(context.ProblemDetails);
    }        
}

Registreamoes cualquier implementación de IProblemDetailsWriter antes de la llamada al método AddProblemDetails:

builder.Services.AddSingleton<IProblemDetailsWriter, CustomWriter>();
builder.Services.AddProblemDetails();

Actualizaciones de middleware de diagnóstico

El siguiente middleware se actualizó para generar respuestas HTTP de detalles del problema cuando se registra el nuevo servicio de detalles del problema (IProblemDetailsService):

  • ExceptionHandlerMiddleware: Genera una respuesta de detalles del problema cuando no se define un controlador personalizado, a menos que el cliente no lo acepte.
  • StatusCodePagesMiddleware: Genera una respuesta de detalles del problema de forma predeterminada, a menos que el cliente no la acepte.
  • DeveloperExceptionPageMiddleware: Genere una respuesta de detalles del problema cuando no se acepte text/html, a menos que no lo acepte el cliente.

Veamos un ejemplo, se configura la aplicación para generar una respuesta de detalles del problema para todas las respuestas de error del servidor y del cliente HTTP que aún no tienen un contenido de cuerpo:

var builder = WebApplication.CreateBuilder(args);

// Add services to the containers
builder.Services.AddControllers();
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

//Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapControllers();
app.Run();

Nuevas interfaces HttpResults

En la Preview 3, los tipos que implementan IResult en ASP.NET Core se hicieron públicos. En esta vista previa, presentamos nuevas interfaces en el espacio de nombres Microsoft.AspNetCore.Http.Http para describir los tipos de IResult:

  • Microsoft.AspNetCore.Http.IContentTypeHttpResult
  • Microsoft.AspNetCore.Http.IFileHttpResult
  • Microsoft.AspNetCore.Http.INestedHttpResult
  • Microsoft.AspNetCore.Http.IStatusCodeHttpResult
  • Microsoft.AspNetCore.Http.IValueHttpResult
  • Microsoft.AspNetCore.Http.IValueHttpResult<TValue>

Con estas interfaces, ahora tenemos una forma más generalizada de detectar el tipo IResult en tiempo de ejecución, que es un patrón común en las implementaciones de filtros.

app.MapGet("/weatherforecast", (int days) =>
{
    if (days <= 0)
    {
        return Results.BadRequest();
    }

    var forecast = Enumerable.Range(1, days.Value).Select(index =>
       new WeatherForecast (DateTime.Now.AddDays(index), Random.Shared.Next(-20, 55), "Cool"))
        .ToArray();
    return Results.Ok(forecast);
}).
AddEndpointFilter(async (context,next) =>
{
    var result = await next(context);

    return result switch
    {
        IValueHttpResult<WeatherForecast[]> weatherForecastResult => new WeatherHttpResult(weatherForecastResult.Value),
        _ => result
    };
});

internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)

Conclusiones

Son muchas las novedades para esta preview. Muchas de ellas en Blazor que cada vez va tomando más fuerza y presencia como herramienta. En próximos post veremos más detalles de la nueva versión de .NET.

Fernando Sonego

Deja una respuesta

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