Atualizar do ASP.NET Framework para o ASP.NET Core
Por que atualizar para o .NET mais recente
ASP.NET Core é o framework web moderno para .NET. Embora ASP.NET Core tenha muitas semelhanças com ASP.NET no .NET Framework, é uma nova estrutura que foi completamente reescrita. ASP.NET aplicações atualizadas para o ASP.NET Core podem beneficiar de um melhor desempenho e acesso às funcionalidades de desenvolvimento web mais recentes.
Abordagens de atualização do ASP.NET Framework
A maioria das aplicações não triviais do ASP.NET Framework deve considerar a utilização da abordagem de atualização incremental . Para obter mais informações, consulte atualização incremental do ASP.NET para o ASP.NET Core.
Para aplicações ASP.NET MVC e Web API, consulte Aprenda a atualizar de ASP.NET MVC e Web API para o ASP.NET Core MVC. Para aplicativos ASP.NET Framework Web Forms, consulte Aprenda a atualizar de ASP.NET Web Forms para ASP.NET Core.
Padrões de aplicativos Web corporativos
Para obter orientação sobre como criar um aplicativo ASP.NET Core confiável, seguro, com desempenho, testável e escalável, consulte Padrões de aplicativos Web corporativos. Está disponível um aplicativo Web de exemplo completo com qualidade de produção que implementa os padrões.
Diferenças de decodificação de URI entre ASP.NET para ASP.NET Core
ASP.NET Core tem as seguintes diferenças de decodificação de URI com o ASP.NET Framework:
ASCII | Codificado | ASP.NET Núcleo | ASP.NET Framework |
---|---|---|---|
\ |
%5C |
\ |
/ |
/ |
%2F |
%2F |
/ |
Ao decodificar %2F
no ASP.NET Core:
- Todo o caminho fica sem escapar, exceto
%2F
porque convertê-lo em/
mudaria a estrutura do caminho. Ele não pode ser decodificado até que o caminho seja dividido em segmentos.
Para gerar o valor para HttpRequest.Url
, use new Uri(this.AspNetCoreHttpRequest.GetEncodedUrl());
para que Uri
não interprete incorretamente os valores.
Migrando segredos de usuário do ASP.NET Framework para o ASP.NET Core
Veja este problema do GitHub.
Este artigo serve como um guia de referência para migrar aplicativos ASP.NET para o ASP.NET Core.
O Visual Studio tem ferramentas para ajudar a migrar ASP.NET aplicativos para o ASP.NET Core. Para obter mais informações, consulte Migrando do ASP.NET para o ASP.NET Core no Visual Studio.
O .NET Upgrade Assistant é uma ferramenta de linha de comando que pode ajudar a migrar ASP.NET para o ASP.NET Core. Para obter mais informações, consulte Visão geral do Assistente de Atualização do .NET e Atualizar um aplicativo MVC ASP.NET para .NET 6 com o Assistente de Atualização do .NET.
Consulte o ebook Portando aplicativos ASP.NET existentes para o .NET Core para obter um guia de portabilidade abrangente.
Pré-requisitos
.NET Core SDK 2.2 ou posterior
Plataformas alvo
Projetos ASP.NET Core oferecem aos desenvolvedores a flexibilidade de se destinar ao .NET Core, ao .NET Framework ou a ambos. Consulte a escolha entre .NET Core e .NET Framework para aplicativos de servidor para determinar qual framework alvo é mais apropriado.
Ao direcionar o .NET Framework, os projetos precisam fazer referência a pacotes NuGet individuais.
O direcionamento do .NET Core permite eliminar inúmeras referências explícitas de pacotes, graças ao ASP.NET Core metapackage. Instale o metapacote Microsoft.AspNetCore.App
em seu projeto:
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
Quando o metapacote é utilizado, nenhum dos pacotes referenciados no metapacote é implantado com a aplicação. O .NET Core Runtime Store inclui esses ativos e eles são pré-compilados para melhorar o desempenho. Consulte o metapacote Microsoft.AspNetCore.App para ASP.NET Core para mais detalhes.
Diferenças na estrutura do projeto
O formato de arquivo .csproj
foi simplificado no ASP.NET Core. Algumas mudanças notáveis incluem:
A inclusão explícita de arquivos não é necessária para que eles sejam considerados parte do projeto. Isso reduz o risco de conflitos de mesclagem XML ao trabalhar em grandes equipes.
Não há referências baseadas em GUID para outros projetos, o que melhora a legibilidade do arquivo.
O arquivo pode ser editado sem descarregá-lo no Visual Studio:
]
Substituição do ficheiro Global.asax
ASP.NET Core introduziu um novo mecanismo para inicializar um aplicativo. O ponto de entrada para aplicativos ASP.NET é o arquivo Global.asax. Tarefas como configuração de rota e registos de filtro e área são tratadas no ficheiro Global.asax.
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Essa abordagem associa o aplicativo e o servidor no qual ele é implantado de uma forma que interfere na implementação. Num esforço para desacoplar, OWIN foi introduzida para fornecer uma maneira mais limpa de usar várias estruturas juntas. O OWIN fornece um pipeline para adicionar apenas os módulos necessários. O ambiente de hospedagem usa uma função Startup para configurar serviços e o pipeline de solicitações do aplicativo.
Startup
registra um conjunto de middleware com o aplicativo. Para cada solicitação, o aplicativo chama cada um dos componentes de middleware com o ponteiro principal de uma lista vinculada para um conjunto existente de manipuladores. Cada componente de middleware pode adicionar um ou mais manipuladores ao pipeline de tratamento de solicitações. Isso é feito retornando uma referência para o manipulador que é a nova cabeça da lista. Cada manipulador é responsável por lembrar e invocar o próximo manipulador na lista. Com o ASP.NET Core, o ponto de entrada para um aplicativo é Startup
e você não depende mais de Global.asax. Ao usar o OWIN com o .NET Framework, use algo como o seguinte como um pipeline:
using Owin;
using System.Web.Http;
namespace WebApi
{
// Note: By default all requests go through this OWIN pipeline. Alternatively you can turn this off by adding an appSetting owin:AutomaticAppStartup with value “false”.
// With this turned off you can still have OWIN apps listening on specific routes by adding routes in global.asax file using MapOwinPath or MapOwinRoute extensions on RouteTable.Routes
public class Startup
{
// Invoked once at startup to configure your application.
public void Configuration(IAppBuilder builder)
{
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("Default", "{controller}/{customerID}", new { controller = "Customer", customerID = RouteParameter.Optional });
config.Formatters.XmlFormatter.UseXmlSerializer = true;
config.Formatters.Remove(config.Formatters.JsonFormatter);
// config.Formatters.JsonFormatter.UseDataContractJsonSerializer = true;
builder.UseWebApi(config);
}
}
}
Isso configura as suas rotas padrão e o padrão é XmlSerialization em detrimento de Json. Adicione outros middleware a este pipeline conforme necessário (carregamento de serviços, definições de configuração, ficheiros estáticos, etc.).
ASP.NET Core usa uma abordagem semelhante, mas não depende do OWIN para lidar com a entrada. Em vez disso, isso é feito através do método Program.cs
Main
(semelhante aos aplicativos de console) e Startup
é carregado por lá.
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace WebApplication2
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}
Startup
deve incluir um método Configure
. Em Configure
, adicione o middleware necessário ao pipeline. No exemplo a seguir (do modelo de site padrão), os métodos de extensão configuram o pipeline com suporte para:
- Páginas de erro
- Segurança de Transporte Estrita HTTP
- Redirecionamento HTTP para HTTPS
- ASP.NET Core MVC
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
O host e o aplicativo foram dissociados, o que oferece a flexibilidade de mudar para uma plataforma diferente no futuro.
Observação
Para obter uma referência mais detalhada ao ASP.NET Core Startup and Middleware, consulte Startup in ASP.NET Core
Configurações da loja
ASP.NET suporta configurações de armazenamento. Essas configurações são usadas, por exemplo, para dar suporte ao ambiente no qual os aplicativos foram implantados. Uma prática comum era armazenar todos os pares chave-valor personalizados na seção <appSettings>
do arquivo Web.config:
<appSettings>
<add key="UserName" value="User" />
<add key="Password" value="Password" />
</appSettings>
Os aplicativos leem essas configurações usando a coleção ConfigurationManager.AppSettings
no namespace System.Configuration
:
string userName = System.Web.Configuration.ConfigurationManager.AppSettings["UserName"];
string password = System.Web.Configuration.ConfigurationManager.AppSettings["Password"];
ASP.NET Core pode armazenar dados de configuração para o aplicativo em qualquer arquivo e carregá-los como parte da inicialização do middleware. O arquivo padrão usado nos modelos de projeto é appsettings.json
:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"AppConfiguration": {
"UserName": "UserName",
"Password": "Password"
}
}
O carregamento deste arquivo em uma instância de IConfiguration
dentro do seu aplicativo é feito em Startup.cs
:
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
A aplicação lê a partir de Configuration
para obter as configurações:
string userName = Configuration.GetSection("AppConfiguration")["UserName"];
string password = Configuration.GetSection("AppConfiguration")["Password"];
Há extensões para essa abordagem para tornar o processo mais robusto, como usar Dependency Injection (DI) para carregar um serviço com esses valores. A abordagem DI fornece um conjunto fortemente tipado de objetos de configuração.
// Assume AppConfiguration is a class representing a strongly-typed version of AppConfiguration section
services.Configure<AppConfiguration>(Configuration.GetSection("AppConfiguration"));
Observação
Para obter uma referência mais detalhada à configuração ASP.NET Core, consulte Configuração no ASP.NET Core.
Injeção de dependência nativa
Um objetivo importante ao criar aplicativos grandes e escaláveis é o acoplamento flexível de componentes e serviços. Injeção de Dependência é uma técnica popular para alcançar esse objetivo, sendo um componente nativo do ASP.NET Core.
Em aplicativos ASP.NET, os desenvolvedores dependem de uma biblioteca de terceiros para implementar a injeção de dependência. Uma dessas bibliotecas é Unity, fornecida pelo Microsoft Patterns & Practices.
Um exemplo de configuração da Injeção de Dependência com Unity é a implementação de IDependencyResolver
que envolve um UnityContainer
:
using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
container.Dispose();
}
}
Crie uma instância do seu UnityContainer
, registre seu serviço e defina o resolvedor de dependência de HttpConfiguration
para a nova instância do UnityResolver
para seu contêiner:
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IProductRepository, ProductRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
// Other Web API configuration not shown.
}
Injete IProductRepository
onde necessário:
public class ProductsController : ApiController
{
private IProductRepository _repository;
public ProductsController(IProductRepository repository)
{
_repository = repository;
}
// Other controller methods not shown.
}
Como a injeção de dependência faz parte do ASP.NET Core, você pode adicionar seu serviço no método ConfigureServices
de Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
// Add application services.
services.AddTransient<IProductRepository, ProductRepository>();
}
O repositório pode ser injetado em qualquer lugar, assim como era com a Unity.
Observação
Para obter mais informações sobre a injeção de dependência, consulte Injeção de dependência.
Servir arquivos estáticos
Uma parte importante do desenvolvimento web é a capacidade de servir ativos estáticos do lado do cliente. Os exemplos mais comuns de arquivos estáticos são HTML, CSS, Javascript e imagens. Esses arquivos precisam ser salvos no local publicado do aplicativo (ou CDN) e referenciados para que possam ser carregados por uma solicitação. Este processo mudou no ASP.NET Core.
No ASP.NET, os arquivos estáticos são armazenados em vários diretórios e referenciados nas exibições.
No ASP.NET Core, os arquivos estáticos são armazenados na "raiz da web" (<raiz de conteúdo (content root)>/wwwroot), a menos que seja configurado de outra forma. Os arquivos são carregados no pipeline de solicitação invocando o método de extensão UseStaticFiles
de Startup.Configure
:
Observação
Se tiver como destino o .NET Framework, instale o pacote NuGet Microsoft.AspNetCore.StaticFiles
.
Por exemplo, um ativo de imagem na pasta wwwroot/images pode ser acessado pelo navegador em um local como http://<app>/images/<imageFileName>
.
Observação
Para obter uma referência mais detalhada ao serviço de arquivos estáticos no ASP.NET Core, consulte Arquivos estáticos.
Cookies de vários valores
Cookies de vários valores não são suportados no ASP.NET Core. Crie um cookie por valor.
Os cookies de autenticação não são compactados no ASP.NET Core
Por razões de segurança, os cookies de autenticação não são comprimidos no ASP.NET Core. Ao usar cookies de autenticação, os desenvolvedores devem minimizar o número de informações de reivindicação incluídas apenas para o necessário para suas necessidades.
Migração parcial de aplicativos
Uma abordagem para a migração parcial de aplicativos é criar um subaplicativo do IIS e mover apenas determinadas rotas do ASP.NET 4.x para o ASP.NET Core, preservando a estrutura de URL do aplicativo. Por exemplo, considere a estrutura de URL do aplicativo a partir do arquivo applicationHost.config:
<sites>
<site name="Default Web Site" id="1" serverAutoStart="true">
<application path="/">
<virtualDirectory path="/" physicalPath="D:\sites\MainSite\" />
</application>
<application path="/api" applicationPool="DefaultAppPool">
<virtualDirectory path="/" physicalPath="D:\sites\netcoreapi" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:80:" />
<binding protocol="https" bindingInformation="*:443:" sslFlags="0" />
</bindings>
</site>
...
</sites>
Estrutura do diretório:
.
├── MainSite
│ ├── ...
│ └── Web.config
└── NetCoreApi
├── ...
└── web.config
[BIND] e Formatadores de Entrada
As versões anteriores do ASP.NET usavam o atributo [Bind]
para proteger contra ataques de superpostagem.
Os formatadores de entrada funcionam de maneira diferente no ASP.NET Core. O atributo [Bind]
já não é concebido para evitar a sobrepostagem quando usado com formatadores de entrada para analisar JSON ou XML. Esses atributos afetam a vinculação de modelo quando a fonte de dados é dados de formulário postados com o tipo de conteúdo x-www-form-urlencoded
.
Para aplicativos que postam informações JSON para controladores e usam JSON Input Formatters para analisar os dados, recomendamos substituir o atributo [Bind]
por um modelo de exibição que corresponda às propriedades definidas pelo atributo [Bind]
.