理解 .NET 6 Minimal APIs
本次大版本發(fā)布,增加了一個(gè)新特性:Minimal APIs,這是什么技術(shù)?
.NET6 使編寫(xiě)具有最小依賴性的 REST API 變得非常簡(jiǎn)單。
乍一看,Minimal APIs 似乎是微軟對(duì) NodeJS(使用 ExpressJS)HTTP 服務(wù)器的回應(yīng),它提供了最小的 API。
但是微軟也對(duì)這項(xiàng)技術(shù)增加了幾個(gè)關(guān)鍵詞
LightWeight,Single file,Cloud Native API Low ceremony,Top-Level C# programs Easy to get started Path to MVC

總結(jié)一句話:.NET 6 Minimal APIs 簡(jiǎn)化了HTTP Rest API的設(shè)計(jì)和實(shí)現(xiàn),讓開(kāi)發(fā)者快速高效實(shí)現(xiàn)HTTP Rest API。
今天,我們花點(diǎn)時(shí)間,研究并科普一下.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 方法使用了內(nèi)聯(lián) lambda 表達(dá)式,完成一個(gè)Controller Action的業(yè)務(wù)邏輯,真的是超簡(jiǎn)單。
超簡(jiǎn)單完成一個(gè)HTTP WebAPI的定義:不再有 Startup.cs、API 控制器、額外依賴項(xiàng)等。
只需要這 4 行代碼即可生成以下輸出:

二、探究一下這段代碼背后的一些技術(shù)
上面的代碼,微軟官方文檔上,建議大家使用VS2022,其實(shí)用VS Code也可以
Tutorial: Create a minimal web API with ASP.NET Core
但是本機(jī)得先安裝.NET 6 SDK
安裝完成后,打開(kāi)VS Code,新建終端,創(chuàng)建一個(gè)Web Project
dotnet?new?web?-o?MyMinimalAPI

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

Program.cs這個(gè)類(lèi)中沒(méi)有using了,當(dāng)然也沒(méi)有main函數(shù)了,這里跟大家解釋一下:
1、.NET 5 引入了Top-Level Class,可以沒(méi)有main函數(shù),代碼作為直接入口執(zhí)行
2、.NET 6 新增了一個(gè)很棒的新特性——“隱式全局使用”
自動(dòng)生成不可見(jiàn)的 using 語(yǔ)句并在全局范圍內(nèi)聲明它們,因此不必處理在每個(gè)文件中重復(fù)聲明命名空間的混亂。
我們打開(kāi)MyMinimalAPI.csproj 看看里面的內(nèi)容,有一個(gè)配置:

dotnet build后,找到obj/Debug/net6.0 文件夾以查看隱藏的自動(dòng)生成文件 - [ProjectName].GlobalUsings.g.cs。使用一個(gè)單獨(dú)的類(lèi)來(lái)將所有 using 語(yǔ)句保存在一個(gè)地方。

這個(gè)功能,讓我們不需要在每個(gè)文件中重復(fù)聲明命名空間的using引用了。的確很方便、簡(jiǎn)單了。
當(dāng)然,如果不想使用此功能,可以禁用 .csproj 文件中的ImplicitUsings標(biāo)志。
在上面的示例中,app.MapGet 方法使用了內(nèi)聯(lián) lambda 表達(dá)式。同時(shí)還提供了:
app.MapPost() app.MapPut() app.MapDelete()
接下來(lái),我們用一個(gè)簡(jiǎn)單的示例,完成一個(gè)demo;
三、完成一個(gè)Minimal APIs完整的Demo
我們以一個(gè)簡(jiǎn)單Order訂單為例,通過(guò)Minimal APIs實(shí)現(xiàn)CRUD設(shè)計(jì)和實(shí)現(xiàn):
3.1 先準(zhǔn)備好Order類(lèi)和IOrderService接口以及OrderServiceRepository
Order類(lèi):
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類(lèi),使用內(nèi)存集合模擬實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)層。
namespace?NET6
{
????public?class?OrderServiceRepository?:?IOrderService
????{
????????static?List?orders?=?new?List();
????????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類(lèi)中,注冊(cè)IOrderService服務(wù),添加AddOrder和GetOrder Http Web API

using?NET6;
var?builder?=?WebApplication.CreateBuilder(args);
//registe?IOrderService?service
builder.Services.AddScoped();
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();
上面的低碼中,首先增加一個(gè)文件級(jí)別的namespace,這個(gè)地方為了和大家示意Global Namespace的區(qū)別
using NET6;
然后,在ASP.NET DI依賴注入框架中添加IOrderService服務(wù):
//registe?IOrderService?service
builder.Services.AddScoped();
添加訂單Order 保存API服務(wù):
//add?order?save?API
app.MapPost("/add",(Order?order,IOrderService?service)=>
{???
????service.CreateOrder(order);
}).WithName("addorder");
上面這個(gè)HttpWebAPI,我們采用了Post方式,請(qǐng)求是必須傳入order參數(shù)。
這個(gè)代碼中,我們看到保存訂單方法有2個(gè)參數(shù),一個(gè)是Order,另一個(gè)是IOrderService,第二個(gè)參數(shù),原生支持依賴注入,不需要顯式聲明創(chuàng)建。
類(lèi)似的,繼續(xù)添加查詢訂單API服務(wù)
//add?order?query?API
app.MapGet("/getorder",(int?id,?IOrderService?service)=>
{???????
????return?service.GetOrder(id);
}).WithName("getorder");
3.3 運(yùn)行調(diào)試
在終端中輸入dotnet run指令,啟動(dòng)運(yùn)行調(diào)試
dotnet?run

調(diào)試這3個(gè)API,建議大家使用PostMan工具
先說(shuō)一個(gè)小坑,一開(kāi)始使用PostMan工具調(diào)試保存訂單接口,將order顯式地參數(shù)放到Headers中請(qǐng)求,結(jié)果一直不通:

看了微軟的示例文檔后,建議直接將order json對(duì)象,http請(qǐng)求體中以raw的方式發(fā)起請(qǐng)求

其他的API接口則沒(méi)有這個(gè)問(wèn)題:

好了,以上是.NET 6 Minimal APIs的一些簡(jiǎn)單介紹和實(shí)踐,希望能幫助大家。
轉(zhuǎn)自:Eric zhou
鏈接:cnblogs.com/tianqing/p/15941896.html
