0

.Net, ASP.NET y Entity Framework 7 Release Candidate 1 #2

Seguimos en la recta final para la nueva versión de .Net, en este caso la versión 7. Seguiremos viendo las novedades que tenemos disponibles para la versión Release Candidate 1.

Interoperabilidad de .NET JavaScript en WebAssembly

.NET 7 presenta un nuevo mecanismo de bajo nivel para usar .NET en aplicaciones basadas en JavaScript. Con esta nueva capacidad de interoperabilidad de JavaScript, puede invocar el código .NET desde JavaScript mediante el tiempo de ejecución de .NET WebAssembly y llamar a la funcionalidad de JavaScript desde .NET sin depender del modelo de componentes de la interfaz de usuario de Blazor.

La forma más fácil de ver la nueva funcionalidad de interoperabilidad de JavaScript en acción es usar las nuevas plantillas experimentales en la carga de trabajo experimental de wasm:

dotnet workload install wasm-experimental

Esta carga de trabajo contiene dos plantillas de proyecto: la aplicación WebAssembly Browser y la aplicación WebAssembly Console. Estas plantillas son experimentales, lo que significa que el flujo de trabajo del desarrollador para ellas aún no se ha resuelto por completo (por ejemplo, estas plantillas aún no se ejecutan en Visual Studio). Pero las API de .NET y JavaScript que se usan en estas plantillas son compatibles con .NET 7 y proporcionan una base para usar .NET en WebAssembly desde JavaScript.

Podemos crear una aplicación de navegador WebAssembly ejecutando el siguiente comando:

dotnet new wasmbrowser

Esta plantilla crea una aplicación web simple que demuestra el uso conjunto de .NET y JavaScript en un navegador. La aplicación de consola WebAssembly es similar, pero se ejecuta como una aplicación de consola Node.js en lugar de una aplicación web basada en navegador.

El módulo de JavaScript en main.js en el proyecto creado demuestra cómo ejecutar código .NET desde JavaScript. Las API relevantes se importan de dotnet.js. Estas API le permiten configurar módulos con nombre que se pueden importar a su código C#, así como llamar a métodos expuestos por su código .NET, incluido Program.Main:

import { dotnet } from './dotnet.js'

const is_browser = typeof window != "undefined";
if (!is_browser) throw new Error(`Expected to be running in a browser`);

// Setup the .NET WebAssembly runtime
const { setModuleImports, getAssemblyExports, getConfig, runMainAndExit } = await dotnet
    .withDiagnosticTracing(false)
    .withApplicationArgumentsFromQuery()
    .create();

// Set module imports that can be called from .NET
setModuleImports("main.js", {
    window: {
        location: {
            href: () => globalThis.window.location.href
        }
    }
});

const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);
const text = exports.MyClass.Greeting(); // Call into .NET from JavaScript
console.log(text);

document.getElementById("out").innerHTML = `${text}`;
await runMainAndExit(config.mainAssemblyName, ["dotnet", "is", "great!"]); // Run Program.Main

Para importar una función de JavaScript para que se pueda llamar desde C#, use el nuevo JSImportAttribute en una firma de método coincidente:

[JSImport("window.location.href", "main.js")]
internal static partial string GetHRef();

El primer parámetro de JSImportAttribute es el nombre de la función de JavaScript para importar y el segundo parámetro es el nombre del módulo, ambos configurados por la llamada setModuleImports en main.js.

En la firma del método importado, podemos usar tipos .NET para parámetros y valores devueltos, que se calcularán por nosotros. Usaremos JSMarshalAsAttribute<T> para controlar cómo se serializan los parámetros del método importado. Por ejemplo, podemos optar por ordenar un largo como JSType.Number o JSType.BitInt. Podemos pasar devoluciones de llamada de acción/función como parámetros, que se calcularán como funciones de JavaScript a las que se puede llamar. Podemos pasar tanto JavaScript como referencias de objetos administrados y se clasificarán como objetos proxy, lo que mantendrá el objeto vivo a través del límite hasta que el proxy se recopile como basura. También puede importar y exportar métodos asincrónicos con el resultado de la tarea, que se calculará según las promesas de JavaScript. La mayoría de los tipos serializados funcionan en ambas direcciones, como parámetros y como valores devueltos, tanto en métodos importados como exportados..

Para exportar un método .NET para que pueda llamarse desde JavaScript, utilizaremos JSExportAttribute:

[JSExport]
internal static string Greeting()
{
    var text = $"Hello, World! Greetings from {GetHRef()}";
    Console.WriteLine(text);
    return text;
}

Blazor proporciona su propio mecanismo de interoperabilidad de JavaScript basado en la interfaz IJSRuntime, que se admite uniformemente en todos los modelos de alojamiento de Blazor. Esta abstracción asíncrona común permite a los autores de bibliotecas crear bibliotecas de interoperabilidad de JavaScript que se pueden compartir en todo el ecosistema de Blazor y sigue siendo la forma recomendada de realizar la interoperabilidad de JavaScript en Blazor. Sin embargo, en las aplicaciones Blazor WebAssembly, también tenía la opción de realizar llamadas de interoperabilidad de JavaScript síncronas mediante IJSInProcessRuntime o incluso llamadas no ordenadas mediante IJSUnmarshalledRuntime

IJSUnmarshalledRuntime era complicado de usar y solo se admitía parcialmente. En .NET 7, IJSUnmarshalledRuntime ahora está obsoleto y debe reemplazarse con el mecanismo [JSImport]/[JSExport]. Blazor no expone directamente la instancia de tiempo de ejecución de dotnet que usa desde JavaScript, pero aún se puede acceder llamando a getDotnetRuntime(0). También puede importar módulos JavaScript desde su código C# llamando a JSHost.ImportAsync, lo que hace que las exportaciones del módulo sean visibles para [JSImport].

Mejoras en la cadena de certificados completa de Kestrel

HttpsConnectionAdapterOptions tiene una nueva propiedad ServerCertificateChain de tipo X509Certificate2Collection, que facilita la validación de cadenas de certificados al permitir que se especifique una cadena completa que incluya certificados intermedios. 

Cargas HTTP/2 más rápidas

Se ha aumentado el tamaño de ventana de conexión de carga HTTP/2 predeterminado de Kestrel de 128 KB a 1 MB, lo que mejora drásticamente las velocidades de carga HTTP/2 en conexiones de alta latencia utilizando la configuración predeterminada de Kestrel.

Probamos el impacto de aumentar este límite cargando un archivo de 108 MB utilizando una sola transmisión en localhost después de introducir solo 10 ms de latencia artificial y observamos una mejora de aproximadamente 6 veces en la velocidad de carga.

La siguiente captura de pantalla compara el tiempo necesario para una carga de 108 MB en la pestaña de red de herramientas de desarrollo de Edge:

Before: 26.9 seconds

After: 4.3 seconds

Mejoras de HTTP/3

.NET 7 RC1 continúa mejorando la compatibilidad de Kestrel con HTTP/3. Las dos áreas principales de mejora son la paridad de funciones con HTTP/1.1 y HTTP/2 y el rendimiento.

La característica más importante de esta versión es el soporte completo para ListenOptions.UseHttps con HTTP/3. Kestrel ofrece opciones avanzadas para configurar certificados de conexión, como conectarse a la Indicación de nombre de servidor (SNI).

El siguiente ejemplo muestra cómo usar una devolución de llamada de SNI para resolver las opciones de TLS:

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenAnyIP(8080, listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
        listenOptions.UseHttps(new TlsHandshakeCallbackOptions
        {
            OnConnection = context =>
            {
                var options = new SslServerAuthenticationOptions
                {
                    ServerCertificate = ResolveCertForHost(context.ClientHelloInfo.ServerName)
                };
                return new ValueTask<SslServerAuthenticationOptions>(options);
            },
        });
    });
});

También el equipo ha trabajado mucho para reducir las asignaciones de HTTP/3 en .NET 7 RC1. Podemos ver algunas de esas mejoras desde estos links:

Soporte experimental de Kestrel para WebTransport sobre HTTP/3

Nueva compatibilidad experimental integrada para WebTransport sobre HTTP/3 en Kestrel. WebTransport es un nuevo borrador de especificación para un protocolo de transporte similar a WebSockets que permite el uso de múltiples flujos por conexión. Esto puede ser útil para dividir los canales de comunicación y así evitar el bloqueo de cabecera de línea. 

Por ejemplo, consideremos un juego en línea basado en la web donde el estado del juego se transmite en una transmisión bidireccional, las voces de los jugadores para la función de chat de voz del juego en otra transmisión bidireccional y los controles del jugador se transmiten en una transmisión unidireccional. Con WebSockets, todo esto debería colocarse en conexiones separadas o agruparse en una sola transmisión. Con WebTransport, puede mantener todo el tráfico en una conexión pero separarlos en sus propios flujos y, si un flujo se bloqueara, los demás continuarían sin interrupciones..

Compatibilidad experimental con OpenAPI para la transcodificación gRPC JSON

La transcodificación gRPC JSON es una característica nueva en .NET 7 para convertir las API gRPC en API RESTful.

.NET 7 RC1 agrega compatibilidad experimental para generar OpenAPI a partir de API RESTful transcodificadas de gRPC. OpenAPI con transcodificación gRPC JSON es una función muy solicitada y nos complace ofrecer una forma de combinar estas excelentes tecnologías. El paquete NuGet es experimental en .NET 7 para darnos tiempo de explorar la mejor manera de integrar estas características.

Para habilitar OpenAPI con gRPC JSON transcodificación:

  1. Agregue una referencia de paquete a Microsoft.AspNetCore.Grpc.Swagger. La versión debe ser 0.3.0-xxx o superior.
  2. Configure Swashbuckle en el inicio. El método AddGrpcSwagger configura Swashbuckle para incluir extremos de gRPC.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc().AddJsonTranscoding();
builder.Services.AddGrpcSwagger();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1",
        new OpenApiInfo { Title = "gRPC transcoding", Version = "v1" });
});

var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
app.MapGrpcService<GreeterService>();

app.Run();

Para confirmar que Swashbuckle está generando Swagger para los servicios RESTful gRPC, inicie la aplicación y vaya a la página de la interfaz de usuario de Swagger:

Mejoras en el middleware de limitación de velocidad

Se han agregado muchas funciones al middleware de limitación de velocidad en .NET 7 RC1 que deberían hacerlo más funcional y más fácil de usar.

El equipo agrego atributos que se pueden usar para habilitar o deshabilitar la limitación de velocidad en un punto final determinado. Por ejemplo, así es como podría aplicar una política llamada MyControllerPolicy a un controlador:

public class MyController : Controller
{
    [EnableRateLimitingAttribute("MyControllerPolicy")]
    public IActionResult Index()
    {
        return View();
    }
}

También puede deshabilitar la limitación de velocidad por completo en un punto final determinado o en un grupo de puntos finales. Supongamos que ha habilitado la limitación de velocidad en un grupo de puntos finales:

app.MapGroup("/public/todos").RequireRateLimiting("MyGroupPolicy");

Luego, puede deshabilitar la limitación de velocidad en un punto final específico dentro de ese grupo de la siguiente manera:

app.MapGroup("/public/todos/donothing").DisableRateLimiting();

Ahora también puede aplicar políticas directamente a los puntos finales. A diferencia de las políticas con nombre, las políticas agregadas de esta manera no necesitan configurarse en RateLimiterOptions. Supongamos que ha definido un tipo de política:

public class MyRateLimiterPolicy : IRateLimiterPolicy<string>
{
...
}

Puede agregar una instancia directamente a un punto final de la siguiente manera:

app.MapGet("/", () => "Hello World!").RequireRateLimiting(new MyRateLimiterPolicy());

Finalmente, actualizamos los métodos convenientes de RateLimiterOptions para tomar una Action<Options> en lugar de una instancia de Options y también se agregó un método de extensión IServiceCollection para usar la limitación de velocidad. Entonces, para habilitar todas las políticas de limitación de velocidad anteriores en su aplicación, puede hacer lo siguiente:

builder.Services.AddRateLimiter(options =>
{
    options.AddTokenBucketLimiter("MyControllerPolicy", options =>
    {
        options.TokenLimit = 1;
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = 1;
        options.ReplenishmentPeriod = TimeSpan.FromSeconds(10);
        options.TokensPerPeriod = 1;
    })
    .AddPolicy<string>("MyGroupPolicy", new MyRateLimiterPolicy());
});

Esto aplicará un TokenBucketLimiter a su controlador, su MyRateLimiterPolicy personalizado a los puntos finales que coincidan con /public/todos (con la excepción de /public/todos/donothing) y su MyRateLimiterPolicy personalizado a /.

mejoras en los certificados de desarrollo de macOS

Se han realizado algunas mejoras significativas en la calidad de vida de la experiencia de usar certificados de desarrollo HTTPS para usuarios de macOS en esta versión, reduciendo en gran medida la cantidad de solicitudes de autenticación que se muestran al crear, confiar, leer y eliminar el desarrollo HTTPS de ASP.NET Core. certificados. Este había sido un punto problemático para los desarrolladores de ASP.NET Core en macOS cuando intentaban usar certificados de desarrollo en sus flujos de trabajo.

Con esta versión, los certificados de desarrollo generados por la herramienta dotnet dev-certs en macOS tienen un alcance de confianza más limitado, la configuración ahora se agrega en la configuración de confianza por usuario en lugar de en todo el sistema, y ​​Kestrel podrá vincularse a estos nuevos certificados sin necesidad de acceder al llavero del sistema. Como parte de este trabajo, también se realizaron algunas mejoras en la calidad de vida, como la reelaboración de algunos mensajes orientados al usuario para mayor claridad y precisión.

Estos cambios se combinan para dar como resultado una experiencia mucho más fluida y muchas menos solicitudes de contraseña cuando se usa HTTPS durante el desarrollo en macOS.

Entity Framework 7 Release Candidate 1

En esta salida se han arreglado algunos puntos reportados por la comunidad,  si quieres ver todas las mejoras te invito a ver mis anteriores post sobre todas las novedades.

Conclusiones

Esta primera Release candidate ha traído más novedades en ASP.NET que en las otras partes. Como comentamos antes, estamos en la recta final esperando la segunda release candidate, como también, la .Net conf en noviembre.

Fernando Sonego

Deja una respuesta

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