【ASP.NET Core】設置Web API 響應的數據格式——Produces 特性篇
- 2022 年 2 月 6 日
- 筆記
- .NET, Asp.Net Core, 個人文章
開春首文,今天老周就跟各位大夥伴們聊一個很簡單的話題:怎麼設定API響應的數據格式。
說本質一點,就是設置所返回內容的 MIME 類型(Content-Type 頭)。當然了,咱們不會使用在HTTP管道中插入中間件的方式來解決,因為:
A、這樣做會導致所有傳入傳出的HTTP消息都被修改;
B、這樣會毀壞API應用的設計規範,弄得不倫不類、禮崩樂壞、不堪入目。
所以,今天的主角是一個特性類(Attribute),它的大名叫 ProducesAttribute,位於 Microsoft.AspNetCore.Mvc 命名空間下。這麼一介紹,你肯定能找到它。
根據定義,該特性類可用於:類、方法。說得再直接一點,就是用於 Controller類 和 Action方法。
這個特性類用於 設置API返回數據的MIME類型,嗯,也就是所謂的格式了。最人性化最簡單的使用方法就是這樣:
[Produces("text/html")] [Produces("audio/wav")] [Produces("image/png")] [Produces("application/octet-stream")]
就是這樣,你希望返回的是啥東西,就用 Content-Type 字符串來指定。
馬上,立刻,現在,就給大伙兒演示一個例子,讓 API 返回 text/json 類型的數據。因為默認情況下,API 返回數據使用 application/json 格式,所以,咱們要改為 text/json,就得用 Produces 特性。
首先,新建一個空的 ASP.NET Core 應用項目。老周喜歡空模板,易於 DIY,可折騰性強。
然後,在 Program.cs 文件中註冊與 MVC 控制器有關的服務,以及Map一下相關中間件。
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); //這一句不要忘了 app.Run();
接着,新建一個類,或者在「新建項」中選擇空的 API 控制器。
[Route("api/[controller]")] [ApiController] public class Demo : ControllerBase { …… }
Route 特性指定訪問這個控制器的 URL,[controller] 是個佔位符,訪問時用實際的控制器名來替換。比如,這裡的控制器的名字是 Demo,訪問時的URL就是 //somehost/api/demo/xxxx。不過,這裡老周的命名不太規範,規範的命名應該是 DemoController。只是老周嫌它的後綴太長。
其實 API 和 MVC 的控制器實現起來一樣,但 API 沒有視圖,所以類繼承時,基類可以用 ControllerBase 類而不是 Controller 類。另外,在類上面加一個 ApiController 特性,表明這個 Demo 類是作為 API 控制器用的,並且它的派生類都作為 API 控制器。
好,我們先實現兩個 Action。
[Route("getbt")] [HttpGet] public string GetWTF() => "What the bitch"; [Route("getak")] [HttpGet] public IDictionary<string, int> GetAK() { // 返回一個類實例和返回字典對象 // 其JSON結構差不多 // 此處為了簡單,直接用字典 return new Dictionary<string, int> { ["item1"] = 10, ["item2"] = 49 }; }
Action 方法上指定的 Route 是相對於控制器類的 Route 的,即 /api/demo/getbt、/api/demo/getak。
這個相信各位看得懂,不用過多解釋,看不懂的肯定是因為你太謙虛了。
運行一下這個示例,直接通過瀏覽器的開發人員工具查看,得知:
第一個 action 返回的 string 類型,因此默認選用 text/plain 格式(普通文本)。
第二個 action 返回的是字典對象,默認選擇 application/json 格式。
現在,把 Produces 特性用上,使其返回的數據變為 text/json 格式。
[Route("api/[controller]")] [ApiController] [Produces("text/json")] public class Demo : ControllerBase { …… }
再次運行,從瀏覽器的開發人員工具中查看HTTP消息。
不過,你得小心!如果你指定的格式與 API 所返回的對象無法兼容,就會崩盤。比如,把上面的 getak 改成這樣:
[Route("getak")] [HttpGet] [Produces("text/plain")] public IDictionary<string, int> GetAK() { …… }
雖然 Demo 控制器類上應用了 Produces 特性指定了 text/json 格式,但這個方法上也應用了此特性,依據就近原則,程序會優先選用 text/plain 格式。在內部的處理機制中,這是不匹配的,除非方法的返回值類型是 string。
一旦執行,就會得到錯誤狀態碼。
下面演示一個返回 jpg 圖像格式(即 image/jpeg)的例子。在剛才的 Demo 控制器類上增加一個方法,名為 GetImage。
[Route("getpic")] [HttpGet] [Produces("image/jpeg")] public Stream GetImage() { // 因為應用程序目錄和內容目錄相同 // 所以直接獲取Current即可 string dirpath = Directory.GetCurrentDirectory(); // 直接返迴文件流 return System.IO.File.OpenRead(Path.Combine(dirpath, "505.jpg")); }
方法的返回類型為 Stream 對象,套用 image/jpeg 格式是沒問題的,畢竟圖像是以二進制的方式響應的。
老周事先從網上找了一張圖片,命名為 505.jpg,放在項目根目錄下。你在測試時可以隨便找個圖片,或者拍一張妹子的照片(前提是妹子不會報警),放到項目目錄下即可,文件名自己改。
在瀏覽器中訪問後得到結果如下圖所示。
————————————————— 異次元分界線 ———————————————————–
既然數據可以以 JSON 格式返回,那能不能返回 XML 格式呢?當然是可以的。
public class 帥哥 { public string Name { get; set; } public int Age { get; set; } public decimal Weight { get; set; } }
----------------------------------------------------------- [Route("getxml")] [HttpGet] [Produces("application/xml")] public 帥哥 GetXML() { return new 帥哥 { Name = "老周", Age = 93, Weight = 203.77M }; }
先是定義了一個新類,叫「帥哥」,接着,GetXML 方法返回一個「帥哥」類型的實例。注意此方法應用了 Produces 特性,指定返回的數據格式為 application/xml。
Web API 控制器默認是不啟用 XML 輸出支持的,所以在 Program.cs 文件中,在註冊MVC功能到服務容器時,需要手動開啟對XML輸出的支持。
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers().AddXmlSerializerFormatters(); var app = builder.Build(); ……
這樣一來,訪問 /api/demo/getxml 就能得到 XML 數據了。
好了,今天的文章就水到這裡了,下一篇咱們聊聊 FormatFilter 特性類。