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 ;)

17 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!
martes, 5 de junio de 2018
ASP.NET CoreComo seguro sabréis, tras varias previews y release candidates, hace pocos días se lanzaron las actualizaciones de varios productos que ya llevábamos tiempo esperando:
Centrándonos en ASP.NET Core, la versión 2.1 incluye numerosas mejoras sobre su predecesora. Muchos componentes internos han sido reescritos y se han añadido características que, sin duda, continúan haciendo de ASP.NET Core un framework cada vez más completo y eficiente.

Pero eso sí, no rompe nada y todo lo que sabemos de ASP.NET Core 2.0 sigue siendo válido (de ahí que sea simplemente una revisión 2.x: no hay breaking changes).

En este post vamos a ver por encima las novedades que creo más destacadas de esta entrega.

Más rendimiento

Este ha sido uno de los grandes focos en ASP.NET 2.1, y vamos a notarlo en muchos aspectos.

Primero, la compilación de proyectos será bastante más rápida, algo que podrá apreciarse especialmente en proyectos grandes.

Pero más importante son las mejoras en tiempo de ejecución, muchas de ellas apoyadas en las novedades a este respecto introducidas en .NET Core 2.1. De hecho, ASP.NET Core está apareciendo ya en las posiciones más altas de los rankings de rendimiento.

En versiones anteriores de ASP.NET Core, libuv, una biblioteca de comunicaciones asíncronas, era el transporte utilizado por defecto por Kestrel para comunicarse con el exterior. En ASP.NET Core 2.1, este componente ha sido reemplazado por una implementación de sockets .NET; al evitar dependencias nativas, hace que el despliegue en nuevas plataformas sólo dependa de la disponibilidad de .NET Core.

Además, el equipo de ASP.NET Core ha puesto toda la carne en el asador con esta nueva implementación de sockets. Aprovechando nuevas capacidades del framework como Span<T> y afinando al máximo han conseguido un componente que es mucho más rápido que el que disfrutábamos hasta la versión 2.0.
Lamentablemente, a última hora se ha caído de esta revisión el esperado nuevo modo de funcionamiento in-process del módulo ASP.NET Core para IIS, que prometía un aumento del rendimiento de entre 4x y 6x eliminado la necesidad de conexiones en localhost entre IIS y Kestrel.
En definitiva, como podéis comprobar, mejorar el rendimiento ha sido un objetivo importante para esta revisión. Por haceros una idea, según benchmarks realizados por TechEmpower hace bien poco, ASP.NET Core es capaz de resolver más de siete millones de peticiones por segundo respondiendo texto plano:

Ranking de becnhmarks de Techempower

Hey, pero no penséis que migrando vuestra aplicación a ASP.NET Core 2.1 seréis capaces de responder peticiones a ese ritmo, ni mucho menos. Estos benchmarks se realizan en entornos muy controlados y afinando al máximo el código para conseguir este rendimiento. Por ejemplo, en este caso, la aplicación testada no usa MVC, ni siquiera routing o middlewares, lo cual hace que estas pruebas concretas sólo muestren el tope máximo al que podría llegarse en un escenario ideal (e irreal), y su posición respecto al resto de competidores en escenarios similares.
Podéis ver el código fuente de la aplicación que consigue este rendimiento en el repositorio de TechEmpower en GitHub.

Mejoras en MVC/Web APIs

El nuevo atributo [ApiController] permite identificar los controladores cuyas acciones son Web APIs para aplicarles de forma automática convenciones bastante razonables, como asumir que los objetos complejos serán bindeados desde el cuerpo de la petición, obligar a que se use rutado por atributos, o retornar un HTTP 400 cuando no se cumplan las reglas de validación establecidas.

También en esta revisión volvemos a encontrarnos con un viejo conocido: ActionResult… o más exactamente en este caso, ActionResult<T>. Una acción que retorne este tipo indica que ésta retornará o bien un IActionResult o bien un objeto de tipo T, lo cual facilita bastante su autodocumentación, sobre todo vistas a la alineación con OpenAPI, y hace su implementación más fácil de escribir y leer:
// Antes (<=2.0)
[Produces(typeof(Invoice))]
public IActionResult Get(int id)
{
    var invoice = _invoiceServices.GetInvoice(id);
    if (invoice == null)  
        return NotFound();

    return Ok(invoice);
}

// Ahora (>=2.1)
public ActionResult<Invoice> Get(int id)
{
    var invoice = _invoiceServices.GetInvoice(id);
    if (invoice == null)
        return NotFound();

    return invoice;
}
Además de esto, se ha añadido soporte para el estándar Problem Details, que especifica una forma estructurada de retornar detalles de error en APIs HTTP. Para ello, se han introducido clases como ValidationProblemDetails y el método ValidationProblem() para retornar un error 400 con esta estructura de datos:
if (!ModelState.IsValid)
{
    return ValidationProblem(ModelState);
}

Mejoras en Razor

Las vistas o páginas Razor pueden ser ahora compiladas y distribuidas en bibliotecas, lo que permitirá construir interfaces de usuario reutilizables. Cuando una aplicación MVC o Web Pages incorpora estas bibliotecas, las vistas que incluya serán detectadas automáticamente y utilizadas de forma normal, como si se encontraran en la carpeta /Views o /Pages. Sin embargo, pueden ser sobrescritas por las aplicaciones simplemente creando vistas con el mismo nombre en las ubicaciones habituales.

Esto, por ejemplo, se pone de manifiesto en la nueva forma de introducir en las aplicaciones creadas usando las plantillas existentes el interfaz de usuario relativo a la gestión de identidad (autenticación, perfil, etc.) usando Identity Framework. Todo el interfaz se distribuye en forma de biblioteca de clases Razor y puede ser incluido en nuestros proyectos usando los scaffolders disponibles a nivel de línea de comando o desde Visual Studio.

Por otra parte, las vistas parciales pueden incluirse ahora desde otra vista utilizando el tag helper <Partial>, que elimina problemas y dudas relativas al uso de helpers como Html.Partial(), Html.RenderPartial() y sus correspondientes versiones asíncronas.

De hecho, los problemas causados por el uso de las versiones síncronas son tan graves que, a partir de esta versión, las llamadas a Html.Partial() serán marcadas como warning, sugiriéndose que sean sustituidas por <partial> o await Html.PartialAsync():

Warning al usar Partial()

También Razor Pages ha sufrido algunas pequeñas mejoras, como el soporte para áreas, el uso de /Pages/Shared como fallback para la búsqueda de páginas, o la introducción de IPageFilter e IAsyncPageFilter para la implementación de funcionalidades transversales, tipo filtro de acción, en este tipo de componentes.

El nuevo paquete Microsoft.AspNetCore.App

Hasta ahora, el metapaquete referenciado habitualmente en los proyectos era Microsoft.AspNetCore.All, pero ahora se promoverá el uso de Microsoft.AspNetCore.App en los nuevos proyectos.

En este nuevo metapaquete han eliminado dependencias hacia proyectos de terceros como los conectores con Sqlite, Redis o algunos servicios de Azure. Por tanto, a partir de la versión 2.1, si queremos usar estos componentes tendremos que referenciar sus paquetes de forma directa.

Por cierto, el metapaquete Microsoft.AspNetCore.All seguirá existiendo durante todas las versiones 2.x, por lo que no es necesario migrarlo de momento. Pero en cualquier caso, si hubiera que hacerlo, tampoco sería demasiado complicado; podéis leer más en este issue de GitHub.

Testing end to end

Las versiones anteriores de ASP.NET Core disponían de una infraestructura muy básica para preparar tests de extremo a extremo, aunque era bastante complicado echarlo a andar con MVC.

ASP.NET Core 2.1 incluye el nuevo paquete Microsoft.AspNetCore.Mvc.Testing que añade infraestructura para la creación de pruebas end to end en memoria. Recordad que este tipo de pruebas, a diferencia de las unitarias, permiten verificar el funcionamiento del stack completo, pues consiste básicamente en simular peticiones y analizar las respuestas.
public class TestingMvcFunctionalTests : IClassFixture<WebApplicationTestFixture<Startup>>
{
    public HttpClient Client { get; }

    public TestingMvcFunctionalTests(WebApplicationTestFixture<Startup> fixture)
    {
        Client = fixture.Client;
    }


    [Fact]
    public async Task GetHomePage()
    {
        // Arrange & Act
        var response = await Client.GetAsync("/");

        // Assert
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    }
}
Fijaos que no estamos hablando de hacer peticiones, sino de simularlas en memoria, por lo que todo será bastante más rápido que si tuviéramos que lanzar un servidor y realizar peticiones reales a través de red (aunque sea el loopback).

Seguridad y cumplimiento de GDPR

La seguridad es un área en continuo movimiento y, además, la llegada de GDPR ha sido uno de los grandes acontecimientos de este año. Obviamente la nueva versión de un framework moderno como ASP.NET Core no podía ignorar este hecho.
  • Los proyectos ASP.NET Core 2.1 utilizarán por defecto HTTPS (se lanzará en localhost:5001), y tendremos disponible un middleware específico para forzar la redirección HTTP->HTTPS:
    app.UseHttpsRedirection();
     
  • Asimismo, mediante otro middleware podremos utilizar HSTS (HTTP Strict Transport Security) para informar a los navegadores de nuestro uso de protocolos seguros.
     
  • Las plantillas de proyectos web incluyen un banner de aceptación de cookies que impedirá la emisión de galletitas no esenciales si no es aceptado.
     
  • La plantilla de proyecto que utiliza Identity Framework incluye de serie opciones en el perfil para descargar los datos personales y para eliminar el usuario.

¡SignalR Core!

Pues sí, amigos, por fin tenemos disponible la versión "core" del framework de servicios en tiempo real lista para utilizar en producción.

Aunque siguen existiendo hubs y otros conceptos que nos resultarán familiares, se trata de una reescritura desde cero, que no mantiene compatibilidad ningún tipo con SignalR 2.x para .NET framework. Aparte de aprovechar las ventajas de ASP.NET Core, En esta versión se han eliminado las dependencias con jQuery, se usan protocolos más eficientes, un modelo de escalado simplificado y muchas novedades más.

Podéis leer más sobre SignalR Core en la documentación oficial.

Mejoras en CLI

Aunque estrictamente hablando se trata de una novedad de .NET Core, vamos a comentar aquí también las mejoras en el interfaz de línea de comandos (CLI) porque seguro que afectará a la forma en que desarrollamos aplicaciones web.

En primer lugar, ahora vienen integrados de serie comandos que antes eran externos y debían ser instalados como paquetes NuGet en el proyecto:
  • dotnet watch, para habilitar la compilación automática ante cambios de código.
  • dotnet ef para realizar operaciones relacionadas con Entity Framework.
  • dotnet user-secrets para gestionar user secrets.
  • dotnet dev-certs para manejar certificados en la máquina local.
  • dotnet sql-cache para configurar servidores de caché distribuida.
Por otra parte, ¿habéis mirando alguna vez con envidia esos comandos basados en NodeJS que se instalan a través de npm? ¡Pues demos la bienvenida a las .NET Core Global tools!

Gracias a esta nueva característica podremos crear comandos con .NET Core y distribuirlos a través de NuGet mediante el comando dotnet tool install -g. Tras ello, lo tendremos disponibles como órdenes de línea de comandos, por ejemplo:
C:\>dotnet tool install -g dotnetsay
Puede invocar la herramienta con el comando siguiente: dotnetsay
La herramienta "dotnetsay" (versión '2.1.3') se instaló correctamente.

C:\>dotnetsay

        Welcome to using a .NET Core global tool!
        [...]

C:\>_
Sin duda, esto nos llevará a un interesante ecosistema de herramientas para ASP.NET Core basadas en el CLI.

Otras mejoras

Aunque no todas ellas están relacionadas directamente con ASP.NET Core, creo que es interesante al menos citar las siguientes novedades:
  • HttpClientFactory es un nuevo mecanismo para facilitar la creación y uso correcto de objetos HttpClient. A diferencia de las versiones anteriores, hace uso del inyector de dependencias para registrar y obtener clientes HTTP, implementa un nuevo concepto llamado outgoing middleware y gestiona el ciclo de vida de forma automática.
     
  • Mejoras en la forma de trabajar con objetos Option, como la posibilidad de configurarlos a través de servicios registrados en el sistema, o de implementar clases que configuren varios objetos de este tipo al mismo tiempo.
     
  • El UI de Identity Framework se puede incluir en los proyectos como biblioteca Razor UI, y modificar únicamente lo que necesitemos. Relacionado con esto, también se ha incluido un nuevo scaffolder en Visual Studio que permite añadir desde el IDE dicha biblioteca y los componentes a sobrescribir.
     
  • Se ha introducido una fórmula para especificar el nivel de compatibilidad de nuestro código con versiones de ASP.NET Core MVC. Mediante el método SetCompatibilityVersion() podemos indicar expresamente si queremos que el framework actúe conforme a una versión específica para proteger nuestra aplicación de posibles cambios futuros:
    public void ConfigureServices(IServiceCollection services)
    {
       services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }
    Por defecto se asume que el nivel de compatibilidad de las aplicaciones que no lo indiquen es CompatibilityVersion.Version_2_0.
     
  • Se han actualizado las plantillas de proyecto web SPA para Angular, React y React con Redux.

Y esto es todo, o casi…

… o al menos lo que más me ha llamado la atención hasta el momento. Espero no haberme dejado muchas novedades interesantes por detrás, pero, si detectáis alguna que os parezca interesante comentar, no dudéis en decirlo ;)

Ah, por último, en la documentación oficial tenéis información sobre el proceso de migración desde ASP.NET Core 2.0, aunque que es bastante sencillito.

Publicado en Variable not found.

Aún no hay comentarios, ¡sé el primero!