體驗全新 ASP.NET Core 6.0 專案範本與 C# 10 語言特性 | The Will Will Web

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

體驗全新 ASP.NET Core 6.0 專案範本與 C# 10 語言特性

我的 ASP.NET Core 6 開發實戰:從入門到進階 課程將在 2021/11/13 開始,就在 .NET 6.0 推出後 4 天。由於 .NET 6.0 與 C# 10 即將推出,全新的 Top-level statements 語言特性,可以大幅簡化 .NET 應用程式的啟動程式碼,這個變化自然也會影響到 ASP.NET Core 6.0 的啟動方式,許多 .NET Core 的老手看到全新的 Hosting Model (裝載模型) 可能會非常不適應,這篇文章主要用來解決大家的疑惑。

基本上,你只要先安裝 .NET 6.0 SDK 之後,就可以透過以下命令快速建立 ASP.NET Core Web API 的專案範本:

dotnet new webapi -n a1

以下我將介紹專案建立之後的每個檔案與相關說明:

  1. 主要專案檔 (a1.csproj)

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
      <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.5" />
      </ItemGroup>
    
    </Project>
    

    <TargetFramework>net6.0</TargetFramework> 是宣告主要的目標框架版本(TFM)!

    <Nullable>enable</Nullable> 是在全專案啟用 C# 8.0 開始提供的 Nullable reference types 語言特性,啟用此特性後,應用程式可以大幅減少常見的 NullReferenceException 的例外狀況,C# 編譯器會不斷提醒你各種可能發生 Null 例外的程式碼!

    <ImplicitUsings>enable</ImplicitUsings> 則是啟用「隱含引用命名空間」功能,依據你在第一行指定的 Sdk 屬性(Microsoft.NET.Sdk.Web),讓整個專案所有 *.cs 檔案都會自動 using 幾個最常見的命名空間(namespace),因此你在 *.cs 程式碼中就可以大幅降低實際 using 引用命名空間的程式碼!詳細說明請見 Implicit global using directives in C# projects 文章。 👍

    Microsoft.NET.Sdk.Web 預設會引用以下命名空間:

  2. 主程式 (Program.cs)

    // 建立 WebApplicationBuilder 物件
    var builder = WebApplication.CreateBuilder(args);
    
    // 透過 builder.Services 將服務加入 DI 容器
    
    builder.Services.AddControllers();
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
    
    // 建立 WebApplication 物件
    var app = builder.Build();
    
    // 透過 app 設定 Middlewares (HTTP request pipeline)
    
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    
    app.UseHttpsRedirection();
    app.UseAuthorization();
    app.MapControllers();
    
    // 啟動 ASP.NET Core 應用程式
    app.Run();
    

    由於 .NET 6.0 引入全新的 Top-level statements 語言特性,這段程式碼你看不到任何 using System;namespace a1 語句,更看不到所謂的 static void Main(string[] args) 方法,因此整份 Program.cs 看起來非常乾淨清爽,對 .NET 初學者來說非常親切! 👍

    另一方面,ASP.NET Core 全新的 Hosting Model 除了大幅簡化 ASP.NET Core 初始化的過程外,同時也保留了原本 .NET 5.0 原本的 Hosting Model。簡單來說,ASP.NET Core 6.0 的啟動 API 其實是封裝了 ASP.NET Core 5.0 的所有 API,雖然程式的寫法不同,但是骨子裡是完全相同的,原本的 ASP.NET Core 5.0 若想升級到 ASP.NET Core 6.0,你原本的 Program.csStartup.cs 都是不用特別改寫的!

  3. 啟動設定檔 (Properties\launchSettings.json)

    {
      "$schema": "https://json.schemastore.org/launchsettings.json",
      "iisSettings": {
        "windowsAuthentication": false,
        "anonymousAuthentication": true,
        "iisExpress": {
          "applicationUrl": "http://0.0.0.0:23665",
          "sslPort": 44347
        }
      },
      "profiles": {
        "a1": {
          "commandName": "Project",
          "dotnetRunMessages": true,
          "launchBrowser": true,
          "launchUrl": "swagger",
          "applicationUrl": "https://0.0.0.0:7021",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        },
        "IIS Express": {
          "commandName": "IISExpress",
          "launchBrowser": true,
          "launchUrl": "swagger",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        }
      }
    }
    
  4. 應用程式組態檔 (appsettings.json)

    以下是 ASP.NET Core 6.0 的預設組態設定檔,有再稍微簡化一點點,但本質上都是相同的:

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

    以下是 ASP.NET Core 5.0 的預設組態設定檔:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*"
    }
    
  5. 應用程式組態檔 (appsettings.Development.json)

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      }
    }
    
  6. API 控制器 (Controllers\WeatherForecastController.cs)

    // 整個控制器只有 using 一個 Microsoft.AspNetCore.Mvc 命名空間
    using Microsoft.AspNetCore.Mvc;
    
    // C# 10 全新的 namespace 語法,不用再看到 namespace 的 { } 了!
    namespace a1.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 = DateTime.Now.AddDays(index*2),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
    
  7. 模型類別 (WeatherForecast.cs)

    // C# 10 全新的 namespace 語法,不用再看到 namespace 的 { } 了!
    namespace a1;
    
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
    
        public int TemperatureC { get; set; }
    
        // 簡化版的 Property 語法
        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    
        // 這裡的 string? 是 Nullable reference types,用來宣稱這個字串有可能為空值
        public string? Summary { get; set; }
    }
    

相關連結