Migración de ASP.NET Core 2.2 a 3.0

Por Scott Addie y Rick Anderson

En este artículo se explica cómo actualizar un proyecto de ASP.NET Core 2.2 existente a ASP.NET Core 3.0. Puede resultar útil crear un nuevo proyecto de ASP.NET Core 3.0 para:

  • Comparar con el código de ASP.NET Core 2.2.
  • Copiar los cambios pertinentes en el proyecto de ASP.NET Core 3.0.

Requisitos previos

Actualización de la versión del SDK de .NET Core en global.json

Si la solución se basa en un archivo global.json para que el destino sea una versión específica del SDK de .NET Core, actualice su propiedad version a la versión 3.0 instalada en la máquina:

{
  "sdk": {
    "version": "3.0.100"
  }
}

Actualización del archivo del proyecto

Actualización de la plataforma de destino

ASP.NET Core 3.0 y las versiones posteriores solo se ejecutan en .NET Core. Establezca el Moniker de la plataforma de destino (TFM) en netcoreapp3.0:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

</Project>

Eliminación de las referencias a paquetes obsoletos

No se produce un gran número de paquetes NuGet para ASP.NET Core 3.0. Estas referencias de paquete deben quitarse del archivo del proyecto. Considere el siguiente archivo del proyecto para una aplicación web de ASP.NET Core 2.2:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App"/>
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
  </ItemGroup>

</Project>

El archivo del proyecto actualizado para ASP.NET Core 3.0:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

</Project>

El archivo del proyecto de ASP.NET Core 3.0 actualizado:

  • En <PropertyGroup>:

    • Actualiza el TFM a netcoreapp3.0
    • Quita el elemento <AspNetCoreHostingModel>. Para obtener más información, consulte Modelo de hospedaje en proceso en este documento.
  • En <ItemGroup>:

    • Se ha eliminado Microsoft.AspNetCore.App. Para obtener más información, consulte Referencia de marco en este documento.
    • Microsoft.AspNetCore.Razor.Design se quita y en la siguiente lista de paquetes ya no se genera.

Para ver la lista completa de paquetes que ya no se generan, seleccione la siguiente lista de expansión:

Haga clic para expandir la lista de paquetes que ya no se generan
  • Microsoft.AspNetCore
  • Microsoft.AspNetCore.All
  • Microsoft.AspNetCore.App
  • Microsoft.AspNetCore.Antiforgery
  • Microsoft.AspNetCore.Authentication
  • Microsoft.AspNetCore.Authentication.Abstractions
  • Microsoft.AspNetCore.Authentication.Cookies
  • Microsoft.AspNetCore.Authentication.Core
  • Microsoft.AspNetCore.Authentication.OAuth
  • Microsoft.AspNetCore.Authorization.Policy
  • Microsoft.AspNetCore.CookiePolicy
  • Microsoft.AspNetCore.Cors
  • Microsoft.AspNetCore.Diagnostics
  • Microsoft.AspNetCore.Diagnostics.HealthChecks
  • Microsoft.AspNetCore.HostFiltering
  • Microsoft.AspNetCore.Hosting
  • Microsoft.AspNetCore.Hosting.Abstractions
  • Microsoft.AspNetCore.Hosting.Server.Abstractions
  • Microsoft.AspNetCore.Http
  • Microsoft.AspNetCore.Http.Abstractions
  • Microsoft.AspNetCore.Http.Connections
  • Microsoft.AspNetCore.Http.Extensions
  • Microsoft.AspNetCore.HttpOverrides
  • Microsoft.AspNetCore.HttpsPolicy
  • Microsoft.AspNetCore.Identity
  • Microsoft.AspNetCore.Localization
  • Microsoft.AspNetCore.Localization.Routing
  • Microsoft.AspNetCore.Mvc
  • Microsoft.AspNetCore.Mvc.Abstractions
  • Microsoft.AspNetCore.Mvc.Analyzers
  • Microsoft.AspNetCore.Mvc.ApiExplorer
  • Microsoft.AspNetCore.Mvc.Api.Analyzers
  • Microsoft.AspNetCore.Mvc.Core
  • Microsoft.AspNetCore.Mvc.Cors
  • Microsoft.AspNetCore.Mvc.DataAnnotations
  • Microsoft.AspNetCore.Mvc.Formatters.Json
  • Microsoft.AspNetCore.Mvc.Formatters.Xml
  • Microsoft.AspNetCore.Mvc.Localization
  • Microsoft.AspNetCore.Mvc.Razor
  • Microsoft.AspNetCore.Mvc.Razor.ViewCompilation
  • Microsoft.AspNetCore.Mvc.RazorPages
  • Microsoft.AspNetCore.Mvc.TagHelpers
  • Microsoft.AspNetCore.Mvc.ViewFeatures
  • Microsoft.AspNetCore.Razor
  • Microsoft.AspNetCore.Razor.Runtime
  • Microsoft.AspNetCore.Razor.Design
  • Microsoft.AspNetCore.ResponseCaching
  • Microsoft.AspNetCore.ResponseCaching.Abstractions
  • Microsoft.AspNetCore.ResponseCompression
  • Microsoft.AspNetCore.Rewrite
  • Microsoft.AspNetCore.Routing
  • Microsoft.AspNetCore.Routing.Abstractions
  • Microsoft.AspNetCore.Server.HttpSys
  • Microsoft.AspNetCore.Server.IIS
  • Microsoft.AspNetCore.Server.IISIntegration
  • Microsoft.AspNetCore.Server.Kestrel
  • Microsoft.AspNetCore.Server.Kestrel.Core
  • Microsoft.AspNetCore.Server.Kestrel.Https
  • Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
  • Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
  • Microsoft.AspNetCore.Session
  • Microsoft.AspNetCore.SignalR
  • Microsoft.AspNetCore.SignalR.Core
  • Microsoft.AspNetCore.StaticFiles
  • Microsoft.AspNetCore.WebSockets
  • Microsoft.AspNetCore.WebUtilities
  • Microsoft.Net.Http.Headers

Revisar cambios importantes

Revisar cambios importantes

Referencia de marco

Las características de ASP.NET Core que estaban disponibles a través de uno de los paquetes enumerados anteriormente están disponibles como parte del marco compartido Microsoft.AspNetCore.App. El marco compartido es el conjunto de ensamblados (archivos .dll) que se instalan en la máquina e incluye un componente de entorno de ejecución y un paquete de destino. Para más información, consulte este artículo sobre el marco de trabajo compartido.

  • Los proyectos que tienen como destino el SDK de Microsoft.NET.Sdk.Web hacen referencia implícitamente al marco Microsoft.AspNetCore.App.

    No se requieren referencias adicionales para estos proyectos:

    <Project Sdk="Microsoft.NET.Sdk.Web">
      <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
      </PropertyGroup>
        ...
    </Project>
    
  • Los proyectos que tienen como destino el SDK Microsoft.NET.Sdk o Microsoft.NET.Sdk.Razor deben agregar un elemento explícito FrameworkReference a Microsoft.AspNetCore.App:

    <Project Sdk="Microsoft.NET.Sdk.Razor">
      <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
      </ItemGroup>
        ...
    </Project>
    

Compilaciones dependientes del marco mediante Docker

Las compilaciones dependientes del marco de las aplicaciones de consola que usan un paquete que depende del marco compartido de ASP.NET Core pueden dar el siguiente error de runtime:

It was not possible to find any compatible framework version
The specified framework 'Microsoft.AspNetCore.App', version '3.0.0' was not found.
  - No frameworks were found.

Microsoft.AspNetCore.App es el marco compartido que contiene el runtime de ASP.NET Core y solo está presente en la imagen de Docker dotnet/core/aspnet. El SDK 3.0 reduce el tamaño de las compilaciones dependientes del marco mediante ASP.NET Core sin incluir copias duplicadas de bibliotecas que están disponibles en el marco compartido. Se trata de un ahorro potencial de hasta 18 MB, pero requiere que el runtime de ASP.NET Core esté presente o instalado para ejecutar la aplicación.

Para determinar si la aplicación tiene una dependencia (directa o indirecta) en el marco compartido de ASP.NET Core, examine el archivo runtimeconfig.json generado durante una compilación o publicación de la aplicación. El siguiente archivo JSON muestra una dependencia en el marco compartido de ASP.NET Core:

{
  "runtimeOptions": {
    "tfm": "netcoreapp3.0",
    "framework": {
      "name": "Microsoft.AspNetCore.App",
      "version": "3.0.0"
    },
    "configProperties": {
      "System.GC.Server": true
    }
  }
}

Si la aplicación usa Docker, use una imagen base que incluya ASP.NET Core 3.0. Por ejemplo: docker pull mcr.microsoft.com/dotnet/core/aspnet:3.0.

Agregar referencias de paquete para ensamblados eliminados

ASP.NET Core 3.0 quita algunos ensamblados que anteriormente formaban parte de la referencia del paquete Microsoft.AspNetCore.App. Para visualizar qué ensamblados se quitaron, compare las dos carpetas del marco compartido. Por ejemplo, una comparación de las versiones 2.2.7 y 3.0.0:

comparación de los ensamblados del marco compartido

Para seguir usando las características proporcionadas por los ensamblados quitados, haga referencia a las versiones 3.0 de los paquetes correspondientes:

Cambios de inicio

En la imagen siguiente se muestran las líneas eliminadas y modificadas en una aplicación web de Páginas Razor de ASP.NET Core 2.2:

las líneas eliminadas y modificadas en la aplicación web Razor ASP.NET Core 2.2

En la imagen anterior, el código eliminado se muestra en rojo. El código eliminado no muestra el código de opciones cookie, que se eliminó antes de comparar los archivos.

En la imagen siguiente se muestran las líneas agregadas y modificadas en una aplicación web de Páginas Razor de ASP.NET Core 3.0:

las líneas agregadas y modificadas en la aplicación web Razor ASP.NET Core 3.0

En la imagen anterior, el código agregado se muestra en verde. Para obtener información sobre los siguientes cambios:

Compatibilidad con analizadores

Proyectos que tienen como destino analizadores Microsoft.NET.Sdk.Web de referencia implícitamente enviados anteriormente como parte del paquete Microsoft.AspNetCore.Mvc.Analyzers. No se requieren referencias adicionales para habilitarlas.

Si la aplicación usa analizadores de API enviados anteriormente mediante el paquete Microsoft.AspNetCore.Mvc.Api.Analyzers, edita el archivo del proyecto para hacer referencia a los analizadores enviados como parte del SDK web de .NET Core:

<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
        <IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
    </PropertyGroup>

    ...
</Project>

Biblioteca de clases Razor

Los proyectos de la biblioteca de clases Razor que proporcionan componentes de interfaz de usuario para MVC deben establecer la propiedad AddRazorSupportForMvc en el archivo del proyecto:

<PropertyGroup>
  <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>

Modelo de hospedaje en proceso

Los proyectos tienen como valor predeterminado el modelo de hospedaje dentro del proceso en ASP.NET Core 3.0 o versiones posteriores. De manera opcional, puedes quitar la propiedad <AspNetCoreHostingModel> en el archivo del proyecto si su valor es InProcess.

Kestrel

Configuración

Migra la configuración Kestrel al generador de hosts web proporcionado por ConfigureWebHostDefaults (Program.cs):

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(serverOptions =>
            {
                // Set properties and call methods on options
            })
            .UseStartup<Startup>();
        });

Si la aplicación crea el host manualmente con ConfigureWebHost en lugar de ConfigureWebHostDefaults, llame a UseKestrel en el generador de hosts web:

public static void Main(string[] args)
{
    var host = new HostBuilder()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .ConfigureWebHost(webBuilder =>
        {
            webBuilder.UseKestrel(serverOptions =>
            {
                // Set properties and call methods on options
            })
            .UseIISIntegration()
            .UseStartup<Startup>();
        })
        .Build();

    host.Run();
}

El middleware de conexión reemplaza a los adaptadores de conexión

Los adaptadores de conexión (Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal.IConnectionAdapter) se han quitado de Kestrel. Reemplaza los adaptadores de conexión por middleware de conexión. El middleware de conexión es similar al middleware HTTP en la canalización de ASP.NET Core, pero para conexiones de nivel inferior. Registro de conexiones y HTTPS:

  • Se han movido de adaptadores de conexión al middleware de conexión.
  • Estos métodos de extensión funcionan como en versiones anteriores de ASP.NET Core.

Para obtener más información, consulta el ejemplo TlsFilterConnectionHandler en la sección ListenOptions.Protocols del Kestrel artículo.

Las abstracciones de transporte se han quitado y se han hecho públicas

La capa de transporte de Kestrel se ha expuesto como una interfaz pública en Connections.Abstractions. Como parte de estas actualizaciones:

  • Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions y los tipos asociados se han quitado.
  • NoDelay se movió de ListenOptions a las opciones de transporte.
  • Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal.SchedulingMode se quitó de KestrelServerOptions.

Para obtener más información, consulta los siguientes recursos de GitHub:

Encabezados de solicitud de finalizador Kestrel

En el caso de las aplicaciones destinadas a versiones anteriores de ASP.NET Core:

  • Kestrel agrega encabezados de finalizador fragmentados HTTP/1.1 a la colección de encabezados de solicitud.
  • Los finalizadores están disponibles después de que el cuerpo de la solicitud se lea hasta el final.

Esto provoca algunas preocupaciones sobre la ambigüedad entre los encabezados y los finalizadores, por lo que los finalizadores se han movido a una nueva colección (RequestTrailerExtensions) en 3.0.

Los finalizadores de solicitudes HTTP/2 son:

  • No está disponible en ASP.NET Core 2.2.
  • Disponible en 3.0 como RequestTrailerExtensions.

Hay métodos nuevos de extensión de solicitud para tener acceso a estos finalizadores. Al igual que con HTTP/1.1, los finalizadores están disponibles después de leer el cuerpo de la solicitud hasta el final.

Para la versión 3.0, están disponibles los siguientes métodos RequestTrailerExtensions:

  • GetDeclaredTrailers: obtiene el encabezado Trailer de solicitud que muestra los finalizadores que se esperan después del cuerpo.
  • SupportsTrailers: indica si la solicitud admite la recepción de encabezados de finalizador.
  • CheckTrailersAvailable: comprueba si la solicitud admite finalizadores y si están disponibles para su lectura. Esta comprobación no supone que hay finalizadores que se van a leer. Es posible que no haya finalizadores para leer incluso si este método devuelve true.
  • GetTrailer: obtiene el encabezado de finalización solicitado de la respuesta. Compruebe SupportsTrailers antes de llamar a GetTrailer, o se puede producir NotSupportedException si la solicitud no admite encabezados finales.

Para obtener más información, consulte Colocar los finalizadores de solicitud en una colección por separado (dotnet/AspNetCore #10410).

AllowSynchronousIO deshabilitado

AllowSynchronousIO habilita o deshabilita las API de E/S sincrónicas, como HttpRequest.Body.Read, HttpResponse.Body.Write y Stream.Flush. Estas API son una fuente común de ausencia de subprocesos que provocan bloqueos en la aplicación. En la versión 3.0, AllowSynchronousIO se ha deshabilitado de manera predeterminada. Para obtener más información, consulte la sección sobre E/S sincrónica del Kestrel artículo.

Si se necesita E/S sincrónica, se puede habilitar configurando la opción AllowSynchronousIO en el servidor que se usa (por ejemplo, al llamar a ConfigureKestrel si se usa Kestrel). Tenga en cuenta que los servidores (Kestrel, HttpSys, TestServer, etc.) tienen su propia opción AllowSynchronousIO que no afectará a otros servidores. La E/S sincrónica se puede habilitar para todos los servidores por solicitud mediante la opción IHttpBodyControlFeature.AllowSynchronousIO:

var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>();

if (syncIOFeature != null)
{
    syncIOFeature.AllowSynchronousIO = true;
}

Si tiene problemas con las implementaciones TextWriter u otras secuencias que llaman a API sincrónicas en Dispose, llame a la nueva API DisposeAsync en su lugar.

Para obtener más información, consulte [Anuncio] AllowSynchronousIO deshabilitado en todos los servidores (dotnet/AspNetCore #7644).

Almacenamiento en búfer del formateador de salida

Los formateadores de salida basados en Newtonsoft.Json, XmlSerializery DataContractSerializer solo admiten la serialización sincrónica. Para permitir que estos formateadores funcionen con las restricciones AllowSynchronousIO del servidor, MVC almacena en búfer la salida de estos formateadores antes de escribir en el disco. Como resultado del almacenamiento en búfer, MVC incluirá el encabezado Content-Length al responder mediante estos formateadores.

System.Text.Json admite la serialización asincrónica y, por consiguiente, el formateador basado en System.Text.Json no almacena en búfer. Considere la posibilidad de usar este formateador para mejorar el rendimiento.

Para deshabilitar el almacenamiento en búfer, las aplicaciones pueden configurar SuppressOutputFormatterBuffering en su inicio:

services.AddControllers(options => options.SuppressOutputFormatterBuffering = true)

Tenga en cuenta que esto puede dar lugar a que la aplicación inicie una excepción de runtime si AllowSynchronousIO no está también configurado.

Ensamblado Microsoft.AspNetCore.Server.Kestrel.Https quitado

En ASP.NET Core 2.1, el contenido de Microsoft.AspNetCore.Server.Kestrel.Https.dll se movió a Microsoft.AspNetCore.Server.Kestrel.Core.dll. Este no fue un cambio importante en el uso de los atributos TypeForwardedTo. Para la versión 3.0, el ensamblado Microsoft.AspNetCore.Server.Kestrel.Https.dll vacío y el paquete NuGet se han quitado.

Las bibliotecas que hacen referencia a Microsoft.AspNetCore.Server.Kestrel.Https deben actualizar las dependencias de ASP.NET Core a 2.1 o una versión posterior.

Las aplicaciones y bibliotecas que tienen como destino ASP.NET Core 2.1 o versiones posteriores deben quitar las referencias directas al paquete Microsoft.AspNetCore.Server.Kestrel.Https.

Compatibilidad con Newtonsoft.Json (Json.NET)

Como parte del trabajo para mejorar el marco compartido de ASP.NET Core, Newtonsoft.Json (Json.NET) se ha quitado del marco compartido de ASP.NET Core.

El serializador JSON predeterminado para ASP.NET Core ahora es System.Text.Json, que es nuevo en .NET Core 3.0. Considere la posibilidad de usar System.Text.Json cuando sea posible. Es de alto rendimiento y no requiere una dependencia de biblioteca adicional. Sin embargo, dado que System.Text.Json es nuevo, es posible que actualmente falten características que la aplicación necesita. Para obtener más información, consulte Migración desde Newtonsoft.json a System.Text.Json.

Uso de Newtonsoft.Json en un proyecto de SignalR ASP.NET Core 3.0

  • Instale el paquete NuGet Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson.

  • En el cliente, encadene una llamada de método AddNewtonsoftJsonProtocol a la instancia HubConnectionBuilder:

    new HubConnectionBuilder()
        .WithUrl("/chathub")
        .AddNewtonsoftJsonProtocol(...)
        .Build();
    
  • En el servidor, encadene una llamada de método AddNewtonsoftJsonProtocol a la llamada de método AddSignalR en Startup.ConfigureServices:

    services.AddSignalR()
        .AddNewtonsoftJsonProtocol(...);
    

Uso de Newtonsoft.Json en un proyecto de ASP.NET Core 3.0 MVC

  • Instale el paquete Microsoft.AspNetCore.Mvc.NewtonsoftJson.

  • Actualice Startup.ConfigureServices para llamar a AddNewtonsoftJson.

    services.AddMvc()
        .AddNewtonsoftJson();
    

    AddNewtonsoftJson es compatible con los nuevos métodos de registro del servicio MVC:

    • AddRazorPages
    • AddControllersWithViews
    • AddControllers
    services.AddControllers()
        .AddNewtonsoftJson();
    

    La configuración Newtonsoft.Json se puede establecer en la llamada a AddNewtonsoftJson:

    services.AddMvc()
        .AddNewtonsoftJson(options =>
               options.SerializerSettings.ContractResolver =
                  new CamelCasePropertyNamesContractResolver());
    

    Nota: Si el método AddNewtonsoftJson no está disponible, asegúrese de que instaló el paquete Microsoft.AspNetCore.Mvc.NewtonsoftJson. Un error común es instalar el paquete Newtonsoft.Json en lugar del paquete Microsoft.AspNetCore.Mvc.NewtonsoftJson.

Para obtener más información, consulta Agregar compatibilidad con formato JSON basado en Newtonsoft.Json.

Registro del servicio MVC

ASP.NET Core 3.0 agrega nuevas opciones para registrar escenarios de MVC dentro de Startup.ConfigureServices.

Hay disponibles tres nuevos métodos de extensión de nivel superior relacionados con escenarios de MVC en IServiceCollection. Las plantillas usan estos nuevos métodos en lugar de AddMvc. Sin embargo, AddMvc continúa comportándose como lo hacía en versiones anteriores.

En el ejemplo siguiente se agrega compatibilidad con controladores y características relacionadas con la API, pero no con vistas ni páginas. La plantilla de API usa este código:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}

En el ejemplo siguiente se agrega compatibilidad con controladores, características relacionadas con la API y vistas, pero no para páginas. La plantilla Aplicación web (MVC) usa este código:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
}

En el ejemplo siguiente se agrega compatibilidad con Páginas Razor y compatibilidad mínima con controladores. La plantilla Aplicación web usa este código:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
}

Los nuevos métodos también se pueden combinar. El ejemplo siguiente equivale a llamar a AddMvc en ASP.NET Core 2.2:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
}

Código de inicio de enrutamiento

Si una aplicación llama a UseMvc o UseSignalR, migre la aplicación al enrutamiento de punto de conexión si es posible. Para mejorar la compatibilidad del enrutamiento de punto de conexión con versiones anteriores de MVC, hemos revertido algunos de los cambios en la generación de direcciones URL introducidos en ASP.NET Core 2.2. Si experimenta problemas con el enrutamiento de punto de conexión en la versión 2.2, espere mejoras en ASP.NET Core 3.0 con las excepciones siguientes:

  • Si la aplicación implementa IRouter o hereda de Route, use DynamicRouteValuesTransformer como reemplazo.
  • Si la aplicación accede a RouteData.Routers directamente dentro de MVC para analizar direcciones URL, puede reemplazarla por el uso de LinkParser.ParsePathByEndpointName.
    • Defina la ruta con un nombre de ruta.
    • Use LinkParser.ParsePathByEndpointName y pase el nombre de ruta deseado.

El enrutamiento de punto de conexión admite la misma sintaxis de patrón de ruta y las características de creación de patrones de ruta que IRouter. El enrutamiento de punto de conexión admite IRouteConstraint. El enrutamiento de punto de conexión admite [Route], [HttpGet] y los demás atributos de enrutamiento de MVC.

Para la mayoría de las aplicaciones, solo Startup requiere cambios.

Migrar Startup.Configure

Consejos generales:

  • Agregue UseRouting.

  • Si la aplicación llama a UseStaticFiles, coloque UseStaticFiles antes que UseRouting.

  • Si la aplicación usa características de autenticación y autorización como AuthorizePage o [Authorize], coloque la llamada a UseAuthentication y UseAuthorization: después, UseRouting y UseCors, pero antes de UseEndpoints:

    public void Configure(IApplicationBuilder app)
    {
      ...
    
      app.UseStaticFiles();
    
      app.UseRouting();
      app.UseCors();
    
      app.UseAuthentication();
      app.UseAuthorization();
    
      app.UseEndpoints(endpoints => {
         endpoints.MapControllers();
      });
    
  • Reemplace UseMvc o UseSignalR por UseEndpoints.

  • Si la aplicación usa escenarios CORS, como [EnableCors], coloque la llamada a UseCors antes de cualquier otro middleware que use CORS (por ejemplo, coloque UseCors antes de UseAuthentication, UseAuthorization y UseEndpoints).

  • Reemplace IHostingEnvironment por IWebHostEnvironment y agregue una instrucción using para el espacio de nombres Microsoft.AspNetCore.Hosting.

  • Reemplace IApplicationLifetime por IHostApplicationLifetime (espacio de nombres Microsoft.Extensions.Hosting).

  • Reemplace EnvironmentName por Environments (espacio de nombres Microsoft.Extensions.Hosting).

El código siguiente es un ejemplo de Startup.Configure en una aplicación típica de ASP.NET Core 2.2:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseStaticFiles();

    app.UseAuthentication();

    app.UseSignalR(hubs =>
    {
        hubs.MapHub<ChatHub>("/chat");
    });

    app.UseMvc(routes =>
    {
        routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
}

Después de actualizar el código Startup.Configure anterior:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseStaticFiles();

    app.UseRouting();

    app.UseCors();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<ChatHub>("/chat");
        endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
}

Advertencia

Para la mayoría de las aplicaciones, las llamadas a UseAuthentication, UseAuthorization y UseCors deben aparecer entre las llamadas a UseRouting y UseEndpoints para que sean eficaces.

Comprobaciones de estado

Las comprobaciones de estado utilizan el enrutamiento de puntos de conexión con el host genérico. En Startup.Configure, llame a MapHealthChecks en el generador de puntos de conexiones con la dirección URL del punto de conexión o la ruta de acceso relativa:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
});

Los puntos de conexión de las comprobaciones de estado pueden:

  • Especificar uno o más hosts o puertos permitidos.
  • Requerir autorización.
  • Requerir CORS.

Para obtener más información, consulte Comprobaciones de estado en ASP.NET Core.

Guía de middleware de seguridad

La compatibilidad con la autorización y CORS se unifica en torno al enfoque de middleware. Esto permite el uso del mismo middleware y funcionalidad en estos escenarios. En esta versión se proporciona un middleware de autorización actualizado y se mejora el middleware de CORS para que pueda comprender los atributos que usan los controladores MVC.

CORS

Anteriormente, CORS podía ser difícil de configurar. El middleware se proporcionó para su uso en algunos casos de uso, pero los filtros MVC estaban diseñados para usarse sin el middleware en otros casos de uso. Con ASP.NET Core 3.0, se recomienda que todas las aplicaciones que requieran CORS usen el middleware de CORS junto con el enrutamiento de punto de conexión. Se puede proporcionar UseCors con una directiva predeterminada, y los atributos [EnableCors] y [DisableCors] se pueden usar para invalidar la directiva predeterminada cuando sea necesario.

En el ejemplo siguiente:

  • CORS está habilitado para todos los puntos de conexión con la directiva de nombre default.
  • La clase MyController deshabilita CORS con el atributo [DisableCors].
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseCors("default");

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

[DisableCors]
public class MyController : ControllerBase
{
    ...
}

Authorization

En versiones anteriores de ASP.NET Core, se proporcionó compatibilidad con la autorización a través del atributo [Authorize]. El middleware de autorización no estaba disponible. En ASP.NET Core 3.0, se requiere middleware de autorización. Se recomienda colocar el middleware de autorización de ASP.NET Core (UseAuthorization) inmediatamente después de UseAuthentication. El middleware de autorización también se puede configurar con una directiva predeterminada, que se puede invalidar.

En ASP.NET Core 3.0 o versiones posteriores, se llama a UseAuthorization en Startup.Configurey el siguiente HomeController requiere un usuario que haya iniciado sesión:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

public class HomeController : Controller
{
    [Authorize]
    public IActionResult BuyWidgets()
    {
        ...
    }
}

Al usar el enrutamiento de punto de conexión, no se recomienda configurar AuthorizeFilter y, en su lugar, se recomienda confiar en el middleware de autorización. Si la aplicación usa AuthorizeFilter como filtro global en MVC, se recomienda refactorizar el código para proporcionar una directiva en la llamada a AddAuthorization.

Inicialmente se configura DefaultPolicy para requerir autenticación, por lo que no se requiere ninguna configuración adicional. En el ejemplo siguiente, los puntos de conexión de MVC se marcan como RequireAuthorization para que todas las solicitudes se deban autorizar en función de DefaultPolicy. Sin embargo, HomeController permite el acceso sin que el usuario inicie sesión en la aplicación debido a [AllowAnonymous]:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute().RequireAuthorization();
    });
}

[AllowAnonymous]
public class HomeController : Controller
{
    ...
}

Autorización para puntos de conexión específicos

La autorización también se puede configurar para clases específicas de puntos de conexión. El código siguiente es un ejemplo de conversión de una aplicación MVC que configuró un AuthorizeFilter global en una aplicación con una directiva específica que requiere autorización:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    static readonly string _RequireAuthenticatedUserPolicy = 
                            "RequireAuthenticatedUserPolicy";
    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(
                 options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        // Pre 3.0:
        // services.AddMvc(options => options.Filters.Add(new AuthorizeFilter(...));

        services.AddControllersWithViews();
        services.AddRazorPages();
        services.AddAuthorization(o => o.AddPolicy(_RequireAuthenticatedUserPolicy,
                        builder => builder.RequireAuthenticatedUser()));

    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute()
                .RequireAuthorization(_RequireAuthenticatedUserPolicy);
            endpoints.MapRazorPages();
        });
    }
}

Las directivas también se pueden personalizar. DefaultPolicy está configurado para requerir autenticación:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(
                 options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddControllersWithViews();
        services.AddRazorPages();
        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new AuthorizationPolicyBuilder()
              .RequireAuthenticatedUser()
              .Build();
        });

    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute().RequireAuthorization();
            endpoints.MapRazorPages();
        });
    }
}
[AllowAnonymous]
public class HomeController : Controller
{

Como alternativa, todos los puntos de conexión se pueden configurar para requerir autorización sin [Authorize] o RequireAuthorization mediante la configuración de FallbackPolicy. FallbackPolicy es diferente de DefaultPolicy. DefaultPolicy se desencadena mediante [Authorize] o RequireAuthorization, mientras que FallbackPolicy se desencadena cuando no se establece ninguna otra directiva. FallbackPolicy se configura inicialmente para permitir solicitudes sin autorización.

El ejemplo siguiente es el mismo que el ejemplo DefaultPolicy anterior, pero usa FallbackPolicy para requerir siempre la autenticación en todos los puntos de conexión, excepto cuando se especifica [AllowAnonymous]:

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddAuthorization(options =>
    {
        options.FallbackPolicy = new AuthorizationPolicyBuilder()
          .RequireAuthenticatedUser()
          .Build();
    });
}

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

[AllowAnonymous]
public class HomeController : Controller
{
    ...
}

La autorización por middleware funciona sin que el marco tenga ningún conocimiento específico de la autorización. Por ejemplo, las comprobaciones de estado no tienen ningún conocimiento específico de la autorización, pero las comprobaciones de estado pueden tener una directiva de autorización configurable aplicada por el middleware.

Además, cada punto de conexión puede personalizar sus requisitos de autorización. En el ejemplo siguiente, UseAuthorization procesa la autorización con DefaultPolicy, pero el punto de conexión de comprobación de estado /healthz requiere un usuario admin:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints
            .MapHealthChecks("/healthz")
            .RequireAuthorization(new AuthorizeAttribute(){ Roles = "admin", });
    });
}

La protección se implementa para algunos escenarios. El middleware de puntos de conexión produce una excepción si se omite una directiva de CORS o autorización debido a que falta middleware. La compatibilidad con el analizador para proporcionar comentarios adicionales sobre una configuración incorrecta está en curso.

Controladores de autorización personalizados

Si la aplicación usa controladores de autorización personalizados, el enrutamiento de punto de conexión pasa un tipo de recurso diferente a los controladores que MVC. Los controladores que esperan que el recurso de contexto del controlador de autorización sea de tipo AuthorizationFilterContext (el tipo de recurso proporcionado por los filtros MVC) deberá actualizarse para controlar los recursos de tipo RouteEndpoint (el tipo de recurso proporcionado a los controladores de autorización por el enrutamiento de punto de conexión).

MVC sigue usando recursos AuthorizationFilterContext, por lo que si la aplicación usa filtros de autorización de MVC junto con la autorización de enrutamiento de puntos de conexión, puede ser necesario controlar ambos tipos de recursos.

SignalR

La asignación de centros SignalR ahora tiene lugar dentro de UseEndpoints.

Asigne cada centro con MapHub. Como en versiones anteriores, cada centro aparece explícitamente.

En el ejemplo siguiente, se agrega compatibilidad con el centro ChatHubSignalR:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<ChatHub>();
    });
}

Hay una nueva opción para controlar los límites de tamaño de mensaje de los clientes. Por ejemplo, en Startup.ConfigureServices:

services.AddSignalR(hubOptions =>
{
    hubOptions.MaximumReceiveMessageSize = 32768;
});

En ASP.NET Core 2.2, podría establecer TransportMaxBufferSize y eso controlaría eficazmente el tamaño máximo del mensaje. En ASP.NET Core 3.0, esa opción ahora solo controla el tamaño máximo antes de que se observe la contrapresión.

Ensamblados SignalR en el marco compartido

Los ensamblados del lado servidor SignalR de ASP.NET Core ahora están instalados con el SDK de .NET Core. Para obtener más información, consulte Quitar referencias de paquetes obsoletos en esta documentación.

Controladores MVC

La asignación de controladores ahora tiene lugar dentro de UseEndpoints.

Agregue MapControllers si la aplicación usa el enrutamiento de atributos. Dado que el enrutamiento incluye compatibilidad con muchos marcos en ASP.NET Core 3.0 o versiones posteriores, agregar controladores enrutados por atributos es opcional.

Reemplace lo siguiente:

  • MapRoute con MapControllerRoute
  • MapAreaRoute con MapAreaControllerRoute

Dado que el enrutamiento ahora incluye compatibilidad con más que solo MVC, la terminología ha cambiado para hacer que estos métodos indiquen claramente lo que hacen. Las rutas convencionales, como MapControllerRoute/MapAreaControllerRoute/MapDefaultControllerRoute, se aplican en el orden en que se agregan. Coloque primero rutas más específicas (como rutas para un área).

En el ejemplo siguiente:

  • MapControllers agrega compatibilidad con controladores enrutados por atributos.
  • MapAreaControllerRoute agrega una ruta convencional para los controladores de un área.
  • MapControllerRoute agrega una ruta convencional para los controladores.
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapAreaControllerRoute(
            "admin",
            "admin",
            "Admin/{controller=Home}/{action=Index}/{id?}");
        endpoints.MapControllerRoute(
            "default", "{controller=Home}/{action=Index}/{id?}");
    });
}

Se ha quitado el sufijo Async de los nombres de acción de controlador

En ASP.NET Core 3.0, ASP.NET Core MVC quita el sufijo Async de los nombres de acción del controlador. Tanto el enrutamiento como la generación de vínculos se ven afectados por este nuevo valor predeterminado. Por ejemplo:

public class ProductsController : Controller
{
    public async Task<IActionResult> ListAsync()
    {
        var model = await _dbContext.Products.ToListAsync();
        return View(model);
    }
}

Antes de ASP.NET Core 3.0:

  • Se puede acceder a la acción anterior en la ruta Products/ListAsync.

  • La generación de vínculos requiere que se especifique el sufijo Async. Por ejemplo:

    <a asp-controller="Products" asp-action="ListAsync">List</a>
    

En ASP.NET Core 3.0:

  • Se puede acceder a la acción anterior en la ruta Products/List.

  • La generación de vínculos no requiere que se especifique el sufijo Async. Por ejemplo:

    <a asp-controller="Products" asp-action="List">List</a>
    

Este cambio no afecta a los nombres especificados mediante el atributo [ActionName]. El comportamiento predeterminado se deshabilita con el siguiente código en Startup.ConfigureServices:

services.AddMvc(options =>
    options.SuppressAsyncSuffixInActionNames = false);

Hay algunas diferencias en la generación de vínculos (por ejemplo, el uso de Url.Link y API similares). Entre ellas se incluyen las siguientes:

  • De manera predeterminada, cuando se usa el enrutamiento de punto de conexión, no se conserva necesariamente el uso de mayúsculas y minúsculas en los parámetros de ruta en los URI generados. Este comportamiento se puede controlar con la interfaz IOutboundParameterTransformer.
  • La generación de un URI para una ruta no válida (un controlador/acción o una página que no existe) generará una cadena vacía en el enrutamiento del punto de conexión en lugar de generar un URI no válido.
  • Los valores ambientales (parámetros de ruta del contexto actual) no se usan automáticamente en la generación de vínculos con enrutamiento de punto de conexión. Anteriormente, al generar un vínculo a otra acción (o página), los valores de ruta no especificados se inferían a partir de los valores de ambiente de las rutas actuales. Al usar el enrutamiento de puntos de conexión, se deben especificar explícitamente todos los parámetros de ruta durante la generación de vínculos.

Razor Pages

La asignación de Páginas Razor ahora tiene lugar dentro de UseEndpoints.

Agregue MapRazorPages si la aplicación usa Páginas Razor. Dado que el enrutamiento de puntos de conexión incluye compatibilidad con muchos marcos, la adición de Páginas Razor ahora es opcional.

En el método Startup.Configure siguiente, MapRazorPages agrega compatibilidad con Páginas Razor:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Uso de MVC sin enrutamiento de punto de conexión

El uso de MVC mediante UseMvc o UseMvcWithDefaultRoute en ASP.NET Core 3.0 requiere una participación explícita dentro de Startup.ConfigureServices. Esto es necesario porque MVC debe saber si puede basarse en la autorización y el middleware de CORS durante la inicialización. Se proporciona un analizador que advierte si la aplicación intenta usar una configuración no admitida.

Si la aplicación requiere compatibilidad IRouter heredada, deshabilite EnableEndpointRoutingmediante cualquiera de los enfoques siguientes en Startup.ConfigureServices:

services.AddMvc(options => options.EnableEndpointRouting = false);
services.AddControllers(options => options.EnableEndpointRouting = false);
services.AddControllersWithViews(options => options.EnableEndpointRouting = false);
services.AddRazorPages().AddMvcOptions(options => options.EnableEndpointRouting = false);

Comprobaciones de mantenimiento

Las comprobaciones de estado se pueden usar como router-ware con enrutamiento de punto de conexión.

Agregue MapHealthChecks para usar comprobaciones de estado con el enrutamiento de punto de conexión. El método MapHealthChecks acepta argumentos similares a UseHealthChecks. La ventaja de usar MapHealthChecks sobre UseHealthChecks es la capacidad de aplicar la autorización y tener un mayor control específico sobre la directiva de coincidencias.

En el ejemplo siguiente, se llama a MapHealthChecks para un punto de conexión de comprobación de estado en /healthz:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHealthChecks("/healthz", new HealthCheckOptions() { });
    });
}

HostBuilder reemplaza a WebHostBuilder

Las plantillas de ASP.NET Core 3.0 usan Generic Host. Las versiones anteriores usaban Web Host. En el código siguiente se muestra la clase Program generada por la plantilla de ASP.NET Core 3.0:

// requires using Microsoft.AspNetCore.Hosting;
// requires using Microsoft.Extensions.Hosting;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

En el código siguiente se muestra la clase Program generada por la plantilla de ASP.NET Core 2.2:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

IWebHostBuilder permanece en la versión 3.0 y es el tipo de webBuilder que se muestra en el ejemplo de código anterior. WebHostBuilder quedará en desuso en una versión futura y se reemplazará por HostBuilder.

El cambio más significativo de WebHostBuilder a HostBuilder está en la inserción de dependencias (DI). Al usar HostBuilder, solo puede insertar lo siguiente en el constructor de Startup:

Las restricciones de inserción de dependencias HostBuilder:

  • Habilite el contenedor de inserción de dependencias para que se compile solo una vez.
  • Evita los problemas de duración de objetos resultantes, como resolver varias instancias de singletons.

Para obtener más información, consulte Evitar la inserción de servicios de inicio en ASP.NET Core 3.

AddAuthorization se ha movido a otro ensamblado

Los métodos AddAuthorization de ASP.NET Core 2.2 y versiones inferiores en Microsoft.AspNetCore.Authorization.dll:

  • Se ha cambiado el nombre AddAuthorizationCore.
  • Se ha movido a Microsoft.AspNetCore.Authorization.Policy.dll.

Las aplicaciones que usan Microsoft.AspNetCore.Authorization.dll y Microsoft.AspNetCore.Authorization.Policy.dll no se ven afectadas.

Las aplicaciones que no usan Microsoft.AspNetCore.Authorization.Policy.dll deben realizar una de las siguientes acciones:

  • Agregue una referencia a Microsoft.AspNetCore.Authorization.Policy.dll. Este enfoque funciona para la mayoría de las aplicaciones y es todo lo que se requiere.
  • Cambie al uso de AddAuthorizationCore

Para obtener más información, consulte Cambio importante en AddAuthorization(o =>) sobrecarga que reside en un ensamblado diferente n.º 386.

IU de Identity

La interfaz de usuario Identity se actualiza para ASP.NET Core 3.0:

  • Agregue una referencia de paquete a Microsoft.AspNetCore.Identity.UI.
  • Las aplicaciones que no usan Páginas Razor deben llamar a MapRazorPages. Consulte Páginas Razor en este documento.
  • Bootstrap 4 es el marco de la interfaz de usuario predeterminado. Establezca una propiedad de proyecto IdentityUIFrameworkVersion para cambiar el valor predeterminado. Para obtener más información, consulte este anuncio de GitHub.

SignalR

El cliente de JavaScript SignalR ha cambiado de @aspnet/signalr a @microsoft/signalr. Para reaccionar a este cambio, cambie las referencias en los archivos package.json, las instrucciones require y las instrucciones import de ECMAScript.

System.Text.Json es el protocolo predeterminado

System.Text.Json es ahora el protocolo de centro predeterminado que usa el cliente y el servidor.

En Startup.ConfigureServices, llame a AddJsonProtocol para establecer las opciones del serializador.

Server:

services.AddSignalR(...)
        .AddJsonProtocol(options =>
        {
            options.PayloadSerializerOptions.WriteIndented = false;
        })

Cliente:

new HubConnectionBuilder()
    .WithUrl("/chathub")
    .AddJsonProtocol(options =>
    {
        options.PayloadSerializerOptions.WriteIndented = false;
    })
    .Build();

Cambiar a Newtonsoft.Json

Si usa características de Newtonsoft.Json que no se admiten en System.Text.Json, puede volver a Newtonsoft.Json. Consulte Uso de Newtonsoft.Json en un proyecto SignalR de ASP.NET Core 3.0 más atrás en este artículo.

Cachés distribuidas de Redis

El paquete Microsoft.Extensions.Caching.Redis no está disponible para aplicaciones de ASP.NET Core  3.0 o posteriores. Reemplace la referencia del paquete por Microsoft.Extensions.Caching.StackExchangeRedis. Para más información, consulte Almacenamiento en caché distribuido en ASP.NET Core.

Participación en la compilación en tiempo de ejecución

Antes de ASP.NET Core 3.0, la compilación en tiempo de ejecución de vistas era una característica implícita del marco. La compilación en tiempo de ejecución complementa la compilación en tiempo de compilación de las vistas. Permite al marco compilar vistas y páginas Razor (archivos .cshtml) cuando se modifican los archivos, sin tener que recompilar toda la aplicación. Esta característica admite el escenario de realizar una edición rápida en el IDE y actualizar el explorador para ver los cambios.

En ASP.NET Core 3.0, la compilación en tiempo de ejecución es un escenario de participación. La compilación en tiempo de ejecución es el único mecanismo para ver la compilación habilitada de manera predeterminada. El runtime se basa en Visual Studio o dotnet-watch en Visual Studio Code para recompilar el proyecto cuando detecta cambios en los archivos .cshtml. En Visual Studio, cambia a los archivos .cs, .cshtmlo .razor del proyecto que se ejecuta (Ctrl+F5), pero no se depura (F5), desencadena la recompilación del proyecto.

Para habilitar la compilación en tiempo de ejecución en el proyecto de ASP.NET Core 3.0:

  1. Instale el paquete NuGet Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.

  2. Actualice Startup.ConfigureServices para llamar a AddRazorRuntimeCompilation:

    Para ASP.NET Core MVC, use el código siguiente:

    services.AddControllersWithViews()
        .AddRazorRuntimeCompilation(...);
    

    Para Páginas Razor de ASP.NET Core, use el código siguiente:

    services.AddRazorPages()
        .AddRazorRuntimeCompilation(...);
    

El ejemplo en https://github.com/aspnet/samples/tree/main/samples/aspnetcore/mvc/runtimecompilation muestra un ejemplo de habilitación condicional de la compilación en tiempo de ejecución en entornos de desarrollo.

Para obtener más información sobre la compilación de archivos Razor, consulteCompilación de archivos Razor en ASP.NET Core.

Migración de bibliotecas a través de varios destinos

Las bibliotecas suelen necesitar admitir varias versiones de ASP.NET Core. La mayoría de las bibliotecas compiladas con versiones anteriores de ASP.NET Core deberían seguir funcionando sin problemas. Las condiciones siguientes requieren que la aplicación se compile de forma cruzada:

  • La biblioteca se basa en una característica que tiene un cambio importante binario.
  • La biblioteca quiere aprovechar las nuevas características de ASP.NET Core 3.0.

Por ejemplo:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netcoreapp3.0;netstandard2.0</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
    <PackageReference Include="Microsoft.AspNetCore" Version="2.1.0" />
  </ItemGroup>
</Project>

Use #ifdefs para habilitar las API específicas de ASP.NET Core 3.0:

var webRootFileProvider =
#if NETCOREAPP3_0
    GetRequiredService<IWebHostEnvironment>().WebRootFileProvider;
#elif NETSTANDARD2_0
    GetRequiredService<IHostingEnvironment>().WebRootFileProvider;
#else
#error unknown target framework
#endif

Para obtener más información sobre el uso de las API de ASP.NET Core en una biblioteca de clases, consulte Uso de las API de ASP.NET Core en una biblioteca de clases.

Cambios varios

El sistema de validación de .NET Core 3.0 y versiones posteriores trata las propiedades enlazadas o los parámetros que no aceptan valores NULL como si tuvieran un atributo [Required]. Para obtener más información, consulte Atributo [requerido].

Publicar

Elimine las carpetas bin y obj en el directorio del proyecto.

TestServer

En el caso de las aplicaciones que usan TestServer directamente con el host genérico, cree TestServer en IWebHostBuilder en ConfigureWebHost:

[Fact]
public async Task GenericCreateAndStartHost_GetTestServer()
{
    using var host = await new HostBuilder()
        .ConfigureWebHost(webBuilder =>
        {
            webBuilder
                .UseTestServer()
                .Configure(app => { });
        })
    .StartAsync();

    var response = await host.GetTestServer().CreateClient().GetAsync("/");

    Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}

Cambios importantes en la API

Revise los cambios importantes:

Enrutamiento de puntos de conexión con el parámetro catch-all

Advertencia

Un parámetro catch-all puede relacionar rutas de forma incorrecta debido a un error en el enrutamiento. Las aplicaciones afectadas por este error tienen las características siguientes:

  • Una ruta catch-all (por ejemplo, {**slug}")
  • La ruta catch-all causa un error al relacionar solicitudes que sí que debería relacionar.
  • Al quitar otras rutas, la ruta catch-all empieza a funcionar.

Para ver casos de ejemplo relacionados con este error, consulte los errores 18677 y 16579 en GitHub.

Se incluye una corrección de participación para este error en el SDK de .NET Core 3.1.301 y versiones posteriores. En el código que hay a continuación se establece un cambio interno que corrige este error:

public static void Main(string[] args)
{
   AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior", 
                         true);
   CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.

.NET Core 3.0 en Azure App Service

El lanzamiento de .NET Core en Azure App Service ha finalizado. .NET Core 3.0 está disponible en todos los centros de datos de Azure App Service.

Módulo de ASP.NET Core (ANCM)

Si el módulo de ASP.NET Core (ANCM) no era un componente seleccionado cuando Visual Studio se instaló o si se instaló una versión anterior de ANCM en el sistema, descargue el instalador de agrupación de hospedaje de .NET Core más reciente (descarga directa) y ejecute el instalador. Para obtener más información, consulte Agrupación de hospedaje.