從 ASP.NET 移轉至 ASP.NET Core

作者:Isaac Levin

這篇文章可作為將 ASP.NET 應用程式移轉至 ASP.NET Core 的參考指南。

.NET Upgrade Assistant是一種命令列工具,可協助將 ASP.NET 移轉至 ASP.NET Core。 如需詳細資訊,請參閱 .NET 升級小幫手 概觀和 使用 .NET Upgrade Assistant 將 ASP.NET MVC 應用程式升級至 .NET 6

如需完整的移植指南,請參閱將 現有 ASP.NET 應用程式移植到 .NET Core 的電子書。

必要條件

.NET Core SDK 2.2 或更新版本

目標 Framework

ASP.NET Core 專案為開發人員提供了彈性,能以 .NET Core、.NET Framework 或兩者為目標。 請參閱針對伺服器應用程式在 .NET Core 和 .NET Framework 之間進行選擇,判斷哪些目標架構最適合。

以 .NET Framework 為目標時,專案需要參考個別的 NuGet 套件。

以 .NET Core 為目標,借助 ASP.NET Core 中繼套件,可讓您消除許多明確的套件參考。 在您的專案中安裝 Microsoft.AspNetCore.App 中繼套件:

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

使用中繼套件時,不使用應用程式部署中繼套件中參考的任何套件。 .NET Core 執行階段存放區包含這些資產,而且它們會先行編譯以改善效能。 如需詳細資訊,請參閱 ASP.NET Core 的 Microsoft.AspNetCore.App 中繼套件

專案結構差異

ASP.NET .csproj Core 已簡化檔案格式。 值得注意的變更包括:

  • 檔案不需要明確包含也會被視為專案的一部分。 在處理大型小組時,這會減少 XML 合併衝突的風險。

  • 其他專案沒有可改善檔案可讀性之以 GUID 為基礎的參考。

  • 您可以編輯檔案,卻不用在 Visual Studio 中卸載它:

    Edit CSPROJ context menu option in Visual Studio 2017

取代 Global.asax 檔案

ASP.NET Core 導入了啟動應用程式的新機制。 ASP.NET 應用程式的進入點是 Global.asax 檔案。 路由組態和篩選器和區域登錄等工作,會在 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);
    }
}

這個方法是以會影響到實作的方式,將應用程式和其部署所在的伺服器結合在一起。 為將它們分開,引進了 OWIN 以提供簡潔的方式,同時使用多個架構。 OWIN 提供的管線只新增所需的模組。 裝載環境採用 Startup 函式,設定服務和應用程式的要求管線。 Startup 向應用程式註冊一組中介軟體。 對於每項要求,應用程式會使用現有處理常式集合連結清單的標頭指標,呼叫每個中介軟體元件。 每個中介軟體元件都可以在要求處理管線新增一或多個處理常式。 這項作業是透過將參考傳回處理常式所完成,而此處理常式為清單的新標頭。 每個處理常式都負責記住和叫用清單中的下一個處理常式。 使用 ASP.NET Core,應用程式的進入點是 Startup,對 Global.asax 不會再有相依性。 使用 OWIN 和 .NET Framework 時,請將類似下列的項目當成管線使用:

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 設為預設值。 視需要在此管線新增其他中介軟體 (載入服務、組態設定、靜態檔案等等)。

ASP.NET Core 使用類似的方法,但不依賴 OWIN 處理項目。 相反地,這是透過 Program.csMain 方法完成 (類似于主控台應用程式) ,並 Startup 透過該處載入。

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 方法。 在 Configure 中將必要的中介軟體新增至管線。 在下列範例 (來自從預設的網站範本) 中,擴充方法會使用對下列項目的支援來設定管線:

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

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

主機與應用程式已分離,這讓您未來可以彈性移至不同的平台。

注意

如需 ASP.NET Core 啟動與中介軟體更深入的參考,請參閱 ASP.NET Core 中的啟動

儲存組態

ASP.NET 支援儲存設定。 例如,這些設定是用來支援要部署應用程式的環境。 過去的常見做法是將所有自訂機碼值組儲存在 Web.config 檔案的 <appSettings> 區段中:

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

應用程式會讀取 System.Configuration 命名空間中這些使用 ConfigurationManager.AppSettings 集合的設定:

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

ASP.NET Core 可將應用程式的組態資料儲存在任何檔案中,將它們當成中介軟體啟動程序的一部分載入。 專案範本中使用的預設檔案為 appsettings.json

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

將這個檔案載入應用程式內的 實例 IConfiguration ,是在 中 Startup.cs 完成:

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

public IConfiguration Configuration { get; }

應用程式讀取自 Configuration 以取得設定:

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

此方法有延伸模組可讓處理序更強固,例如使用相依性插入 (DI) 載入具有這些值的服務。 DI 方法提供強型別的組態物件集合。

// 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 中的組態

原生相依性插入

建置可延展的大型應用程式時,鬆散的元件和服務結合程度就是重要的目標。 相依性插入是達到此目標的常用技巧,它也是 ASP.NET Core 的原生元件。

在 ASP.NET 應用程式中,開發人員仰賴協力廠商程式庫來實作插入相依性。 其中一個這類程式庫是 Unity,由 Microsoft Patterns & Practices 提供。

使用 Unity 設定相依性插入的範例,是實作包裝 UnityContainerIDependencyResolver

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 相依性解析程式:

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

在需要的位置插入 IProductRepository

public class ProductsController : ApiController
{
    private IProductRepository _repository;

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

    // Other controller methods not shown.
}

因為相依性插入是 ASP.NET Core 的一部分,所以您可以在 的 方法 Startup.csConfigureServices 新增服務:

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

存放庫可插入任何位置,就像以前的 Unity 一樣。

注意

如需有關相依性插入的詳細資訊,請參閱相依性插入

提供靜態檔案

網頁程式開發很重要的一部分是能夠提供靜態的用戶端資產。 最常見的靜態檔案範例包括 HTML、CSS、Javascript 和影像。 這些檔案需要儲存在應用程式 (或 CDN) 的發佈位置供參考,以便要求可以載入它們。 此程序在 ASP.NET Core 中已變更。

在 ASP.NET 中,靜態檔案會儲存在不同目錄中,於檢視中提供參考。

在 ASP.NET Core 中,除非另有設定,否則靜態檔案會儲存在「web 根目錄」 (< 內容根 > /wwwroot) 。 從 Startup.Configure 叫用 UseStaticFiles 擴充方法,將檔案載入至要求管線:

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

注意

如以 .NET Framework 為目標,請安裝 NuGet 套件 Microsoft.AspNetCore.StaticFiles

例如,位在 http://<app>/images/<imageFileName> 等位置的瀏覽器可存取 wwwroot/images 資料夾中的影像資產。

注意

如需在 ASP.NET Core 中提供靜態檔案更深入的參考,請參閱靜態檔案

多重值 cookie s

ASP.NET Core 不支援多重值 cookie。 為每個值建立一個 cookie 。

驗證 cookie 不會在 ASP.NET Core 中壓縮

基於安全性考慮,驗證 cookie 不會壓縮在 ASP.NET Core 中。 使用驗證 cookie 時,開發人員應該盡可能減少其需求所需的宣告資訊數目。

部分應用程式移轉

部分應用程式移轉的其中一種方法是建立 IIS 子應用程式,並只將特定路由從 ASP.NET 4.x 移至 ASP.NET Core,同時保留應用程式的 URL 結構。 例如,請考慮 applicationHost.config檔案中 應用程式的 URL 結構:

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

目錄結構:

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

[BIND] 和輸入格式器

舊版 ASP.NET 使用 [Bind] 屬性來防範超載攻擊。 輸入格式器 在 ASP.NET Core 中的運作方式不同。 屬性 [Bind] 已不再設計為在搭配輸入格式器使用以剖析 JS ON 或 XML 時防止過度發佈。 當資料來源是以內容類型張貼 x-www-form-urlencoded 的表單資料時,這些屬性會影響模型系結。

對於將 ON 資訊張貼 JS 至控制器並使用 JS ON 輸入格式器剖析資料的應用程式,建議將 屬性取代 [Bind] 為符合 屬性所定義屬性的 [Bind] 檢視模型。

其他資源