通俗理解.NET 6 Minimal APIs

微軟技術棧發表於2022-02-28

   .NET 6,微軟稱為“最快的.NET”,帶有了許多令人興奮的新功能、語言和效能改進。這是自 .NET Core 3.1 以來的第一個 LTS 版本,將支援三年。

   本次大版本釋出,增加了一個新特性:Minimal APIs,這是什麼技術?

        .NET6 使編寫具有最小依賴性的 REST API 變得非常簡單。

   乍一看,Minimal APIs 似乎是微軟對 NodeJS(使用 ExpressJS)HTTP 伺服器的回應,它提供了最小的 API。

   但是微軟也對這項技術增加了幾個關鍵詞

  • LightWeight,Single file,Cloud Native API
  • Low ceremony,Top-Level C# programs
  • Easy to get started
  • Path to MVC

   總結一句話:.NET 6 Minimal APIs 簡化了HTTP Rest API的設計和實現,讓開發者快速高效實現HTTP Rest API。

   今天,我們花點時間,研究併科普一下.NET 6 Minimal APIs。

一、先看一下.NET 6 Minimal APIs的示例程式碼

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

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

app.Run();

在上面的示例中,app.MapGet 方法使用了內聯 lambda 表示式,完成一個Controller Action的業務邏輯,真的是超簡單。

超簡單完成一個HTTP WebAPI的定義:不再有 Startup.cs、API 控制器、額外依賴項等。

只需要這 4 行程式碼即可生成以下輸出:

二、探究一下這段程式碼背後的一些技術

上面的程式碼,微軟官方文件上,建議大家使用VS2022,其實用VS Code也可以

Tutorial: Create a minimal web API with ASP.NET Core

但是本機得先安裝.NET 6 SDK

安裝完成後,開啟VS Code,新建終端,建立一個Web Project

dotnet new web -o MyMinimalAPI

       程式碼工程中,我們可以看到:

 Program.cs這個類中沒有using了,當然也沒有main函式了,這裡跟大家解釋一下:

  ① .NET5 引入了Top-Level Class,可以沒有main函式,程式碼作為直接入口執行

  ② .NET 6 新增了一個很棒的新特性——“隱式全域性使用

自動生成不可見的 using 語句並在全域性範圍內宣告它們,因此不必處理在每個檔案中重複宣告名稱空間的混亂。

我們開啟MyMinimalAPI.csproj 看看裡面的內容,有一個配置:

       <ImplicitUsings>enable</ImplicitUsings>
 

 dotnet build後,找到obj/Debug/net6.0 資料夾以檢視隱藏的自動生成檔案 - [ProjectName].GlobalUsings.g.cs。您可以定義一個單獨的類來將所有 using 語句儲存在一個地方。

 

    這個功能,讓我們不需要在每個檔案中重複宣告名稱空間的using引用了。的確很方便、簡單了。

    當然,如果不想使用此功能,可以禁用 .csproj 檔案中的ImplicitUsings標誌。

    在上面的示例中,app.MapGet 方法使用了內聯 lambda 表示式。同時還提供了:

app.MapPost()
app.MapPut()
app.MapDelete()

    接下來,我們用一個簡單的示例,完成一個demo;

三、完成一個Minimal APIs完整的Demo

  我們以一個簡單Order訂單為例,通過Minimal APIs實現CRUD設計和實現:

  3.1 先準備好Order類和IOrderService介面以及OrderServiceRepository

   Order類:    

namespace NET6
{
    public class Order
    {
        public int ID {get;set;}

        public decimal  Price  {get;set;}

        public string CustomAddress {get;set;}

        public int State{get;set;}
    }
}

    IOrderService介面:

namespace NET6
{
    public interface IOrderService
    {
         Order GetOrder(int id);

         void CreateOrder(Order order);

         void DeleteOrder(int id);

         void UpdateOrder(Order order);
    }
}

      OrderServiceRepository類,使用記憶體集合模擬實現資料儲存層。

namespace NET6
{
    public class OrderServiceRepository : IOrderService
    {
        static List<Order> orders = new List<Order>();

        public Order GetOrder(int id)
        {
            return orders.FirstOrDefault(i=>i.ID == id)?? null;
        }

        public void CreateOrder(Order order)
        {
            orders.Add(order);
        }

        public void DeleteOrder(int id)
        {
            var order = orders.FirstOrDefault(i=>i.ID == id);
            if(order!=null)
            orders.Remove(order);
        }

        public void UpdateOrder(Order order)
        {
            DeleteOrder(order.ID);
            CreateOrder(order);
        }
    }
}

 3.2 在Program.cs類中,註冊IOrderService服務,新增AddOrder和GetOrder Http Web API

  

using NET6;

var builder = WebApplication.CreateBuilder(args);

//registe IOrderService service
builder.Services.AddScoped<IOrderService, OrderServiceRepository>();

var app = builder.Build();

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

//add order save API
app.MapPost("/add",(Order order,IOrderService service)=>
{   
    service.CreateOrder(order);
}).WithName("addorder");

//add order query API
app.MapGet("/getorder",(int id, IOrderService service)=>
{       
    return service.GetOrder(id);
}).WithName("getorder");

app.Run();

  上面的低碼中,首先增加一個檔案級別的namespace,這個地方為了和大家示意Global Namespace的區別

   using NET6;
 
   然後,在ASP.NET DI依賴注入框架中新增IOrderService服務:
//registe IOrderService service
builder.Services.AddScoped<IOrderService, OrderServiceRepository>();

   新增訂單Order 儲存API服務:

//add order save API
app.MapPost("/add",(Order order,IOrderService service)=>
{   
    service.CreateOrder(order);
}).WithName("addorder");

   上面這個HttpWebAPI,我們採用了Post方式,請求是必須傳入order引數。

   這個程式碼中,我們看到儲存訂單方法有2個引數,一個是Order,另一個是IOrderService,第二個引數,原生支援依賴注入,不需要顯式宣告建立。

   類似的,繼續新增查詢訂單API服務

//add order query API
app.MapGet("/getorder",(int id, IOrderService service)=>
{       
    return service.GetOrder(id);
}).WithName("getorder");

 3.3 執行除錯

  在終端中輸入dotnet run指令,啟動執行除錯

dotnet run

 除錯這3個API,建議大家使用PostMan工具

 先說一個小坑,一開始使用PostMan工具除錯儲存訂單介面,將order顯式地引數放到Headers中請求,結果一直不通:

  

 

   看了微軟的示例文件後,建議直接將order json物件,http請求體中以raw的方式發起請求

   

 

     其他的API介面則沒有這個問題:

    

 

  好了,以上是.NET 6 Minimal APIs的一些簡單介紹和實踐,希望能幫助大家。

 

周國慶

2022/2/28

 

  

 

相關文章