【ASP.NET Core】體驗一下 Mini Web API


在上一篇水文中,老周給大伙伴們簡單演示了通過 Socket 編程的方式控制 MPD (在樹莓派上)。按照計划,老周還想給大伙伴們演示一下使用 Web API 來封裝對 MPD 控制。思路很 Easy,樹莓派上使用本地 Socket 來封裝一下,然后以 Web API 的方式對客戶端公開。這樣有一個好處:之后不管你打算把客戶端做成桌面窗口,還是 Web 頁面,或是做成手機 App,你都可以直接調用這套 Web API。這樣一來,很多代碼就不必重復寫了,省時省力,減少腦細胞的大量死亡。

如果大家比較關心時事的話,應該知道 .NET 6 的 ASP.NET Core 有一個新特性—— Mini API,或 Mini Web API。有一個不錯的翻譯叫做“極簡 API”。其實,極簡的不只是 Web API,整個 ASP.NET Core 應用項目的結構都精簡了不少。最讓老周高興的就是沒有了 Startup 類(其實早期版本中也可以不使用 Startup,如果你以前看過老周的誤人子弟教程的話,你應該有印象),也不用費心地搞個什么 ConfigureService 又要弄個 Configure 方法約定了。再配合 C# 9 的新功能,連 Main 方法都省了。所以初始化配置工作都可以在一個代碼文件中搞定。

使用這個簡化版的 Web API 來做 MPD 的封裝還真的不錯。不過,本文老周先不弄這個,先讓大伙伴們了解一下 Mini API 怎么玩——權且當作預備知識。

.NET 6 還有個新功能也不錯,就是全局的 using 指令。以前在 C 語言中,如果你寫一個 abc.h 頭文件,里面放上這些代碼:

#ifndef _ABC_H_
#define _ABC_H_

#include "nc.h"
#include "nt.h"
#include "zz.h"
#include "xb.h"
#include "sb.h"

#endif

然后在代碼文件中 include 一個這個 abc.h 就可以間接引用這些頭文件,但 C# 中沒有這種玩法,每個代碼文件要用到哪些命名空間,都要寫一遍 using 指令。在隨同 .NET 6 一同發布的 C# 10 中終於有全局 using 了。只要你在其中一個代碼文件中寫上全局 using 指令,然后其他代碼文件中就不必再 using 了。

方法是在 using 前加上 global 就行了。C# 雖然早有 global 關鍵字,但在過去這個並不是全局 using 用的,而是專用來標識 .NET 框架中的命名空間的,主要是防止命名空間重名的。

 

好了,咱們現在就去嗨一下 Mini API吧。

此處假設你已經安裝好 VS 2022 和 .NET 6。在創建新項目時選擇空白 ASP.NET Core 應用程序。用空白項目方便稍后寫自己的 Code。

 

然后輸入項目名稱以及存放路徑。

 

選擇.net 版本號。

 

  最后,確定新創建項目。

---------------------------------------------------------------------------------

項目創建后你會發現,真TM簡潔了不少,Program.cs 文件中只有這么幾行。

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

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

app.Run();

第一行:調用 CreateBuilder 方法創建一個builder ,這個 builder 隨后用於構建 Web 應用程序。

第二行:直接就用預設的參數構建了一個 app 對象。

第三行:配置 HTTP 管道——怎么處理HTTP請求。此處配置表明只向客戶端返回“Hello World!”。

第四行:運行 app。

你,不用再寫 Startup 類了,也不用遵守方法簽約定去寫 ConfigureServices 等方法了。

要配置服務咋辦?直接 Services Add。例如

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); builder.Services.AddRazorPages(); builder.Services.AddAntiforgery() .AddWebEncoders() .AddSingleton<XXX, YYY>(); var app = builder.Build();
app.MapGet("/", () => "Hello World!");

app.Run();

看看是不是很整齊?注意這個過程是在 build 方法調用之前完成的。原因和以前 Startup 類中寫方法一樣,Add 服務是聲明咱們的應用程序中要使用哪些功能,哪些對象被用於依賴注入,一旦 build 了,程序的功能結構就確定下來了,所以應用程序構建后就不再修改其功能了。

以前在寫 Startup 時,我們知道,還有一個 Configure 方法用來配置中間件的,也就是剛剛說的配置HTTP管道。build 方法構建 app 后,就可以直接通過這個 app 實例來配置你要 Use 的東西。例如

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 中間件配置
app.MapGet("/", () => "Hello World!"); app.UseRouting(); app.UseCookiePolicy(); app.Use(async (context, next) => { context.Response.Headers.Add("Server", "Big Bomb"); await next(); }); 

 app.MapControllers();
 app.MapBlazorHub();
 app.MapRazorPages();

app.Run();

如果我們要編寫 Mini API,不需要 Add 什么 Service,也不需要 Use 什么組件,在 build 和 app.run 之間直接 MapXXX 就行了。XXX 指 HTTP 請求方法,比如 GET、POST、PUT 等。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
//====================================
// Mini API 寫在這里
//====================================
app.Run();

 

相當有意思的是:這些 MapXXX 擴展方法都有一個 handler 參數,類型是 Delegate。也就是說你在調用時可以傳遞任何類型的委托對象。於是,就可以這樣搞:

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

app.UseHttpsRedirection();
//====================================
// Mini API 寫在這里
app.MapGet("/greet", () => { return "What the fuck?"; }); //====================================
app.Run();

一個 Web API 就完成了。真的,可以用了,不信運行下看看。拿出秘密武器——Postman,測試一下。

 

 

用 Postman 還是有些不夠爽,而且這貨現在越做越復雜,還整天叫你注冊帳號,實屬無趣。我們改為用 swagger 來測試。打開 Nuget 包管理器,搜索 swagger。

 

 安裝這個包包。

 

把代碼改一下。

var builder = WebApplication.CreateBuilder(args);
// 不要忘了加這兩個服務
builder.Services.AddSwaggerGen(); builder.Services.AddEndpointsApiExplorer(); var app = builder.Build();
if (app.Environment.IsDevelopment())
{
   app.UseSwagger(); app.UseSwaggerUI();
}
app.UseHttpsRedirection();
//====================================
// Mini API 寫在這里
app.MapGet("/greet", () =>
{
    return "What the fuck?";
});
//====================================
app.Run();

這樣一來,咱們在開發測試階段就可以直接用這個組件在 Web 頁上測試 API 的調用了,不再啟動其他工具軟件了。

運行該項目,然后瀏覽器定位到 http(s)://root_url:port/swagger。

比如,我運行后得到的URL是 https://localhost:7189,那么在瀏覽器中打開 https://localhost:7189/swagger。

 

 

點擊右邊的“try it out”,然后點 “Execute” 按鈕,就能看到執行結果了。

 

 

怎么樣,好用吧?咱們再添加一個API,這次要帶參數的 POST 請求。

app.MapPost("/submit", (string name, int age) =>
{
    return $"你提交的內容:{name} - {age}";
});

這個 API 帶兩個參數,分別取名為 name,age。在調用時,是通過請求的 body 來提供的,格式為 JSON。

前面老周說過,這些MapXXX方法的委托參數是 Delegate 類型,所以你可以用任意類型的委托,有參數的沒參數的,有返回值的沒返回值的。

每次調試時都要在瀏覽器地址輸入 http(s)://root/swagger 太TM不方便了,咱們可以配置一下,讓其自動定位到 swagger 下。打開項目屬性窗口,轉到“調試”標簽。

 

 點擊頁面上的“打開調試啟動配置文件 UI”鏈接。

 

 把滾動條往地獄方向拉,一直拉到看到“URL”標題,在文本中填上 swagger。搞定。

現在,你直接運行項目,就自動打開 API 列表了。點擊展開 submit,再點“try it out”。

 

 為 name 和 age 參數填上值,執行。

 

 

下面再舉一例,請求方式為 GET,參數來自 URL 查詢(即帶 ? 的URL,如 /abc?t=3000)。

app.MapGet("/md5", ([FromQuery(Name = "msg")] string data) =>
{
    byte[] buffer = Encoding.UTF8.GetBytes(data);
    using MD5 md5ec = MD5.Create();
    byte[] comres = md5ec.ComputeHash(buffer);
    return $"加密結果:{Convert.ToHexString(comres).ToLower()}";
});

這個 API 的功能:接收一個字符串類型的對象,對其作 MD5 運算,然后返回結果。這個請求是從查詢字符串中得到參數 data 的值的,所以要加上 FromQuery 特性,而且,實際傳值時查詢參數的名稱與API的參數名稱不同,故要用 Name = .... 明確指定,要從 msg 查詢參數中提取值。

綜上,此API的調用方式為 GET /md5?msg=呵呵哈哈呵呵哈

 

 

咱們玩這一步了,你心中一定有個高大上的疑問:這貨支持依賴注入乎?

很好,老周也有此疑問,要不,咱們搞搞看。

public interface IComputer
{
    int RunIt(int x, int y, int z);
}

internal class ComputerService : IComputer
{
    public int RunIt(int x, int y, int z)
    {
        return x - y - z;
    }
}

我定義了一個服務接口,里面有個 RunIt 方法;然后俺實現之。邏輯很簡單,x、y、z 三數相減。

接下來改代碼,在 build 方法調用之前注冊服務,咱們就注冊個單實例模式吧,全局共享一個實例。

var builder = WebApplication.CreateBuilder(args);
…… builder.Services.AddSingleton<IComputer, ComputerService>();

然后,我們完成 API。

app.MapPost("/comp", (int n1, int n2, int n3, IComputer compsv) =>
{
    int r = compsv.RunIt(n1, n2, n3);
    return $"計算結果:{r}";
});

不要猶豫,運行它!

 

 得到結果:

 

 

在這個API中,n1,n2,n3 三個參數是從客戶端 POST 過來的,而最后一個參數是通過依賴注入得到引用對象的。那么,把參數的位置調換一下,是否也可行呢?

app.MapPost("/comp", (IComputer compsv, int n1, int n2, int n3) =>
{
    int r = compsv.RunIt(n1, n2, n3);
    return $"計算結果:{r}";
});

然后再測,結果表明,是可行滴。

 

 

好了,今天的話題就聊到這兒了,下次咱們就用這個 Mini API 來封裝 MPD。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM