2023年1月17日 星期二

由 ASP.NET Core Web API 專案範本來理解與學習 ASP.NET Cor

由 ASP.NET Core Web API 專案範本來理解與學習 ASP.NET Core

在這個系列文章 由專案範本來理解與學習 ASP.NET Core 架構 中,將會透過 Visual Studio 2022 內建的幾個專案範本所產生的程式碼,了解 ASP.NET Core 7 的運作方式與在這些專案中的差異在哪裡?

對於更多關於 ASP.NET Core 7 的說明內容,可以參考 ASP.NET Core 基本概念的概觀

在上一篇文章中,使用 ASP.NET Core 空白範本建立一個專案,並且從這個專案原始碼中,了解到 ASP.NET Core 的運作方式,首先使用 WebApplication.CreateBuilder 將會建立一個 WebApplicationBuilder 執行個體,接著執行 var app = builder.Build(); ,這樣就會產生一個型別為 WebApplication 物件,最後執行 app.Run() ,這樣這個 Web 應用程式就會啟動了,可以接收來自於使用者的請求。

在這篇文章中,將會建立同樣名稱的專案,不過將會採用 ASP.NET Core Web API 類型的專案範本,並且來比較這個 Web API 類型的專案與空白類型的專案有何不同。

首先先來建立一個 ASP.NET Core Web API 專案,請依照底下說明來建立這個專案

  • 打開 Visual Studio 2022 IDE 應用程式

  • 從 [Visual Studio 2022] 對話窗中,點選右下方的 [建立新的專案] 按鈕

  • 在 [建立新專案] 對話窗右半部

    • 切換 [所有語言 (L)] 下拉選單控制項為 [C#]
    • 切換 [所有專案類型 (T)] 下拉選單控制項為 [Web]
  • 在中間的專案範本清單中,找到並且點選 [ASP.NET Core Web API] 專案範本選項

    Visual Studio 2022 建立新專案

  • 點選右下角的 [下一步] 按鈕

  • 在 [設定新的專案] 對話窗

  • 找到 [專案名稱] 欄位,輸入 ASPNETCore7 作為專案名稱 Visual Studio 2022 設定新的專案

  • 點選右下角的 [下一步] 按鈕

  • 現在將會看到 [其他資訊] 對話窗

  • 找到 [使用控制器 (取消勾選已使用最低 API)] 檢查盒,注意,一定需要勾選這個選項,因為,在此先來觀察傳統的使用 API Controller 建立的專案長成甚麼樣子。 Visual Studio 2022 其他資訊

  • 請點選右下角的 [建立] 按鈕

完成專案創建之後,將會看到 Visual Studio 2022 將這個新專案開啟,從 [方案總管] 視窗內,可以看到這個專案內所建立的檔案

首先,按下 F5 看看這個專案的執行結果會呈現甚麼樣貌

在 Visual Studio 2022 應用程式的上方,將會看到一個綠色三角形,請點選該綠色三角形來執行這個專案。

一旦專案編譯、建置完成後,瀏覽器將會出現這個網頁

在網頁上看出,並沒有如同上一個空白專案會顯示出 Hello World! 這個文字,而是出現一個標題為 [Swagger UI] 的網頁內容,而更多關於 Swagger 的內容,可以參考 Swashbuckle 與 ASP.NET Core 使用者入門

從專案內容來理解為什麼會有這樣的執行結果

在方案總管視窗內,將會看到這個 Web API 專案所產生出來的內容,將會多了一個 [Controllers] 資料夾,該資料夾內會有一個 [WeatherForecastController.cs] 檔案;另外,在專案的根目錄下,也產生了一個 [WeatherForecast.cs] 檔案。

也許會覺得很奇怪,只是多的這兩個檔案,就可以讓原本單純的 ASP.NET Core 空白專案,變成一個 ASP.NET Core Web API 專案,而且出來的畫面也會有所不同,接下來就來探討究竟發生了甚麼事情。

對於 [Properties] 資料夾內的 [launchSettings.json] 檔案 與 [appsettings.json] 這兩個檔案,其實與空白專案內的用法與意義是相同的。

不過,需要先來看一下 空白 與 Web API 這兩個專案的專案定義宣告檔案,也就是 [.csproj]。

可以透過直接點擊方案總管內的專案名稱節點,也就是 [ASPNETCore7] 或者 使用檔案總管找到 [ASPNETCore7.csproj] 這個檔案,便可以看到關於這個專案的定義宣告檔案。

底下的將會是空白專案的 [.csproj] 檔案內容

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

</Project>

這裡可以看到,這個 空白 專案,將會採用 [Microsoft.NET.Sdk.Web] 這個 SDK,並且將會採用 .NET7 作為目的框架。

底下的將會是 Web API 專案的 [.csproj] 檔案內容

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.1" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

</Project>

這個 Web API 專案,同樣的採用 [Microsoft.NET.Sdk.Web] 這個 SDK,與採用 .NET7 作為目的框架。

從 Web API 專案的 .csproj 檔案內,可以看到這個專案加入了兩個 NuGet 套件 [Microsoft.AspNetCore.OpenApi] 、 [Swashbuckle.AspNetCore] ,這兩個套件將會提供剛剛看到的 Swagger UI 網頁內容。

了解完第一個差異點,接下來要來比較程式進入點差異,也就是這個 Web 網站的核心程式碼,這些程式碼將會在 [Program.cs] 檔案內,其內容如下:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

從 Web API 專案內產生的 [Program.cs] 檔案,同樣的使用 var builder = WebApplication.CreateBuilder(args); 敘述來建立一個 [WebApplicationBuilder] 型別物件到 [builder] 變數內。

在 空白 專案內,對於這個 builder 並沒有做其他的呼叫,僅呼叫 builder.Build() 方法,取得一個型別為 [WebApplication] 物件到 [app] 變數內。

不過,在 Web API 專案內,將會透過 [WebApplicationBuilder] 類別提供的 [Services] 屬性,進行會使用到的服務註冊到相依性注入容器 (IoC 容器) 內,如此,其他的服務便可以透過建構式注入的方式,來取得這些宣告在 DI Dependency Injection 容器內的服務,進而做到程式碼間鬆散耦合設計需求。

第一個 [builder] 物件呼叫的方法將會是 builder.Services.AddControllers(); ,這裡將會是將控制器的服務加入至指定的 IServiceCollection 。 這個方法不會註冊用於檢視或頁面的服務。

builder.Services.AddEndpointsApiExplorer() : 讓 Swagger 產生關於 Minimal APIs 資訊

builder.Services.AddSwaggerGen() : 提供 API 資訊與描述,可以顯示在 Swagger 頁面上

接下來就是相關中介軟體 Middleware 的宣告

if (app.Environment.IsDevelopment()){ ... } : 這裡將會使用 Environment 環境物件來查看,現在是否為開發環境下,若為真,則可以使用 Swagger 的 Web 網頁

app.UseSwagger() : 新增 Swagger 中介軟體

app.UseSwaggerUI() : 會啟用 Swagger 會使用到的靜態檔案中介軟體

app.UseHttpsRedirection() : 將 HTTP 要求重新導向至 HTTPS

app.UseAuthorization() : 授權中介軟可授權使用者存取安全資源

app.MapControllers() : 對應屬性路由控制器

app.Run() : 執行應用程式並封鎖呼叫執行緒,直到主機關閉為止

以上的內將會是採用 [使用控制器 (取消勾選已使用最低 API)] 模式來建立這個 Web API 專案,不過,若是在建立 Web API 專案過程中,在 [其他資訊] 視窗下方找到 [使用控制器 (取消勾選已使用最低 API)] 檢查盒,不要勾選這個選項

若想要觀察採用 [最小 API] 方式所建立的 Web API 專案長成甚麼樣子,請重新建立一個 Web API 專案,在 [其他資訊] 視窗下方找到 [使用控制器 (取消勾選已使用最低 API)] 檢查盒,不要勾選這個選項,這樣就會使用 [最小 API] 方式來建立 Web API 專案。

底下螢幕截圖,將會是採用 [最小 API] 模式建立的 Web API 專案所有檔案內容,原則上與 空白 專案的檔案幾乎是相同的。

不過,當打開 [Program.cs] 檔案後,會看底下內容

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();

app.Run();

internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

在此,可以比較有使用 控制器 的專案,其實就可以知道,就是把所有的程式碼(控制器、資料模型等等),全部都寫在同一個類別檔案內。

最後,在 [Controllers] 資料夾內有 [WeatherForecastController.cs] 檔案,這個檔案內容如下:

using Microsoft.AspNetCore.Mvc;

namespace ASPNETCore7.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

這個檔案內有個 [WeatherForecastController] 控制器類別,透過 [ApiController] 屬性標示,註明這是個 API 控制器

其中這個控制器內使用到的類別 WeatherForecast ,將會定義在 [WeatherForecast.cs] 檔案內 












2023年1月16日 星期一

由 ASP.NET Core 空白專案範本來理解與學習 ASP.NET Core

在這個系列文章 由專案範本來理解與學習 ASP.NET Core 架構 中,將會透過 Visual Studio 2022 內建的幾個專案範本所產生的程式碼,了解 ASP.NET Core 7 的運作方式與在這些專案中的差異在哪裡?

對於更多關於 ASP.NET Core 7 的說明內容,可以參考 ASP.NET Core 基本概念的概觀

首先先來建立一個 ASP.NET Core 空白專案,請依照底下說明來建立這個專案

  • 打開 Visual Studio 2022 IDE 應用程式

  • 從 [Visual Studio 2022] 對話窗中,點選右下方的 [建立新的專案] 按鈕

  • 在 [建立新專案] 對話窗右半部

    • 切換 [所有語言 (L)] 下拉選單控制項為 [C#]
    • 切換 [所有專案類型 (T)] 下拉選單控制項為 [Web]
  • 在中間的專案範本清單中,找到並且點選 [空的 ASP.NET Core] 專案範本選項

    Visual Studio 2022 建立新專案

  • 點選右下角的 [下一步] 按鈕

  • 在 [設定新的專案] 對話窗

  • 找到 [專案名稱] 欄位,輸入 ASPNETCore7 作為專案名稱 Visual Studio 2022 設定新的專案

  • 點選右下角的 [下一步] 按鈕

  • 現在將會看到 [其他資訊] 對話窗 Visual Studio 2022 其他資訊

  • 請點選右下角的 [建立] 按鈕

完成專案創建之後,將會看到 Visual Studio 2022 將這個新專案開啟,從 [方案總管] 視窗內,可以看到這個專案內所建立的檔案

首先,按下 F5 看看這個專案的執行結果會呈現甚麼樣貌

在 Visual Studio 2022 應用程式的上方,將會看到一個綠色三角形,請點選該綠色三角形右方的 白色 向下白色三角型,此時,將會彈出一個子功能表,從這裡可以選取要使用哪種方式來執行這個專案。

可以看到,預設會採用 HTTPS 方式來執行這個 Web 專案,當然也可以選擇第一個 http 項目,表示使用 HTTP 方式來執行這個專案,不論是哪個,都將會是採用 ASP.NET Core 的 Kestrel 網頁伺服器 來啟動與執行這個網站,當然,也可以選擇 [IIS Express] 這個選項,透過 Windows 電腦中的 IIS Express 服務來運作這個網站。

在此,將會使用預設 https 方式來啟動此專案

一旦專案編譯、建置完成後,瀏覽器將會出現這個網頁

從上面剛剛提到的彈出功能表中,倒數第四項目,是可以選擇要採用哪種瀏覽器來執行這個網站網頁,因為沒有特別設定,從螢幕截圖可以看出,將會採用 Google Chrome 瀏覽器來開啟這個 ASP.NET Core 空白範本專案

在網頁上看出,這個網頁將採用 HTTPS 方式來連線到 Kestrel 網站服務,並且指定使用 7234 通訊埠來通訊;而從網頁上可以看到,僅有 Hello World! 這個文字。

從專案內容來理解為什麼會有這樣的執行結果

首先要看看 [Properties] 資料夾內的 [launchSettings.json] 檔案,這是一個 JSON 格式內容。

launchSettings.json 是用於制定 在 ASP.NET Core 中使用多個環境 運作的設定檔案

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:51976",
      "sslPort": 44358
    }
  },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5242",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:7234;http://localhost:5242",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

在這個 [iisSettings] 節點內,定義了 IIS Express 運作屬性,而在 [profiles] 內則會宣告可以有幾種啟動這個 Web 網站的方式,而且每個啟動方式可以指定不同參數

對於剛剛選擇的 https 執行模式,其啟動參數定義如下,將可以使用 https://localhost:7234 或者 http://localhost:5242 方式來連上這個專案網站,其中,因為 "ASPNETCORE_ENVIRONMENT": "Development" 設定值,將會強制環境參數為 Development,此時,將會影響到這個網站內的運作行為。

"https": {
  "commandName": "Project",
  "dotnetRunMessages": true,
  "launchBrowser": true,
  "applicationUrl": "https://localhost:7234;http://localhost:5242",
  "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development"
  }
}

接下來就是第二個檔案 appsettings.json ,這個檔案也是一個 JSON 格式內容,其預設檔案內容如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

在 ASP.NET Core 7 中,將會提供 ASP.NET Core 的設定 功能,透過 ASP.NET Core 的設定 豐富能力,可以讓整個專案在設計與開發上更加有彈性。

最後一個就是這個專案的程式進入點,也就是這個 Web 網站的核心程式碼,這些程式碼將會在 [Program.cs] 檔案內,其內容如下:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

WebApplication.CreateBuilder 將會使用預先設定的預設值,建立一個 WebApplicationBuilder 執行個體,而這個專案可以透過型別為 WebApplicationBuilder 的 builder 物件,進行操作,例如,可以透過這個物件提供的 WebApplicationBuilder.Services 屬性 來進行相依性注入服務容器 或 稱之為 IoC 容器的相關服務註冊之用。

而對於 Configuration 屬性 將會要撰寫之應用程式的組態提供者集合

Environment 屬性 將 提供應用程式正在執行之 Web 主控環境的相關資訊

Host 屬性 將 無法修改,因為此唯讀屬性,若要在組態之後建置,請呼叫 Build() 方法

Logging 屬性 將 要撰寫之應用程式的記錄提供者集合

WebHost 屬性 將 用於設定伺服器特定屬性

因為這是一個相當簡單的 Web 專案,也就是空白專案,因此,將不會到 物件做任何操作,而是執行 var app = builder.Build(); ,這樣就會產生一個型別為 WebApplication 物件,而將會透過 app 這個本地變數來存取。

對於 WebApplication 類別 的物件,將會用來設定 HTTP 管線和路由的 Web 應用程式

app.MapGet 這個方法,將是提供 最小 API 模式來設計,並且透過這個方法可以宣告網站路由,從這個範例程式碼 app.MapGet("/", () => "Hello World!"); 代表宣告一個網站首頁路由,一旦導航到個 "/" 路由,將會顯示 Hello World! 文字在網頁上。

到現在為止,應該可以知道,為什麼開啟這個網站,就會出現這段文字了吧!

最後一行程式碼 app.Run() 也就是執行應用程式並封鎖呼叫執行緒,直到主機關閉為止,此時,這個網站程式已經開始運作,可以讓使用者透過瀏覽器來進行各種互動;不過,因為這是一個相當精簡的專案,並沒有提供其他額外路由與功能。