從 ASP.NET 移轉至 ASP.NET CoreMigrate from ASP.NET to ASP.NET Core

作者:Isaac LevinBy Isaac Levin

這篇文章可作為將 ASP.NET 應用程式移轉至 ASP.NET Core 的參考指南。This article serves as a reference guide for migrating ASP.NET apps to ASP.NET Core.

PrerequisitesPrerequisites

.NET Core SDK 2.2 或更新版本.NET Core SDK 2.2 or later

目標 FrameworkTarget frameworks

ASP.NET Core 專案為開發人員提供了彈性,能以 .NET Core、.NET Framework 或兩者為目標。ASP.NET Core projects offer developers the flexibility of targeting .NET Core, .NET Framework, or both. 請參閱針對伺服器應用程式在 .NET Core 和 .NET Framework 之間進行選擇,判斷哪些目標架構最適合。See Choosing between .NET Core and .NET Framework for server apps to determine which target framework is most appropriate.

以 .NET Framework 為目標時,專案需要參考個別的 NuGet 套件。When targeting .NET Framework, projects need to reference individual NuGet packages.

以 .NET Core 為目標,借助 ASP.NET Core 中繼套件,可讓您消除許多明確的套件參考。Targeting .NET Core allows you to eliminate numerous explicit package references, thanks to the ASP.NET Core metapackage. 在您的專案中安裝 Microsoft.AspNetCore.App 中繼套件:Install the Microsoft.AspNetCore.App metapackage in your project:

<ItemGroup>
   <PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

使用中繼套件時,不使用應用程式部署中繼套件中參考的任何套件。When the metapackage is used, no packages referenced in the metapackage are deployed with the app. .NET Core 執行階段存放區包含這些資產,而且它們會先行編譯以改善效能。The .NET Core Runtime Store includes these assets, and they're precompiled to improve performance. 如需詳細資訊,請參閱 ASP.NET Core 的 Microsoft.AspNetCore.App 中繼套件See Microsoft.AspNetCore.App metapackage for ASP.NET Core for more detail.

專案結構差異Project structure differences

ASP.NET Core 中已簡化 .csproj 檔案格式。The .csproj file format has been simplified in ASP.NET Core. 值得注意的變更包括:Some notable changes include:

  • 檔案不需要明確包含也會被視為專案的一部分。Explicit inclusion of files isn't necessary for them to be considered part of the project. 在處理大型小組時,這會減少 XML 合併衝突的風險。This reduces the risk of XML merge conflicts when working on large teams.

  • 其他專案沒有可改善檔案可讀性之以 GUID 為基礎的參考。There are no GUID-based references to other projects, which improves file readability.

  • 您可以編輯檔案,卻不用在 Visual Studio 中卸載它:The file can be edited without unloading it in Visual Studio:

    在 Visual Studio 2017 中編輯 CSPROJ 操作功能表選項

取代 Global.asax 檔案Global.asax file replacement

ASP.NET Core 導入了啟動應用程式的新機制。ASP.NET Core introduced a new mechanism for bootstrapping an app. ASP.NET 應用程式的進入點是 Global.asax 檔案。The entry point for ASP.NET applications is the Global.asax file. 路由組態和篩選器和區域登錄等工作,會在 Global.asax 檔案中處理。Tasks such as route configuration and filter and area registrations are handled in the Global.asax file.

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

這個方法是以會影響到實作的方式,將應用程式和其部署所在的伺服器結合在一起。This approach couples the application and the server to which it's deployed in a way that interferes with the implementation. 為將它們分開,引進了 OWIN 以提供簡潔的方式,同時使用多個架構。In an effort to decouple, OWIN was introduced to provide a cleaner way to use multiple frameworks together. OWIN 提供的管線只新增所需的模組。OWIN provides a pipeline to add only the modules needed. 裝載環境採用 Startup 函式,設定服務和應用程式的要求管線。The hosting environment takes a Startup function to configure services and the app's request pipeline. Startup 向應用程式註冊一組中介軟體。Startup registers a set of middleware with the application. 對於每項要求,應用程式會使用現有處理常式集合連結清單的標頭指標,呼叫每個中介軟體元件。For each request, the application calls each of the middleware components with the head pointer of a linked list to an existing set of handlers. 每個中介軟體元件都可以在要求處理管線新增一或多個處理常式。Each middleware component can add one or more handlers to the request handling pipeline. 這項作業是透過將參考傳回處理常式所完成,而此處理常式為清單的新標頭。This is accomplished by returning a reference to the handler that's the new head of the list. 每個處理常式都負責記住和叫用清單中的下一個處理常式。Each handler is responsible for remembering and invoking the next handler in the list. 使用 ASP.NET Core,應用程式的進入點是 Startup,對 Global.asax 不會再有相依性。With ASP.NET Core, the entry point to an application is Startup, and you no longer have a dependency on Global.asax. 使用 OWIN 和 .NET Framework 時,請將類似下列的項目當成管線使用:When using OWIN with .NET Framework, use something like the following as a 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);
        }
    }
}

這會設定您的預設路由,並透過 JSON 將 XmlSerialization 設為預設值。This configures your default routes, and defaults to XmlSerialization over Json. 視需要在此管線新增其他中介軟體 (載入服務、組態設定、靜態檔案等等)。Add other Middleware to this pipeline as needed (loading services, configuration settings, static files, etc.).

ASP.NET Core 使用類似的方法,但不依賴 OWIN 處理項目。ASP.NET Core uses a similar approach, but doesn't rely on OWIN to handle the entry. 相反地,這會透過 Program.cs Main 方法完成 (類似主控台應用程式),而 Startup 也是透過該處載入。Instead, that's done through the Program.cs Main method (similar to console applications) and Startup is loaded through there.

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 必須包含 Configure 方法。Startup must include a Configure method. Configure 中將必要的中介軟體新增至管線。In Configure, add the necessary middleware to the pipeline. 在下列範例 (來自從預設的網站範本) 中,擴充方法會使用對下列項目的支援來設定管線:In the following example (from the default web site template), extension methods configure the pipeline with support for:

  • 錯誤頁面Error pages
  • HTTP 嚴格的傳輸安全性HTTP Strict Transport Security
  • HTTP 重新導向 到 HTTPSHTTP redirection to HTTPS
  • ASP.NET Core MVCASP.NET Core MVC
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseMvc();
}

主機與應用程式已分離,這讓您未來可以彈性移至不同的平台。The host and application have been decoupled, which provides the flexibility of moving to a different platform in the future.

注意

如需 ASP.NET Core 啟動與中介軟體更深入的參考,請參閱 ASP.NET Core 中的啟動For a more in-depth reference to ASP.NET Core Startup and Middleware, see Startup in ASP.NET Core

儲存組態Store configurations

ASP.NET 支援儲存設定。ASP.NET supports storing settings. 例如,這些設定是用來支援要部署應用程式的環境。These setting are used, for example, to support the environment to which the applications were deployed. 過去的常見做法是將所有自訂機碼值組儲存在 Web.config 檔案的 <appSettings> 區段中:A common practice was to store all custom key-value pairs in the <appSettings> section of the Web.config file:

<appSettings>
  <add key="UserName" value="User" />
  <add key="Password" value="Password" />
</appSettings>

應用程式會讀取 System.Configuration 命名空間中這些使用 ConfigurationManager.AppSettings 集合的設定:Applications read these settings using the ConfigurationManager.AppSettings collection in the System.Configuration namespace:

string userName = System.Web.Configuration.ConfigurationManager.AppSettings["UserName"];
string password = System.Web.Configuration.ConfigurationManager.AppSettings["Password"];

ASP.NET Core 可將應用程式的組態資料儲存在任何檔案中,將它們當成中介軟體啟動程序的一部分載入。ASP.NET Core can store configuration data for the application in any file and load them as part of middleware bootstrapping. 專案範本中所用的預設檔案是 appsettings.jsonThe default file used in the project templates is appsettings.json:

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "AppConfiguration": {
    "UserName": "UserName",
    "Password": "Password"
  }
}

將此檔案載入應用程式內的 IConfiguration 執行個體,是在 Startup.cs 中完成:Loading this file into an instance of IConfiguration inside your application is done in Startup.cs:

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

public IConfiguration Configuration { get; }

應用程式讀取自 Configuration 以取得設定:The app reads from Configuration to get the settings:

string userName = Configuration.GetSection("AppConfiguration")["UserName"];
string password = Configuration.GetSection("AppConfiguration")["Password"];

此方法有延伸模組可讓處理序更強固,例如使用相依性插入 (DI) 載入具有這些值的服務。There are extensions to this approach to make the process more robust, such as using Dependency Injection (DI) to load a service with these values. DI 方法提供強型別的組態物件集合。The DI approach provides a strongly-typed set of configuration objects.

// Assume AppConfiguration is a class representing a strongly-typed version of AppConfiguration section
services.Configure<AppConfiguration>(Configuration.GetSection("AppConfiguration"));

注意

如需 ASP.NET Core 組態更深入的參考,請參閱 ASP.NET Core 中的組態For a more in-depth reference to ASP.NET Core configuration, see Configuration in ASP.NET Core.

原生相依性插入Native dependency injection

建置可延展的大型應用程式時,鬆散的元件和服務結合程度就是重要的目標。An important goal when building large, scalable applications is the loose coupling of components and services. 相依性插入是達到此目標的常用技巧,它也是 ASP.NET Core 的原生元件。Dependency Injection is a popular technique for achieving this, and it's a native component of ASP.NET Core.

在 ASP.NET 應用程式中,開發人員仰賴協力廠商程式庫來實作插入相依性。In ASP.NET apps, developers rely on a third-party library to implement Dependency Injection. Microsoft 模式和實務提供的 Unity 就是這樣的程式庫。One such library is Unity, provided by Microsoft Patterns & Practices.

使用 Unity 設定相依性插入的範例,是實作包裝 UnityContainerIDependencyResolverAn example of setting up Dependency Injection with Unity is implementing IDependencyResolver that wraps a 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();
    }
}

建立您 UnityContainer 的執行個體、註冊您的服務,以及為容器設定 UnityResolver 新執行個體的 HttpConfiguration 相依性解析程式:Create an instance of your UnityContainer, register your service, and set the dependency resolver of HttpConfiguration to the new instance of UnityResolver for your container:

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.
}

在需要的位置插入 IProductRepositoryInject IProductRepository where needed:

public class ProductsController : ApiController
{
    private IProductRepository _repository;

    public ProductsController(IProductRepository repository)  
    {
        _repository = repository;
    }

    // Other controller methods not shown.
}

因為相依性插入是 ASP.NET Core 的一部分,所以您可以在 Startup.csConfigureServices 方法中新增服務:Because Dependency Injection is part of ASP.NET Core, you can add your service in the ConfigureServices method of Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // Add application services.
    services.AddTransient<IProductRepository, ProductRepository>();
}

存放庫可插入任何位置,就像以前的 Unity 一樣。The repository can be injected anywhere, as was true with Unity.

注意

如需有關相依性插入的詳細資訊,請參閱相依性插入For more information on dependency injection, see Dependency injection.

提供靜態檔案Serve static files

網頁程式開發很重要的一部分是能夠提供靜態的用戶端資產。An important part of web development is the ability to serve static, client-side assets. 最常見的靜態檔案範例包括 HTML、CSS、Javascript 和影像。The most common examples of static files are HTML, CSS, Javascript, and images. 這些檔案需要儲存在應用程式 (或 CDN) 的發佈位置供參考,以便要求可以載入它們。These files need to be saved in the published location of the app (or CDN) and referenced so they can be loaded by a request. 此程序在 ASP.NET Core 中已變更。This process has changed in ASP.NET Core.

在 ASP.NET 中,靜態檔案會儲存在不同目錄中,於檢視中提供參考。In ASP.NET, static files are stored in various directories and referenced in the views.

在 ASP.NET Core 中,除非另有設定,否則靜態檔案會儲存在「web 根目錄」(* < 內容根目錄 > /wwwroot*)中。In ASP.NET Core, static files are stored in the "web root" (<content root>/wwwroot), unless configured otherwise. Startup.Configure 叫用 UseStaticFiles 擴充方法,將檔案載入至要求管線:The files are loaded into the request pipeline by invoking the UseStaticFiles extension method from Startup.Configure:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();
}

注意

如以 .NET Framework 為目標,請安裝 NuGet 套件 Microsoft.AspNetCore.StaticFilesIf targeting .NET Framework, install the NuGet package Microsoft.AspNetCore.StaticFiles.

例如,位在 http://<app>/images/<imageFileName> 等位置的瀏覽器可存取 wwwroot/images 資料夾中的影像資產。For example, an image asset in the wwwroot/images folder is accessible to the browser at a location such as http://<app>/images/<imageFileName>.

注意

如需在 ASP.NET Core 中提供靜態檔案更深入的參考,請參閱靜態檔案For a more in-depth reference to serving static files in ASP.NET Core, see Static files.

多重值 cookieMulti-value cookies

ASP.NET Core 中不支援多重值的 cookieMulti-value cookies aren't supported in ASP.NET Core. 為每個值建立一個 cookie。Create one cookie per value.

部分應用程式遷移Partial app migration

部分應用程式遷移的其中一個方法是建立 IIS 子應用程式,並只將特定路由從 ASP.NET 4.x 移至 ASP.NET Core,同時保留該應用程式的 URL 結構。One approach to partial app migration is to create an IIS sub-application and only move certain routes from ASP.NET 4.x to ASP.NET Core while preserving the URL structure the app. 例如,請考慮來自applicationHost.config檔案的應用程式 URL 結構:For example, consider the URL structure of the app from the applicationHost.config file:

<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>

目錄結構:Directory structure:

.
├── MainSite
│   ├── ...
│   └── Web.config
└── NetCoreApi
    ├── ...
    └── web.config

其他資源Additional resources