Migración de ASP.NET Core 1.x a 2.0

Por Scott Addie

En este artículo se le guía a lo largo del proceso de actualización de un proyecto existente de ASP.NET Core 1.x a ASP.NET Core 2.0. La migración de la aplicación a ASP.NET Core 2.0 permite aprovechar muchas características nuevas y mejoras de rendimiento.

Las aplicaciones existentes de ASP.NET Core 1.x se basan en plantillas de proyecto específicas de la versión. A medida que el marco de trabajo de ASP.NET Core evoluciona, también lo hacen las plantillas de proyecto y el código de inicio incluido en ellas. Además de actualizar el marco de trabajo de ASP.NET Core, debe actualizar el código de la aplicación.

Requisitos previos

Consulte Introducción a ASP.NET Core.

Actualización del moniker de la plataforma de destino (TFM)

Los proyectos para .NET Core deben usar el TFM de una versión mayor o igual que .NET Core 2.0. Busque el nodo <TargetFramework> del archivo .csproj y reemplace su texto interno por netcoreapp2.0:

<TargetFramework>netcoreapp2.0</TargetFramework>

Los proyectos para .NET Framework deben usar el TFM de una versión mayor o igual que .NET Framework 4.6.1. Busque el nodo <TargetFramework> del archivo .csproj y reemplace su texto interno por net461:

<TargetFramework>net461</TargetFramework>

Nota

.NET Core 2.0 ofrece un área expuesta mucho mayor que .NET Core 1.x. Si el destino es .NET Framework solo porque faltan API en .NET Core 1.x, el uso de .NET Core 2.0 como destino es probable que dé resultado.

Si el archivo de proyecto contiene <RuntimeFrameworkVersion>1.{sub-version}</RuntimeFrameworkVersion>, consulte este problema de GitHub.

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 para usar la versión 2.0 instalada en el equipo:

{
  "sdk": {
    "version": "2.0.0"
  }
}

Actualización de las referencias del paquete

El archivo .csproj de un proyecto de 1.x enumera cada paquete NuGet usado por el proyecto.

En un proyecto de ASP.NET Core 2.0 para .NET Core 2.0, una sola referencia de metapaquete del archivo .csproj reemplaza a la colección de paquetes:

<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.9" />
</ItemGroup>

Todas las características de ASP.NET Core 2.0 y Entity Framework Core 2.0 están incluidas en el metapaquete.

Los proyectos de ASP.NET Core 2.0 para .NET Framework deben seguir haciendo referencia a paquetes NuGet individuales. Actualización del atributo Version de cada nodo <PackageReference /> a 2.0.0.

Por ejemplo, esta es la lista de nodos <PackageReference /> usados en un proyecto típico de ASP.NET Core 2.0 para .NET Framework:

<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore" Version="2.0.0" />
  <PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.0.0" />
  <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="2.0.0" />
  <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.0.0" />
  <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" />
  <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="2.0.0" PrivateAssets="All" />
  <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" PrivateAssets="All" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" PrivateAssets="All" />
  <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.0.0" />
  <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.0" PrivateAssets="All" />
</ItemGroup>

El paquete Microsoft.Extensions.CommandLineUtils se ha retirado. Sigue estando disponible, pero sin compatibilidad.

Actualización de las herramientas de la CLI de .NET

En el archivo .csproj, actualice el atributo Version de cada nodo <DotNetCliToolReference /> a 2.0.0.

Por ejemplo, esta es la lista de herramientas de la CLI usadas en un proyecto típico de ASP.NET Core 2.0 para .NET Core 2.0:

<ItemGroup>
  <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
  <DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" />
  <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />
</ItemGroup>

Cambio de nombre de la propiedad Package Target Fallback

El archivo .csproj de un proyecto de 1.x usa un nodo PackageTargetFallback y una variable:

<PackageTargetFallback>$(PackageTargetFallback);portable-net45+win8+wp8+wpa81;</PackageTargetFallback>

Cambie el nombre del nodo y la variable a AssetTargetFallback:

<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

Actualización del método Main de Program.cs

En los proyectos de 1.x, el método Main de Program.cs tenía este aspecto:

using System.IO;
using Microsoft.AspNetCore.Hosting;

namespace AspNetCoreDotNetCore1App
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .UseApplicationInsights()
                .Build();

            host.Run();
        }
    }
}

En los proyectos de 2.0, el método Main de Program.cs se ha simplificado:

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace AspNetCoreDotNetCore2App
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}

La adopción de este nuevo patrón 2.0 es muy recomendable y necesaria para que funcionen características de producto como las migraciones de Entity Framework (EF) Core. Por ejemplo, la ejecución de Update-Database desde la ventana Consola del Administrador de paquetes o de dotnet ef database update desde la línea de comandos (en proyectos convertidos a ASP.NET Core 2.0) genera el error siguiente:

Unable to create an object of type '<Context>'. Add an implementation of 'IDesignTimeDbContextFactory<Context>' to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.

Incorporación de proveedores de configuración

En los proyectos de 1.x, la incorporación de proveedores de configuración a una aplicación se lograba a través del constructor Startup. Para ello, era necesario crear una instancia de ConfigurationBuilder, cargar los proveedores aplicables (variables de entorno, configuración de la aplicación, etc.) e inicializar un miembro de IConfigurationRoot.

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

    if (env.IsDevelopment())
    {
        builder.AddUserSecrets<Startup>();
    }

    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; }

En el ejemplo anterior se carga el miembro Configuration con opciones de configuración de appsettings.json, así como cualquier archivo appsettings.{Environment}.json que coincida con la propiedad IHostingEnvironment.EnvironmentName. La ubicación de estos archivos está en la misma ruta de acceso que Startup.cs.

En los proyectos de 2.0, el código de configuración reutilizable inherente a los proyectos de 1.x se ejecuta en segundo plano. Por ejemplo, las variables de entorno y la configuración de la aplicación se cargan durante el inicio. El código de Startup.cs equivalente se reduce a la inicialización de IConfiguration con la instancia insertada:

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

public IConfiguration Configuration { get; }

Para quitar los proveedores predeterminados que WebHostBuilder.CreateDefaultBuilder agrega, invoque el método Clear en la propiedad IConfigurationBuilder.Sources dentro de ConfigureAppConfiguration. Para volver a agregar proveedores, use el método ConfigureAppConfiguration en Program.cs:

public static void Main(string[] args)
{
    BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureAppConfiguration((hostContext, config) =>
        {
            // delete all default configuration providers
            config.Sources.Clear();
            config.AddJsonFile("myconfig.json", optional: true);
        })
        .Build();

La configuración que el método CreateDefaultBuilder utiliza en el fragmento de código anterior puede verse aquí.

Para más información, consulte Configuración en ASP.NET Core.

Mover el código de inicialización de la base de datos

En proyectos de 1.x que usen EF Core 1.x, un comando como dotnet ef migrations add hace lo siguiente:

  1. Crea una instancia de Startup.
  2. Invoca el método ConfigureServices para registrar todos los servicios de la inserción de dependencias (como los tipos DbContext).
  3. Realiza las tareas necesarias.

En proyectos 2.0 que usen EF Core 2.0, se invoca Program.BuildWebHost para obtener los servicios de aplicación. A diferencia de 1.x, se invoca Startup.Configure como efecto secundario adicional. Si la aplicación 1.x ha invocado el código de inicialización de la aplicación en el método Configure, pueden producirse errores inesperados. Por ejemplo, si todavía no existe la base de datos, el código de propagación se ejecuta antes que el comando EF Core Migrations. Este problema provocará un error en un comando dotnet ef migrations list si la base de datos no existe.

Tenga en cuenta el código de propagación 1.x siguiente en el método Configure de Startup.cs:

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

SeedData.Initialize(app.ApplicationServices);

En los proyectos 2.0, mueva la llamada SeedData.Initialize al método Main de Program.cs:

var host = BuildWebHost(args);

using (var scope = host.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    try
    {
        // Requires using RazorPagesMovie.Models;
        SeedData.Initialize(services);
    }
    catch (Exception ex)
    {
        var logger = services.GetRequiredService<ILogger<Program>>();
        logger.LogError(ex, "An error occurred seeding the DB.");
    }
}

host.Run();

A partir de 2.0 se desaconseja cualquier acción en BuildWebHost, excepto la compilación y la configuración del host web. Todo lo relacionado con la ejecución de la aplicación deberá gestionarse fuera de BuildWebHost, normalmente en el método Main de Program.cs.

Revisión de la configuración de compilación de la vista de Razor

Un tiempo de inicio de aplicación más rápido y unos lotes publicados más pequeños son de la máxima importancia para el usuario. Por ello, la compilación de la vista de Razor está habilitada de forma predeterminada en ASP.NET Core 2.0.

Ya no es necesario establecer la propiedad MvcRazorCompileOnPublish en true. A menos que se esté deshabilitando la compilación de la vista, se puede quitar la propiedad del archivo .csproj.

Si el destino es .NET Framework, se debe hacer referencia de forma explícita al paquete NuGet Microsoft.AspNetCore.Mvc.Razor.ViewCompilation en el archivo .csproj:

<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="2.0.0" PrivateAssets="All" />

Características "light-up" de Application Insights como base

Es importante configurar sin esfuerzo la instrumentación de rendimiento de la aplicación. Ahora puede basarse en las nuevas características "light-up" de Application Insights disponibles en las herramientas de Visual Studio 2017.

Los proyectos de ASP.NET Core 1.1 creados en Visual Studio 2017 han agregado Application Insights de forma predeterminada. Si no usa el SDK de Application Insights directamente, fuera de Program.cs y Startup.cs, siga estos pasos:

  1. Si el destino es .NET Core, elimine el siguiente nodo <PackageReference /> del archivo .csproj:

    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
    
  2. Si el destino es .NET Core, elimine la invocación del método de extensión UseApplicationInsights de Program.cs:

    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .UseApplicationInsights()
            .Build();
    
        host.Run();
    }
    
  3. Quite la llamada API del lado cliente de Application Insights de _Layout.cshtml. Comprende las dos líneas de código siguientes:

    @inject Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet JavaScriptSnippet
    @Html.Raw(JavaScriptSnippet.FullScript)
    

Si usa el SDK de Application Insights directamente, siga haciéndolo. El metapaquete 2.0 incluye la versión más reciente de Application Insights, por lo que si se hace referencia a una versión anterior, aparece un error de degradación de paquete.

Mejoras de Identity y adopción de la autenticación

ASP.NET Core 2.0 tiene un nuevo modelo de autenticación y presenta una serie de cambios significativos en ASP.NET Core Identity. Si ha creado el proyecto con la opción Cuentas de usuario individuales habilitada, o bien si ha agregado manualmente la autenticación o Identity, vea Migración de la autenticación e Identity a ASP.NET Core 2.0.

Recursos adicionales