從 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 的電子書。
必要條件
目標 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 中卸載它:
取代 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.cs
Main
方法完成 (類似于主控台應用程式) ,並 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 設定相依性插入的範例,是實作包裝 UnityContainer
的 IDependencyResolver
:
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.cs
中 ConfigureServices
新增服務:
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]
檢視模型。