Migrar do ASP.NET Core 1.x para 2.0

Por Scott Addie

Neste artigo, vamos orientá-lo pela atualização de um projeto existente ASP.NET Core 1.x para o ASP.NET Core 2.0. A migração do aplicativo para o ASP.NET Core 2.0 permite que você aproveite muitos novos recursos e melhorias de desempenho.

Os aplicativos ASP.NET Core 1.x existentes baseiam-se em modelos de projeto específicos à versão. Conforme a estrutura do ASP.NET Core evolui, os modelos do projeto e o código inicial contido neles também. Além de atualizar a estrutura ASP.NET Core, você precisa atualizar o código para o aplicativo.

Pré-requisitos

Veja a Introdução ao ASP.NET Core.

Atualizar TFM (Moniker da Estrutura de Destino)

Projetos direcionados ao .NET Core devem usar o TFM de uma versão maior ou igual ao .NET Core 2.0. Pesquise pelo nó <TargetFramework> no arquivo .csproj e substitua o texto interno por netcoreapp2.0:

<TargetFramework>netcoreapp2.0</TargetFramework>

Projetos direcionados ao .NET Framework devem usar o TFM de uma versão maior ou igual ao .NET Framework 4.6.1. Pesquise pelo nó <TargetFramework> no arquivo .csproj e substitua o texto interno por net461:

<TargetFramework>net461</TargetFramework>

Observação

O .NET Core 2.0 oferece uma área de superfície muito maior do que o .NET Core 1.x. Se você estiver direcionando o .NET Framework exclusivamente devido a APIs ausentes no .NET Core 1.x, o direcionamento do .NET Core 2.0 provavelmente funcionará.

Se o arquivo de projeto contiver <RuntimeFrameworkVersion>1.{sub-version}</RuntimeFrameworkVersion>, confira esse problema de GitHub.

Atualizar a versão do SDK do .NET Core no global.json

Se a solução depender de um arquivo global.json para ser direcionada a uma versão específica do SDK do .NET Core, atualize a propriedade version para que ela use a versão 2.0 instalada no computador:

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

Referências do pacote de atualização

O arquivo .csproj em um projeto 1.x lista cada pacote NuGet usado pelo projeto.

Em um projeto ASP.NET Core 2.0 direcionado ao .NET Core 2.0, uma única referência de metapacote no arquivo .csproj substitui a coleção de pacotes:

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

Todos os recursos do ASP.NET Core 2.0 e do Entity Framework Core 2.0 são incluídos no metapacote.

Os projetos do ASP.NET Core 2.0 direcionados ao .NET Framework devem continuar a referenciar pacotes NuGet individuais. Atualize o atributo Version de cada nó <PackageReference /> para 2.0.0.

Por exemplo, esta é a lista de nós <PackageReference /> usados em um projeto ASP.NET Core 2.0 típico direcionado ao .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>

O pacote Microsoft.Extensions.CommandLineUtils foi desativado. Ele ainda está disponível, mas sem suporte.

Atualizar ferramentas da CLI do .NET Core

No arquivo .csproj, atualize o atributo Version de cada nó <DotNetCliToolReference /> para 2.0.0.

Por exemplo, esta é a lista de ferramentas da CLI usadas em um projeto ASP.NET Core 2.0 típico direcionado ao .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>

Renomear a propriedade de Fallback de Destino do Pacote

O arquivo .csproj. de um projeto 1.x usou um nó PackageTargetFallback e uma variável:

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

Renomeie o nó e a variável como AssetTargetFallback:

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

Atualizar o método Main em Program.cs

Em projetos 1.x, o método Main de Program.cs era parecido com este:

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

Em projetos 2.0, o método Main de Program.cs foi 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();
    }
}

A adoção desse novo padrão do 2.0 é altamente recomendada e é necessária para que os recursos de produto como as Migrações do Entity Framework (EF) Core funcionem. Por exemplo, a execução de Update-Database na janela do Console do Gerenciador de Pacotes ou de dotnet ef database update na linha de comando (em projetos convertidos no ASP.NET Core 2.0) gera o seguinte erro:

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.

Adicionar provedores de configuração

Nos projetos 1.x, a adição de provedores de configuração em um aplicativo foi realizada por meio do construtor Startup. As etapas incluíram a criação de uma instância de ConfigurationBuilder, o carregamento de provedores aplicáveis (variáveis de ambiente, configurações do aplicativo, etc.) e a inicialização de um membro 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; }

O exemplo anterior carrega o membro Configuration com definições de configuração do appsettings.json, bem como qualquer arquivo appsettings.{Environment}.json correspondente à propriedade IHostingEnvironment.EnvironmentName. Estes arquivos estão localizados no mesmo caminho que Startup.cs.

Nos projetos 2.0, o código de configuração clichê inerente aos projetos 1.x é executado de modo oculto. Por exemplo, as variáveis de ambiente e as configurações do aplicativo são carregadas na inicialização. O código Startup.cs equivalente é reduzido à inicialização de IConfiguration com a instância injetada:

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

public IConfiguration Configuration { get; }

Para remover os provedores padrão adicionados por WebHostBuilder.CreateDefaultBuilder, invoque o método Clear na propriedade IConfigurationBuilder.Sources dentro de ConfigureAppConfiguration. Para adicionar os provedores de volta, utilize o método ConfigureAppConfiguration em 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();

A configuração usada pelo método CreateDefaultBuilder no snippet de código anterior pode ser vista aqui.

Para obter mais informações, consulte Configuração no ASP.NET Core.

Mover código de inicialização do banco de dados

Em projetos do 1.x que usam o EF Core 1.x, um comando como dotnet ef migrations add faz o seguinte:

  1. Cria uma instância Startup
  2. Invoca o método ConfigureServices para registrar todos os serviços com injeção de dependência (incluindo tipos DbContext)
  3. Executa suas tarefas de requisito

Em projetos do 2.0 que usam o EF Core 2.0, o Program.BuildWebHost é invocado para obter os serviços do aplicativo. Ao contrário do 1.x, isso tem o efeito colateral adicional de chamar o Startup.Configure. Caso seu aplicativo do 1.x tenha chamado o código de inicialização do banco de dados no seu método Configure, problemas inesperados poderão ocorrer. Por exemplo, se o banco de dados ainda não existir, o código de propagação será executado antes da execução do comando das Migrações do EF Core. Esse problema fará com que um comando dotnet ef migrations list falhe se o banco de dados ainda não existir.

Considere o seguinte código de inicialização de propagação do 1.x no método Configure de Startup.cs:

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

SeedData.Initialize(app.ApplicationServices);

Em projetos do 2.0, mova a chamada SeedData.Initialize para o método Main do 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 do 2.0, é uma prática inadequada realizar qualquer ação no BuildWebHost, exceto compilação e configuração do host da Web. Tudo relacionado à execução do aplicativo deve ser tratado fora do BuildWebHost – normalmente, no método Main de Program.cs.

Examinar a configuração de compilação do modo de exibição do Razor

Um tempo de inicialização mais rápido do aplicativo e pacotes publicados menores são de extrema importância para você. Por esses motivos, a opção Compilação de exibição do Razor é habilitada por padrão no ASP.NET Core 2.0.

A configuração da propriedade MvcRazorCompileOnPublish como verdadeiro não é mais necessária. A menos que você esteja desabilitando a compilação de exibição, a propriedade poderá ser removida do arquivo .csproj.

Ao direcionar o .NET Framework, você ainda precisa referenciar explicitamente o pacote NuGet Microsoft.AspNetCore.Mvc.Razor.ViewCompilation no arquivo .csproj:

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

Depender dos recursos “Light-Up” do Application Insights

A instalação fácil da instrumentação de desempenho do aplicativo é importante. Agora, você pode contar com os novos recursos “light-up” do Application Insights disponíveis nas ferramentas do Visual Studio 2017.

Os projetos do ASP.NET Core 1.1 criados no Visual Studio 2017 adicionaram o Application Insights por padrão. Se não estiver usando o SDK do Application Insights diretamente, fora de Program.cs e Startup.cs, siga estas etapas:

  1. Se você estiver direcionando ao .NET Core, remova o nó <PackageReference /> seguinte do arquivo .csproj:

    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
    
  2. Se você estiver direcionando ao .NET Core, remova a invocação do método de extensão 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. Remova a chamada à API do lado do cliente do Application Insights de _Layout.cshtml. Ela inclui as duas seguintes linhas de código:

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

Se você estiver usando o SDK do Application Insights diretamente, continue fazendo isso. O metapacote do 2.0 inclui a última versão do Application Insights. Portanto, um erro de downgrade do pacote será exibido se você estiver referenciando uma versão mais antiga.

Adotar melhorias de autenticação/Identity

O ASP.NET Core 2.0 tem um novo modelo de autenticação e uma série de alterações significativas no ASP.NET Core Identity. Se você criar o projeto com a opção Contas de Usuário Individuais habilitada ou se adicionar manualmente a autenticação ou Identity, consulte Migrar a autenticação e Identity para o ASP.NET Core 2.0.

Recursos adicionais