ASP.NET Core Web API 教程 - Project Configuration

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:

image-20210903091248728

填寫項目名稱並選擇項目路徑:

image-20210903091326072

然後選擇目標框架,並點擊 Create :

image-20210916135618075


2. launchSettings.json 文件

項目創建成功後,在解決方案的 Properties 節點下可以看到 launchSettings.json 文件:

image-20210903091855750

這個文件決定了 ASP.NET Core 應用程式的啟動行為,可以看到,它包含了 IIS 和自託管應用(self-hosted)Kestrel 的啟動設置的相關配置。

{
  "$schema": "//json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "//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": "//localhost:5001;//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,則應用程式啟動時會重定向到 //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

image-20210915135043050

然後在該文件夾中創建一個類: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("//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 的任何屬性。如果想修改某些配置,可以參考官方文檔:

image-20210916094920266

至此,我們已經編寫了用於支援 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 中,這兩個配置文件被關聯在了一起。

image-20210916131620615

appsettings.{EnvironmentSuffix}.json 是用於特定環境時的配置文件,可以覆蓋 appsettings.json 文件中的配置。如果appsettings.{EnvironmentSuffix}.json 文件中存在與 appsettings.json 文件同名的鍵值對,則會覆蓋鍵值對的值。另外我們還可以自定義特定的環境,例如,對於生產環境,我們可以添加另一個文件: appsettings.Production.json:

image-20210916131945517

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 文件可以看到:

image-20210916144600843

對於應用程式開發來說,日誌記錄是非常重要的一項功能,無論是在開發中、還是部署後的使用中,日誌都會幫助我們發現、記錄問題,我們可以根據日誌來定位、復現並修復問題,所以儘可能的早的將日誌服務添加到應用程式中是很有必要的,在下一章中我們將會介紹如何配置日誌服務。