Setembro de 2017

Volume 32 - Número 9

ASP.NET Core - Introdução ao ASP.NET Core 2.0

Por Mike Rousos | Setembro de 2017

O ASP.NET Core facilita a criação de aplicativos Web entre plataformas rápidos e portáteis. Este artigo mostrará passo a passo como desenvolver um site ASP.NET Core e mostrará o papel de cada arquivo no projeto. Ele também explicará conceitos importantes sobre o ASP.NET Core. O artigo focará especialmente nas alterações no ASP.NET Core 2.0 para ajudar os leitores que já conhecem o ASP.NET Core 1.0 e o 1.1 a migrarem para a versão 2.0.

Criando um projeto do ASP.NET Core

Os projetos do ASP.NET Core podem ser criados a partir de modelos usando o Visual Studio ou a interface de linha de comando do .NET Core (.NET CLI). O Visual Studio 2017 oferece uma experiência de desenvolvimento excelente no .NET Core — com um depuramento de última geração, integração com o Docker e muitos outros recursos — mas eu usarei o .NET CLI e o Visual Studio Code nesta explicação caso você queira acompanhá-la em um computador de desenvolvimento Mac ou Linux.

O novo comando dotnet é usado para criar novos projetos do .NET Core. Executar um novo dotnet sem qualquer argumento adicional listará os modelos de projeto disponíveis, como mostrado na Figura 1. Se você estiver familiarizado com as versões anteriores do .NET CLI, você verá uma série de modelos novos na versão 2.0.

Novos modelos de projeto do .NET Core

Figura 1 Novos modelos de projeto do .NET Core

Modelos Angular e React.js SPA: Esses modelos criam um aplicativo ASP.NET Core que atende um aplicativo de página única (usando um Angular 4 ou React.js) como seu front-end. Os modelos incluem tanto aplicativos front-end quanto back-end, assim como configuração Webpack para compilar o front-end (e modificações csproj para iniciar a compilação Webpack sempre que um projeto ASP.NET Core é compilado).

Aplicativo ASP.NET Core Web com Páginas Razor: As Páginas Razor é um novo recurso do ASP.NET Core 2.0 que permite criar páginas que podem lidar diretamente com solicitações (sem precisar de um controlador). Eles são uma ótima opção para cenários que se ajustam a um modelo de programação baseado em página.

Nestas instruções básicas, vamos começar com o modelo de Páginas Razor executando o novo razor do dotnet. Assim que o projeto for criado, você deverá conseguir executá-lo por meio do dotnet. Nas últimas versões do .NET Core, teria sido necessário executar primeiro a restauração do dotnet para instalar os pacotes NuGet necessários. Mas, começando com o .NET Core 2.0, o comando de restauro é agora automaticamente executado pelos comandos CLI que dependem dele. Siga em frente e teste o site do modelo executando o dotnet e navegando até a URL na qual o aplicativo está escutando (provavelmente http://localhost:5000). Você deverá ver o aplicativo Web renderizado (como na Figura 2).

 Um aplicativo ASP.NET Core simples em execução

Figura 2 Um aplicativo ASP.NET Core simples em execução

Parabéns pode iniciar seu primeiro aplicativo ASP.NET Core 2.0! Agora que você tem um aplicativo Web simples em execução, vamos ver os conteúdos do projeto para entender melhor como o ASP.NET Core funciona.

Dependências, fontes e recursos

O primeiro arquivo a observar é o próprio arquivo de projeto, o .csproj. O arquivo diz ao MSBuild como compilar o projeto, quais pacotes dependem dele, qual versão .NET Core usar, e assim por diante. Se você já observou arquivos .csproj no passado, perceberá que este arquivo de projeto é muito menor. Foram realizados muitos esforços para tornar os arquivos .csproj mais curtos e mais fáceis de ler. Os arquivos de origem já não precisam mais ser listados de forma explícita, alteração que ajudou bastante na redução do tamanho do arquivo de projeto. Em vez disso, o SDL do .NET Core compilará automaticamente qualquer arquivo .cs no arquivo de projeto ou em qualquer diretório no .csproj. De forma semelhante, todos os arquivos .resx encontrados serão inseridos como recursos. Se você preferir não ter todos esses arquivos .cs compilados, você pode removê-los do ItemGroup Compilar ou desabilitar os itens de compilação completamente configurando a propriedade EnableDefaultCompileItems como falso.

A versão do .NET que o aplicativo deve executar é especificado pelo elemento <TargetFramework>. Isso é definido como netcoreapp2.0 com o objetivo de aproveitar os novos recursos do ASP.NET Core 2.0 e a área de superfície muito maior do .NET Core 2.0.

O elemento <PackageReference> no meio do arquivo .csproj indica um pacote NuGet do qual o projeto depende. Você perceberá no ASP.NET Core 2.0 que agora você só pode incluir um pacote meta por padrão (Microsoft.AspNetCore.All). Este pacote inclui todos os pacotes Microsoft.AspNetCore em uma referência sucinta e torna os arquivos de projeto ASP.NET Core 2.0 muito menores do que os arquivos de projeto das versões anteriores. As dependências adicionais do NuGet podem ser adicionadas com a inclusão de mais elementos <PackageReference>, usando a interface do usuário do Pacote NuGet do Visual Studio ou com o comando de adição dotnet da interface de linha de comando do .NET.

Se você estiver usando um modelo SPA (angular, react ou reactredux), também haveriam destinos personalizados no arquivo .csproj para ter certeza de que o Webpack foi executado durante a compilação do projeto.

Criando e executando o host da Web

Program.cs representa o ponto de entrada do aplicativo. Os aplicativos do ASP.NET Core são aplicativos de console, por isso, como todos os aplicativos de console, possuem um método Main que inicia quando o aplicativo é executado.

Os conteúdos dos modelos dos métodos Main do ASP.NET Core 2.0 são muito simples — eles criam um objeto IWebHost e chamam Run nele.

Se você usou anteriormente o ASP.NET Core 1.0, você perceberá que este arquivo é um pouco mais simples que o programa program.cs desses modelos mais antigos. A razão disto é o novo método WebHost.CreateDefaultBuilder. Anteriormente, o método Main do aplicativo ASP.NET Core configuraria o WebHostBuilder para criar a instância IWebHost. Esta configuração incluía etapas como especificação do servidor Web, configuração do caminho de raiz do conteúdo e ativação da integração IIS.

O novo método CreateDefaultBuilder simplifica coisas como a criação de um IWebHost pronto para funcionamento com a configuração mais comum já feita. Além de especificar os itens listados anteriormente, o CreateDefaultBuilder também trata de algumas configurações que foram anteriormente realizadas no Startup.cs (configuração das informações e dos registros dos provedores de logs padrão). Como o ASP.NET Core é um software de código-fonte aberto, você pode ver todos os detalhes do que o CreateDefaultBuilder está fazendo exibindo sua fonte no GitHub (bit.ly/2uR1Dar), se lhe interessar.

Vamos ver resumidamente as chamadas mais importantes feitas no CreateDefaultBuilder e sus finalidade. Apesar de tudo isso ser feito para você (pelo CreateDefaultBuilder), ainda é bom entender o que está acontecendo nos bastidores.

O UseKestrel especifica que seu aplicativo deve usar Kestrel, um servidor Web entre plataformas baseado em libuv. A outra opção aqui seria usar HttpSys como o servidor Web (UseHttpSys). HttpSys é suportado somente no Windows (Windows 7/2008 R2 e posterior), mas tem as vantagens de permitir a autenticação do Windows e poder ser executado diretamente exposto à Internet com segurança (por outro lado, o Kestrel deve estar por trás de um proxy de inversão como o IIS, Nginx ou Apache se for receber solicitações da Internet).

O UseContentRoot especifica o diretório raiz do aplicativo no qual o ASP.NET Core encontrará conteúdos gerais como os arquivos config. Observe que isto não é o mesmo que a raiz Web (a partir da qual os arquivos estáticos são atendidos), apesar de a raiz Web ser, por padrão, baseada da raiz de conteúdo ([ContentRoot]/wwwroot).

O ConfigureAppConfiguration cria o objeto de configuração que o aplicativo usará para ler as configurações durante o tempo de execução. Quando chamado a partir do CreateDefaultBuilder, isto lerá as definições de configuração de um arquivo appsettings.json, um arquivo .json de ambiente especifico (se existir um), variáveis de ambiente e argumentos de linha de comando. Se for em um ambiente de desenvolvimento, ele também usará segredos de usuário. O método é novo no ASP.NET Core 2.0 e discutiremos isso com mais detalhes posteriormente.

O ConfigureLogging configura o registro para o aplicativo. Quando chamados a partir do CreateDefaultBuilder, os provedores de registro de console e de depuração são adicionados. Como o ConfigureAppConfiguration, este método é novo e será discutido posteriormente.

O UseIISIntegration configura o aplicativo a ser executado no IIS. Observe que o UseKestrel ainda é necessário. O ISS atua como proxy de inversão e o Kestrel ainda é usado como o host. Além disso, o UseIISIntegration não terá qualquer efeito se o aplicativo não estiver sendo executado por trás do ISS, por isso, é seguro chamá-lo mesmo se o aplicativo for executado em cenários que não são de IIS.

Em muitos caos, a configuração padrão fornecida por Create­DefaultBuilder será suficiente. Tudo o que é necessário para além dessa chamada é especificar a classe de inicialização com uma chamada para UseStartup<T>, em que T é o tipo de inicialização.

Se o CreateDefaultBuilder não atender às suas necessidades de cenário, não hesite em personalizar a maneira como o IWebHost é criado. Se você precisar de apenas alguns ajustes, você pode chamar o CreateDefault­Builder e, em seguida, modificar o WebHostBuilder que é retornado (talvez chamando o ConfigureAppConfiguration novamente, por exemplo, para adicionar mais fontes de configuração). Se você precisar fazer alterações maiores no IWebHost, você pode deixar totalmente de chamar o CreateDefaultBuilder e apenas construir um WebHostBuilder sozinho, como teria feito com o ASP.NET Core 1.0 ou o 1.1. Mesmo que você siga este caminho, você ainda pode aproveitar os novos métodos ConfigureAppConfiguration e ConfigureLogging. Para mais detalhes sobre configurações de host, consulte bit.ly/2uuSwwM.

Ambientes do ASP.NET Core

Algumas das ações tomadas pelo CreateDefaultBuilder dependem do ambiente em que seu aplicativo ASP.NET Core está sendo executado. O conceito de ambientes não é novo na versão 2.0, mas vale a pena revisá-lo resumidamente, pois ele surge com frequência.

No ASP.NET Core, o ambiente no qual um aplicativo está sendo executado é indicado pela variável de ambiente ASPNETCORE_ENVIRONMENT. Você pode definir isto com o valor que desejar, sendo que os valores Development, Staging e Production são normalmente os mais usados. Por isso, se você definir a variável ASPNETCORE_ENVIRONMENT como Development antes de chamar uma execução dotnet (ou se você definir essa variável de ambiente em um arquivo launchSettings.json), seu aplicativo será executado em modo Development (em vez de Production, que é o modo padrão sem qualquer definição de variáveis). Este valor é usado por vários recursos do ASP.NET Core (mencionarei isto ao discutir Configuração e Registro mais tarde) para modificar o comportamento do tempo de execução e pode ser acessado em seu próprio código usando o serviço IHostingEnvironment. Para mais informações sobre os ambientes do ASP.NET Core, consulte a documentação disponível no site (bit.ly/2eICDMF).

Configuração do ASP.NET Core

O ASP.NET Core usa a interface IConfiguration do pacote Microsoft.Extensions.Configuration para fornecer definições de configuração de tempo de execução. Como mencionado anteriormente, o CreateDefaultBuilder lerá as configurações dos arquivos .json e das variáveis de ambiente. No entanto, o sistema de configuração é extensível e pode ler a informação de configuração de uma grande variedade de provedores (arquivos .json, arquivos .xml, arquivos .ini, variáveis de ambiente, Azure Key Vault e assim por diante).

Ao trabalhar com os objetos IConfiguration e IConfigurationBuilder, lembre-se de que a ordem em que dos provedores são adicionados é importante. Posteriormente, os provedores pode substituir as configurações de provedores anteriores, por isso, você desejará primeiro adicionar provedores de base comum e, mais tarde, adicionar provedores específicos de ambiente que possam substituir algumas das configurações.

As definições de configuração no ASP.NET Core são hierárquicas. Por exemplo, no novo projeto criado, appsettings.json (veja a Figura 3) contém um elemento de registro de alto nível com sub-configurações por baixo dele. Essas configurações indicam a prioridade mínima de mensagens a ser registrada (por meio das configurações “LogLevel”) e se o escopo lógico do aplicativo no momento em que a mensagem é registrada deve ser gravada (via IncludeScopes). Para recuperar configurações aninhadas como estas, você pode usar o método IConfiguration.GetSection para recuperar uma única seção da configuração ou especificar todo o caminho de uma determinada configuração, delimitada com dois pontos. Por isso, o valor de Include­Scopes no projeto deve ser recuperado como:

Figura 3 Arquivo de configurações do ASP.NET Core

{
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  }
}
Configuration["Logging:IncludeScopes"]

Ao ajustar as definições de configuração com as variáveis de ambiente, o nome da variável de ambiente deve incluir todos os níveis da hierarquia e pode ser delimitado com dois pontos (:) ou sublinhado duplo (__). Por exemplo, uma variável de ambiente chamada Logging__IncludeScopes substituiria a configuração do arquivo de exemplo na Figura 3, assumindo que o provedor da variável de ambiente é adicionado após o arquivo de configurações, como é no caso do CreateDefaultBuilder.

Como o WebHost.CreateDefaultBuilder está lendo a configuração dos arquivos appsettings.json e .json específicos de ambiente, você perceberá que o comportamento de registro é alterado quando você muda os ambientes (appsettings.Development.json substitui as configurações LogLevel padrão do appsettings.json com mais níveis detalhados de “depuração” e “informação”). Se você definir o ambiente para Development antes de chamar a execução do dotnet, você perceberá uma boa parte do registro acontecendo no console (o que é ótimo porque é útil para depurar). Por outro lado, se você definir o ambiente para Production, você não obterá nenhum registro de console para avisos e erros (o que também é ótimo porque o registro de console é lento e deve ser mantido a um mínimo na produção).

Se você tem experiência com o ASP.NET Core 1.0 e 1.1, você deve perceber que o método ConfigureAppConfiguration é novo na versão 2.0. Anteriormente, era comum criar um IConfiguration como parte da criação do tipo Startup. Usar o novo método ConfigureAppConfiguration é uma alternativa útil porque atualiza o objeto IConfiguration armazenado na contêiner da injeção de dependência de aplicativo (DI) para uma recuperação fácil no futuro e torna as definições de configuração dispon+iveis mesmo durante a vida útil do aplicativo.

Registro do ASP.NET Core

Como com o conjunto de configuração, se estiver familiarizado com as versões anteriores do ASP.NET Core você poderá se lembrar da configuração de registro sendo feita no Startup.cs em vez de no Program.cs. No ASP.NET Core 2.0, o registro de configuração pode agora ser feito ao compilar um IWebHost por meio do método ConfigureLogging.

Ainda é possível configurar o registro no Startup (usando services.Add-Logging no Startup.ConfigureServices), mas ao configurar o registro no tempo de criação do host na Web, o tipo de Startup é simplificado e o registro é disponibilizado logo no inicio do processo de inicialização do aplicativo.

Tal como na configuração, a registro do ASP.NET Core é extensível. Diferentes provedores são registrados para entrar em diferentes pontos de extremidade. Muitos provedores são disponibilizados imediatamente com uma referência ao Microsoft.AspNetCore.All, e há ainda mais disponível na comunidade de desenvolvedores do .NET.

Como pode ser visto no código-fonte do WebHost.CreateDefaultBuilder, os provedores de log podem ser adicionados chamando métodos de extensão específicos do provedor como o AddDebug ou o AddConsole no ILoggingBuilder. Se você usar o WebHost.CreateDefaultBuilder mas ainda quiser registrar os provedores de log em vez de os de depuração e de console, é possível fazer isto com uma chamada adicional para o ConfigureLogging no IWebHostBuilder retornado pelo CreateDefaultBuilder

Quando o log tiver sido configurado e os provedores registrados, o ASP.NET Core registrará automaticamente as mensagens relacionadas com seu trabalho de processamento das solicitações de entrada. Você também pode registrar suas próprias mensagens de diagnóstico solicitando um objeto ILogger por meio de uma injeção de dependência (mais sobre isto na próxima seção). Chamadas para o ILogger.Log e as variantes específicas de nível (como LogCritical, LogInformation e assim por diante) são usadas para registrar mensagens.

O tipo Startup

Agora que você viu o Program.cs para perceber como o host da Web é criado, vamos pular para o Startup.cs. O tipo Startup que seu aplicativo deve usar é indicado pela chamada do UseStartup ao criar o IWebHost. Não muita coisa mudou no Startup.cs no ASP.NET Core 2.0 (exceto para se tornar mais simples porque o registro e a configuração são definidos no Program.cs), mas revisarei resumidamente os dois tipos de métodos importantes do Startup porque eles são muito centrais em um aplicativo ASP.NET Core.

A injeção de dependência: o tipo de método ConfigureServices do Startup adiciona serviços ao contêiner de injeção de dependência do aplicativo. Todos os aplicativos ASP.NET Core têm um contêiner de injeção de dependência para armazenar serviços para uso posterior. Isto permite que os serviços sejam realizados sem o acoplamento rígido dos componentes que dependem deles. Se você já viu alguns exemplos disto, tanto o ConfigureAppConfiguration quanto o ConfigureLogging adicionarão serviços ao contêiner para uso posterior em seu aplicativo. Durante o tempo de execução, se uma instância de um tipo de chamada, o ASP.NET Core recuperará automaticamente, se possível, o objeto do contêiner de injeção de dependência.

Por exemplo, sua classe Startup do projeto ASP.NET Core 2.0 tem um construtor que obtém um parâmetro IConfiguration. Este construtor será chamado automaticamente quando seu IWebHost começar a executar. Quando isso acontece, o ASP.NET Core fornecerá o argumento IConfiguration necessário do contêiner de injeção de dependência.

Como outro exemplo, se você quiser registrar mensagens de uma Página Razor, você pode solicitar um objeto de agente como um parâmetro no construtor do modelo de página (como quando o Startup solicita um objeto IConfiguration) ou no cshtml com a sintaxe @inject, conforme mostrado a seguir:

@using Microsoft.Extensions.Logging
@inject ILogger<Index_Page> logger

@functions {
  public void OnGet()
    {
      logger.LogInformation("Beginning GET");
    }
}

Algo semelhando poderia ser feito para recuperar um objeto IConfiguration ou qualquer outro tipo que foi registrado como serviço. Desta forma, o tipo Startup, as Páginas Razor, os controladores e outros podem depender vagamente dos serviços fornecidos no contêiner de injeção de dependência.

Como mencionado no início desta seção, os serviços são adicionados ao contêiner de injeção de dependência no método Startup.ConfigureServices. O modelo de projeto que você usou para criar seu aplicativo já tem uma chamada em ConfigureServices: services.AddMvc. Como você pode adivinhar, isto registra os serviços necessários à estrutura MVC.

Outro tipo de serviço que é comum ver registrado no método ConfigureServices é o Entity Framework Core. Apesar de não ser usado neste exemplo, os aplicativos que fazem uso do Entity Framework Core normalmente registram os DbContexts necessários para trabalhar com os modelos do Entity Framework usando chamadas para o services.AddDbContext.

Você também pode registrar seus próprios tipos e serviços aqui chamando services.AddTransient, services.AddScoped ou services.Add­Singleton (dependendo do tempo de vida necessário para os objetos fornecidos com injeção de dependência). Registrar como um singleton resultará em uma única instância do serviço que é retornado toda vez que seu tipo é solicitado, enquanto o registro como transiente criará uma nova instância para cada solicitação. Adicionar como escopo fará com que uma única instância de um serviço seja usada por todo o processamento de uma única solicitação HTTP. Para mais detalhes sobre injeção de dependência no ASP.NET Core consulte bit.ly/2w7XtJI.

Pipeline de processamento de solicitação HTTP e Middleware Outro método importante no tipo Startup é o método Configure. É aqui que o coração do aplicativo ASP.NET Core — seu pipeline de processamento de solicitação HTTP — é configurado. Neste método, diversas peças do middleware que estão registradas atuarão em solicitações HTTP para gerar respostas.

No Startup.Configure, os componentes do middleware são adicionados a um IApplicationBuilder para formar o pipeline de processamento. Quando uma solicitação chega, a primeira peça de middleware registrada será invocada. Esse middleware realizará a lógica necessária e, em seguida, chamará a próxima peça de middleware no pipeline ou, se tiver abordado completamente a resposta, retornará à peça de middleware anterior (se havia uma anterior) para que ele possa executar toda a lógica necessária após uma resposta ter sido preparada. Este padrão de chamada de componentes de middleware em ordem quando uma solicitação chega e, em seguida, na ordem inversa foi abordado e ilustrado na Figura 4.

Pipeline de processamento de middleware do ASP.NET Core

Figura 4 Pipeline de processamento de middleware do ASP.NET Core

Para usar um exemplo concreto, a Figura 5 mostra o método Configure do projeto de modelo. Dependendo do seu ambiente, quando uma nova solicitação chega, ela irá primeiro para o middleware DeveloperExceptionPage ou para o middleware ExceptionHandler (como anteriormente, isto é configurado com a variável de ambiente ASPNETCORE_ENVIRONMENT). Inicialmente, esses componentes de middleware não agem muito, mas depois que o middleware seguinte for executado e a solicitação estiver voltando do pipeline do middleware, eles terão atenção com as exceções e tratarão delas.

Figura 5 Método Startup.Configure do ASP.NET Core configura o pipeline do middleware

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  if (env.IsDevelopment())
  {
    app.UseDeveloperExceptionPage();
  }
  else
  {
    app.UseExceptionHandler("/Error");
  }

  app.UseStaticFiles();

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

Em seguida, o middleware StaticFiles será chamado, que poderá servir a solicitação fornecendo um arquivo estático (uma imagem ou planilha de estilo, por exemplo). Se ele fizer isto, ele interromperá o pipeline e retornará o controle do middleware anterior (manipuladores de exceção). Se o middleware StaticFiles não pider fornecer uma resposta, ele chamará a próxima peça de middleware — o middleware MVC. Este middleware tentará rotear a solicitação para um controlador MVC (ou Página Razor) para fins de preenchimento, de acordo com as opções de roteamento especificadas.

A ordem em que os componentes de middleware são registrados é muito importante. Se UseStaticFiles vier após UseMvc, o aplicativo tentará rotear todas as solicitações para os controladores MVC antes de verificar os arquivos estáticos. Isso resultará em uma degradação de desempenho! Se o middleware de manipulação de exceção vier posteriormente no pipeline, ele não será capaz de tratar das exceções ocorrendo nos componentes de middleware anteriores.

Páginas Razor

Além dos arquivos .csproj, program.cs e startup.cs, seu projeto ASP.NET Core também contém uma pasta Pages contendo todas as páginas Razor do aplicativo. As páginas são parecidas com os modos de exibição MVC, mas as solicitações podem ser roteadas diretamente para uma Página Razor sem a necessidade de um controlador separado. Isto permite simplificar os aplicativos baseados em página e mantêm as exibições e modelos de exibição juntos. O modelo que oferece suporte à página pode ser incluído diretamente na página cshtml (em uma diretiva de @funções) ou em um arquivo de código separado, que é referenciado com a diretiva de @modelo.

Para saber mais sobre as Páginas Razor, confira o artigo de Steve Smith, “Aplicativos MVC do ASP.NET mais simples com as Páginas Razor” também nesta edição.

Conclusão

Espero que estas instruções ajudem a explicar como criar um novo aplicativo Web do ASP.NET Core 2.0 e a desmistificar os conteúdos dos novos modelos de projeto. Eu revisei os conteúdos do projeto do arquivo .csproj simplificado ao ponto de entrada do aplicativo e configuração de host da Web no Program.cs, para o registro de serviço e middleware no Startup.cs.

Para continuar a obter mais detalhes sobre o que é possível fazer com o ASP.NET Core, poderá ser útil criar alguns dos novos projetos usando outros modelos, como o modelo da API Web ou talvez alguns dos novos modelos SPA. Você também poderá desejar experimentar a implantação de seu aplicativo ASP.NET Core no Azure como um aplicativo Web do Serviço de Aplicativo ou empacotando o aplicativo como uma imagem do Linux ou do Windows Docker. E, é claro, confira toda a documentação em docs.microsoft.com/aspnet/core para mais informações sobre os tópicos abordados neste artigo e muito mais.


Mike Rousos é engenheiro-chefe de software na equipe de Sucesso do Cliente do .NET. Rousos faz parte da equipe .NET desde 2004 e trabalha com tecnologias incluindo rastreamento, segurança gerenciada, hospedagem e, mais recentemente, .NET Core.

Agradecemos aos seguintes especialistas técnicos da Microsoft pela revisão deste artigo: Glenn Condron e Ryan Nowak


Discuta esse artigo no fórum do MSDN Magazine