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
文件可以看到:
對於應用程序開發來說,日志記錄是非常重要的一項功能,無論是在開發中、還是部署后的使用中,日志都會幫助我們發現、記錄問題,我們可以根據日志來定位、復現並修復問題,所以盡可能的早的將日志服務添加到應用程序中是很有必要的,在下一章中我們將會介紹如何配置日志服務。