ASP.NET Core Web API 教程
本系列文章主要參考了《Ultimate ASP.NET Core 3 Web API》一書,我對原文進行了翻譯,同時適當刪減、修改了一部分內容。
對於某些概念和原理,原書和本文中都沒有進行詳細描述,如果一一詳細介紹,內容就顯得臃腫且混亂,我個人是先對原書進行了通讀,理解主要內容,然後再具體搜尋瞭解其中不明白或者感興趣的概念和知識點。
由於我的技術水平和英文水平都有限,且主要是為了方便以後自己檢視回顧,所以有錯誤之處,還請各位批評指正。
第一章 專案配置
本章內容簡介:Configuration 在開發過程中至關重要,我們首先需要了解如何配置我們的應用程式。在之前的 .NET Framework 專案中,我們一般是通過 web.config 檔案來完成對應用程式的配置,而在 .NET Core 中,我們不再使用該檔案,而是使用 .NET Core 內建的 Configuration 框架。本文將介紹 Startup 類中的配置方法以及如何通過這些方法來設定應用程式。除此之外,還將介紹如何註冊服務以及如何通過擴充套件方法來實現註冊。
1. 建立新專案
開啟 Visual Studio 2019,點選 Create a new project ,然後選擇 ASP.NET Core Web API:
填寫專案名稱並選擇專案路徑:
然後選擇目標框架,並點選 Create :
2. launchSettings.json 檔案
專案建立成功後,在解決方案的 Properties 節點下可以看到 launchSettings.json 檔案:
這個檔案決定了 ASP.NET Core 應用程式的啟動行為,可以看到,它包含了 IIS 和自託管應用(self-hosted)Kestrel 的啟動設定的相關配置。
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:59126",
"sslPort": 44389
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"CompanyEmployees": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
由於我們開發的是 Web API 專案,因此我們並不需要使用瀏覽器像檢視 Web 專案一樣來檢視 API,我們之後會通過 Postman (以後會介紹)來呼叫並檢視 API 的輸出。而為了阻止應用程式啟動時自動開啟瀏覽器,需要將 launchBrowser
屬性值設定為 false
:
"launchBrowser": false
在建立專案時,如果勾選了 Configure for HTTPS 的核取方塊,那麼在 applicationUrl
節點中就會有兩個 URL,一個用於 HTTP,另一個用於 HTTPS。
注意:此 HTTPS 配置項盡在本地環境中有效,當應用程式正式部署後,必需配置真實有效的證書。
在本地開發應用程式時,還有一個很重要的屬性:launchUrl
,該屬性定義了應用程式啟動時預設導航到的 URL。如果要讓該屬性生效,就需要將 launchBrowser
屬性值設定為 true
。例如,如果將 launchUrl
屬性值設定為 weatherforecast
,則應用程式啟動時會重定向到 https://localhost:5001/weatherforecast。
3. Program.cs 和 Startup.cs
ASP.NET Core 應用程式本質是一個控制檯應用程式,它通過建立 web 伺服器來託管應用程式並監聽傳入的HTTP請求,然後返回響應,所以程式的入口還是 Program
類的 Main()
方法,ASP.NET Core Web API 應用程式中的 Program
如下:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
關於 Host 的啟動過程,可以參考:以後補充。
CreateDefaultBuilder(args)
方法設定專案的預設配置檔案和變數,以及日誌提供程式。在應用啟動過程的早期配置好日誌提供程式意味著可以使用日誌記錄發生在啟動過程中的問題。
之後,呼叫 webBuilder.UseStartup<Startup>()
方法來初始化 Startup
類,Startup
類在 ASP.NET Core Web API 專案中是強制要求的類,需要在該類中配置應用程式需要的嵌入式或者自定義的服務,程式碼如下:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
其中,正如方法名字所示,ConfigureServices()
方法用於配置應用程式使用的服務,而服務就是為應用程式新增功能的一些可重用的程式碼。在 Configure()
方法中將會嚮應用程式的請求管道新增不同的中介軟體。
由於較大的應用程式可能包含許多不同的服務,因此在 ConfigureServices()
方法中可能會出現大量的程式碼,這樣會導致程式碼看起來混亂臃腫、可讀性差。為了提高程式碼可讀性,我們可以將新增服務的程式碼分離成一個個的擴充套件方法。
4. 擴充套件方法和 CORS 配置
擴充套件方法本質上是一種靜態方法。它與其他靜態方法的不同之處在於,它接受 this
作為第一個引數,this
表示使用該擴充套件方法的物件的資料型別。
擴充套件方法必需定義在靜態類中,它擴充套件了.NET 中型別的行為。一旦定義了擴充套件方法,就可以在同一型別的物件上多次鏈式呼叫它。
接下來開始寫程式碼,首先在專案中建立一個新的資料夾:Extensions
然後在該資料夾中建立一個類:ServiceExtensions
,並將這個類改為靜態類,程式碼如下:
public static class ServiceExtensions
{
}
接下來就開始實現一個具體的功能,這樣就能看到應該如何使用靜態類。我們要做的第一件事就是在應用程式中配置 CORS。CORS ( Cross-Origin Resource Sharing,跨資源共享 ) 是一種向來自不同域的應用程式授予或者限制訪問許可權的機制。
如果我們想從不同的域嚮應用程式傳送請求,那就必須配置 CORS。所以接下來就在 ServiceExtensions
類中新增一個擴充套件方法來允許將來自所有域的所有請求傳送到我們的 API:
public static void ConfigureCors(this IServiceCollection services) =>
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
我們這裡暫時使用基本的 CORS 策略設定,因為目前來說允許所有來源 ( origin )、所有型別的方法、所有 header 是可以接受的。但是如果是生產環境,那我們應該儘可能的將策略設定的更嚴格。
當有需要的時候,我們可以使用 WithOrigins("https://example.com")
方法來限制請求只能來自某個具體源,而不是使用 AllowAnyOrigin()
方法允許來自所有源的請求。同樣,可以使用 WithMethods("POST","GET")
方法來限制請求只能是特定的 HTTP 方法,而不是使用 AllowAnyMethods()
方法允許所有型別的 HTTP 方法。另外,可以使用 WithHeaders("accept","content-type")
方法來限制請求包含特定的 headers。
5. IIS 配置
ASP.NET Core 應用預設是自託管(self hosted),當然我們也可以通過配置 IIS 整合來幫助我們將應用使用 IIS 託管,可以通過新增以下擴充套件方法來實現:
public static void ConfigureIISIntegration(this IServiceCollection services) =>
services.Configure<IISOptions>(options =>
{
});
目前我們使用預設配置就可以,所以在上述程式碼中沒有初始化 options
的任何屬性。如果想修改某些配置,可以參考官方文件:
至此,我們已經編寫了用於支援 CORS 和 IIS 整合的擴充套件方法,接下來就在 Startup
類中進行呼叫,注意引用名稱空間 using CompanyEmployees.Extensions
,ConfigureService()
程式碼如下:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//custom extension methods
services.ConfigureCors();
services.ConfigureIISIntegration();
services.AddControllers();
}
對於直接在 ConfigureServices()
方法中新增一系列程式碼來說,使用擴充套件方法後可以使程式碼更簡潔,可讀性更高。另外擴充套件方法的命名要儘可能準確、明瞭。
我們已經成功的將 CORS 和 IIS 配置新增到應用程式的服務容器中,但是還沒有真正用到這些服務,所以還需要在 Configure()
方法中新增一些使用服務的程式碼:
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
//custom pipeline start
app.UseStaticFiles();
app.UseCors("CorsPolicy");
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.All
});
//custom pipeline end
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
其中,
UseForwardedHeaders()
:將轉發的 header 應用於當前請求上的匹配的欄位。按照約定, HTTP 代理以眾所周知的 HTTP header 從客戶端轉發訊息。該中介軟體讀取這些 header 並填充 HttpContext
上的相關欄位。
UseStaticFiles()
:對當前請求的路徑啟用靜態檔案服務,意思就是可以通過路徑訪問當前目錄的檔案。如果沒有設定靜態檔案目錄的路徑,則預設使用 wwwroot 目錄。
UseCors()
:將 CORS 中介軟體新增到應用程式的請求管道中以允許跨域請求。
6. Startup 類中的其它程式碼
ConfigureServices()
方法中,
AddControllers()
:將控制器的服務新增到服務集合中。AddMvc()
方法也可以將控制器新增到服務集合中,但它除了控制器外,還會將檢視和頁面新增到服務集合中。我們的專案是 Web API 專案,所以只需要控制器就可以。
Configure()
方法中,
UseRouting()
:將路由中介軟體新增到請求管道中。
UseAuthorization()
:將授權中介軟體新增到請求管道中。
UseEndpoints()
:為控制器的 Action 新增終結點並將終結點新增路由中。
中介軟體的順序非常重要,以後會單獨寫一篇關於中介軟體的文章。
7. 基於環境的設定
在開發應用程式時,我們使用 開發 (development) 環境,當我們釋出了應用程式之後就需要使用 生產 (production) 環境。開發環境和生產環境對應不同的 URLs、埠、連線字串、密碼等其它敏感資訊。所以我們需要根據環境來區分配置,這在 .NET Core 中是很容易實現的。
當我們建立一個專案後,可以在專案的根目錄中看到 appsettings.json
檔案,這就我們主要的配置檔案,點選檔案前面的箭頭可以看到一個 appsettings.Development.json
檔案。如果在系統的檔案資源管理器中開啟專案目錄,可以看到這是兩個不同的檔案,但是在 Visual Studio 中,這兩個配置檔案被關聯在了一起。
appsettings.{EnvironmentSuffix}.json
是用於特定環境時的配置檔案,可以覆蓋 appsettings.json
檔案中的配置。如果appsettings.{EnvironmentSuffix}.json
檔案中存在與 appsettings.json
檔案同名的鍵值對,則會覆蓋鍵值對的值。另外我們還可以自定義特定的環境,例如,對於生產環境,我們可以新增另一個檔案: appsettings.Production.json
:
appsettings.Production.json
檔案中應該包含用於生產環境的配置項。
為了設定應用程式執行時的環境,我們需要設定 ASPNETCORE_ENVIRONMENT
環境變數。例如,如果想讓應用程式執行在生產環境中,就需要在部署的機器上將上述環境變數的值修改為 Production
。在 Windows 環境中,可以通過輸入命令: set ASPNETCORE_ENVIRONMENT=Production
來實現。在 Linux 環境中,可以通過輸入命令: export ASPNET_CORE_ENVIRONMENT=Production
來實現。
ASP.NET Core 應用程式通過上述環境變數的值來決定使用哪個 appsettings.json
檔案,例如在生產環境中,將會使用 appsettings.Production.json
檔案。預設情況下 ASPNETCORE_ENVIRONMENT
變數的值是 Development
,開啟 launchSettings.json
檔案可以看到:
對於應用程式開發來說,日誌記錄是非常重要的一項功能,無論是在開發中、還是部署後的使用中,日誌都會幫助我們發現、記錄問題,我們可以根據日誌來定位、復現並修復問題,所以儘可能的早的將日誌服務新增到應用程式中是很有必要的,在下一章中我們將會介紹如何配置日誌服務。