0

ASP.NET Core updates in .NET 7 Preview 3

Como siempre, de la mano de las novedades de .Net, llegan las novedades de Asp.Net. En este caso la versión Preview 3. Veamos las novedades más importantes de estas versión:

  • ‎Compatibilidad con filtros de controlador de rutas en Minimal API.
  • ‎Capacidad de prueba unitaria mejorada para manejadores de Minimal API.
  • ‎Enlazar mediante TryParse para controladores MVC y API‎.
  • ‎Nuevas sobrecargas‎: Results.Stream().
  • ‎Rendimiento HTTP/2 mejorado cuando se utilizan muchas secuencias en una conexión‎.
  • ‎Nuevo evento ServerReady para medir el tiempo de inicio‎‎
  • Modo oscuro de la página de excepción del desarrollador‎

Puedes comenzar a utilizar esta preview instalando el SDK desde este link. Si estás utilizando el sistema operativo Windows se recomienda utilizar la versión de Visual Studio 2022 preview. En otros sistemas operativos no se encuentra disponible por el momento.

‎Compatibilidad con filtros de controlador de rutas en Minimal API

Se agregó el soporte para filtros en controladores en Minimal API. Los filtros se ejecutan antes de la lógica del controlador de ruta principal y se pueden usar para inspeccionar y modificar los parámetros del controlador o interceptar la ejecución del controlador.‎

Hay varias formas de registrar los filtros, por ejemplo, registrar un filtro mediante un‎ RouteHandlerFilterDelegate y AddFilter‎ método de extensión de la siguiente manera:‎

string HelloName(string name) => $"Hello, {name}!";

app.MapGet("/hello/{name}", HelloName)
    .AddFilter(async (routeHandlerInvocationContext, next) =>
    {
        var name = (string) routeHandlerInvocationContext.Parameters[0];
        if (name == "Bob")
        {
            return Results.Problem("No Bob's allowed");
        }
        return await next(routeHandlerInvocationContext);
    });

También es posible hacerlo por medio de una estrategia factory por medio de RouteHandlerContext y MethodInfo‎ asociado con el controlador y los metadatos registrados en el extremo.‎

app.MapGet("/hello/{name}", HelloName)
    .AddFilter((routeHandlerContext, next) =>
    {
        var parameters = routeHandlerContext.MethodInfo.GetParameters();
        var hasCorrectSignature = parameters.Length == 1 && parameters[0].ParameterType == typeof(string);
        return async (routeHandlerInvocationContext) =>
        {
            if (hasCorrectSignature)
            {
                var name = (string) routeHandlerInvocationContext.Parameters[0];
                if (name == "Bob")
                {
                    return Results.Problem("No Bob's allowed");
                }
            }
            return await next(routeHandlerInvocationContext);
        };
    })

Por último, los filtros se pueden implementar la interfaz IRouteHandlerFilter y resolverlo por DI o pasado como una instancia.‎

app.MapGet("/hello/{name}", HelloName)
    .AddFilter<MyFilter>();

Pruebas unitarias mejoradas para handlers 

IResult‎ los tipos de implementación ahora están disponibles públicamente en el espacio de nombres‎ Microsoft.AspNetCore.Http con el sufijo HttpResult (OkObjectHttpResult, ProblemHttpResult, etc.). ‎Con estos, ahora se pueden realizar pruebas unitarias más fácilmente en los controladores de ruta mínimos cuando usamos métodos con nombre en lugar de lambdas.‎

[Fact]
public async Task GetTodoReturnsTodoFromDatabase()
{
    var todo = new Todo { Id = 42, Name = "Improve Results testability!" };
    var mockDb = new MockTodoDb(new[] { todo });

    var result = (OkObjectHttpResult)await TodoEndpoints.GetTodo(mockDb, todo.Id);

    //Assert
    Assert.Equal(200, result.StatusCode);

    var foundTodo = Assert.IsAssignableFrom<Models.Todo>(result.Value);
    Assert.Equal(id, foundTodo.Id);
}

[Fact]
public void CreateTodoWithValidationProblems()
{
    //Arrange
    var newTodo = default(Todo);
    var mockDb = new MockTodoDb();

    //Act
    var result = TodoEndpoints.CreateTodo(mockDb, newTodo);

    //Assert        
    var problemResult = Assert.IsAssignableFrom<ProblemHttpResult>(result);
    Assert.NotNull(problemResult.ProblemDetails);
    Assert.Equal(400, problemResult.StatusCode);
}

‎Enlazar usando ‎TryParse‎ en MVC y API Controllers

ahora se puede enlazar los valores de los parámetros de acción del controlador mediante un‎ TryParse:‎

public static bool TryParse(string value, T out result);
public static bool TryParse(string value, IFormatProvider provider, T out result);

En el siguiente controlador, en el GETm se enlazan los datos de la cadena de consulta mediante un‎ TryParse ‎método en el tipo de parámetro‎:

public class TryParseController : ControllerBase
{
    // GET /tryparse?data=MyName
    [HttpGet]
    public ActionResult Get([FromQuery]CustomTryParseObject data) => Ok();

    public class CustomTryParseObject
    {
        public string? Name { get; set; }

        public static bool TryParse(string s, out CustomTryParseObject result)
        {
            if (s is null) 
            {
                result = default;
                return false;
            }

            result = new CustomTryParseObject { Name = s };
            return true;
        }
    }
}

Nuevas sobrecargas en Results.Stream()

Nuevas sobrecargas en ‎Results.Stream(…)‎ para adaptarse a escenarios en los que necesita acceso a la secuencia de respuesta HTTP subyacente sin almacenamiento en búfer. Estas sobrecargas también mejoran los casos en los que la API desea transmitir datos a la secuencia de respuesta HTTP, como desde Azure Blob Storage. 

app.MapGet("/process-image", async (HttpContext http) =>
{
    using var image = await Image.LoadAsync("puppy.jpeg");
    int width = image.Width / 2;
    int height = image.Height / 2;
    image.Mutate(x => x.Resize(width, height));
    http.Response.Headers.CacheControl = $"public,max-age={FromHours(24).TotalSeconds}";
    return Results.Stream(stream => image.SaveAsync(stream, PngFormat.Instance), "image/png");
});

‎Rendimiento HTTP/2 mejorado cuando se utilizan muchas secuencias en una conexión‎

Se realizaron cambios en el código de escritura de tramas HTTP/2 mejorando el rendimiento cuando hay varias secuencias que intentan escribir datos en una sola conexión HTTP/2. Ahora se envía el trabajo TLS al grupo de subprocesos y se libera más rápidamente un bloqueo de escritura que otras secuencias pueden adquirir para escribir sus datos. La reducción en los tiempos de espera, en algunos casos, mejora en el rendimiento donde hay contención para este bloqueo de escritura. Un punto de referencia gRPC con 70 flujos en una sola conexión (con TLS) mostró una mejora de ~ 15% en las solicitudes por segundo (RPS) con este cambio.‎

Nuevo evento para medir el tiempo de inicio: ServerReady

‎Si utiliza‎mos EventSource‎ para métricas/diagnósticos y deseamos medir el tiempo de inicio de su aplicación ASP.NET Core, ahora podemos utilizar el nuevo evento ServerReady que es parte de Microsoft.AspNetCore.Hosting ‎que representa el punto en el que el servidor está en funcionamiento

‎Modo oscuro de la página de excepción del desarrollador‎

‎La página de excepción para desarrolladores de ASP.NET Core ahora admite el modo oscuro:‎

Conclusiones

Tenemos cosas muy interesantes en esta preview para Asp.Net, próximamente tendremos muchas novedades de la mano de Blazor. No te pierdas los siguientes posts, veremos todo lo que viene en la próxima 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 *