跟同事合做先後端分離項目,本身對 WebApi 的不少知識不夠全,雖然說沒必要要學全棧,但是也要了解基礎知識,才能合理設計接口、API,方便與前端交接。html
晚上回到宿舍後,對 WebApi 的知識查漏補缺,主要補充了 WebAPi 的一些方法、特性等如何與前端契合,如何利用工具測試 API 、Axios 請求接口。前端
本文主要寫 WebApi 前端請求數據到 API 、後端返回處理結果,不涉及登陸、跨域請求、前端 UI 等。(難一點我不會了。。。看張隊的公衆號,篇篇都看不懂。。。)ios
前提:會一點點 VUE、會一點 Axios、會一點點 Asp.net Core。git
工具:Visual Studio 2019(或者其它版本) + Visual Studio Code + Swagger +Postmangithub
因爲 Visual Studio 2019 寫 ASP.NET Core 頁面時,沒有 Vue 的智能提示,因此須要使用 VSCode 來寫前端頁面。web
本文 代碼 已發佈到 GitHub https://github.com/whuanle/CZGL.IKonwWebApishell
特性 | 綁定源 |
---|---|
[FromBody] | 請求正文 |
[FromForm] | 請求正文中的表單數據 |
[FromHeader] | 請求標頭 |
[FromQuery] | 請求查詢字符串參數 |
[FromRoute] | 當前請求中的路由數據 |
[FromServices] | 做爲操做參數插入的請求服務 |
來一張 Postman 的圖片:
HTTP 請求中,會攜帶不少參數,這些參數能夠在前端設置,例如表單、Header、文件、Cookie、Session、Token等。
那麼,上面的表格正是用來從 HTTP 請求中獲取數據的 「方法」
或者說 「手段」
。HttpContext 等對象不在本文討論範圍。
Microsoft.AspNetCore.Mvc
命名空間提供不少用於配置Web API 控制器的行爲和操做方法的屬性:
特性 | 說明 |
---|---|
[Route] | 指定控制器或操做的 URL 模式。 |
[Bind] | 指定要包含的前綴和屬性,以進行模型綁定。 |
[Consumes] | 指定某個操做接受的數據類型。 |
[Produces] | 指定某個操做返回的數據類型。 |
[HttpGet] | 標識支持 HTTP GET 方法的操做。 |
[HttpPost] | 標識支持 HTTP POST 方法的操做。 |
... ... ... | ... ... ... |
WebApi 應用
首先建立一個 Asp.Net Core MVC 應用,而後在 Controllers 目錄添加一個 API 控制器 DefaultController.cs
。(這裏不建立 WebApi 而是 建立 MVC,經過 MVC 建立 API 控制器)。
建立後默認代碼:
[Route("api/[controller]")] [ApiController] public class DefaultController : ControllerBase { }
在 Nuget 中搜索 Swashbuckle.AspNetCore
,或打開 程序包管理器控制檯 -> 程序包管理器控制檯
,輸入如下命令進行安裝
Install-Package Swashbuckle.AspNetCore -Version 5.0.0-rc2
打開 Startup
文件,添加引用
using Microsoft.OpenApi.Models;
在 ConfigureServices
中添加服務,雙引號文字內容隨便改。
services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); });
添加中間件
app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseCookiePolicy(); // 添加下面的內容 app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); });
訪問 /swagger
能夠訪問到 Swagger 的 UI 界面。
爲了便於查看輸出和固定端口,打開 Progarm,cs
,修改內容
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseUrls("https://*:5123") .UseStartup<Startup>();
不要使用 IIS 託管運行。
注意:本文所有使用 [HttpPost] ;全局使用 JsonResult 做爲返回類型。
直接寫 action
,不使用特性
[HttpPost("aaa")] public async Task<JsonResult> AAA(int? a, int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 2000, result = a + "|" + b }); }
打開 https://localhost:5123/swagger/index.html 查看 UI 界面
也就是說,建立一個 action
,什麼都不加,默認是 query
。
經過 Postman 提交數據、測試接口
對於 Query 的 action 來講, axios 的寫法
postaaa: function () { axios.post('/api/default/aaa?a=111&b=222' ) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) }
在網上查找資料時,發現有人說經過 params 添加數據也能夠,不過筆者測試,貌似不行。
講道理,別人能夠,爲啥我不行。。。
axios 代碼:
postaaa: function () { axios.post('/api/default/aaa', { params: { a: 123, b: 234 } } ) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) }
包括下面的,都試過了,不行。
axios.post('/api/default/aaa', { a:1234, b:1122 } axios.post('/api/default/aaa', { data:{ a:1234, b:1122 } }
把 [HttpPost]
改爲 [HttpGet]
,則可使用
axios.post('/api/default/aaa', { params: { a: 123, b: 234 } } ... ...
提示:
... ... .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); })
.then
當請求成功時觸發,請求失敗時觸發 catch
。res
是請求成功後返回的信息,res.data
是請求成功後服務器返回的信息。便是 action
處理數據後返回的信息。
在瀏覽器,按下 F12 打開控制檯,點擊 Console ,每次請求後,這裏會打印請求結果和數據。
官方文檔解釋:請求正文。[FromBody] 針對複雜類型參數進行推斷。 [FromBody] 不適用於具備特殊含義的任何複雜的內置類型,如 IFormCollection 和 CancellationToken。 綁定源推理代碼將忽略這些特殊類型。
算了,看得一頭霧水,手動實際試試。
剛剛開始的時候,我這樣使用:
public async Task<JsonResult> BBB([FromBody]int? a, [FromBody]int? b)
結果編譯時就報錯,提示只能使用一個 [FromBody],因而改爲
[HttpPost("bbb")] public async Task<JsonResult> BBB([FromBody]int? a, int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 2000, result = a + "|" + b }); }
打開 Swagger UI 界面,刷新一下
從圖片中發現,只有 b,沒有 a,並且右上角有下拉框,說明了加 [FromBody] 是 json 上傳。
那麼說明 [FromBody] 修飾得應當是對象,而不是 字段。
修改程序以下:
// 增長一個類型 public class AppJson { public int? a { get; set; } public int? b { get; set; } } [HttpPost("bbb")] public async Task<JsonResult> BBB([FromBody]AppJson ss) { if (ss.a == null || ss.b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 2000, result = ss.a + "|" + ss.b }); }
再看看微軟的文檔:[FromBody] 針對複雜類型參數進行推斷。
,這下可理解了。。。
便是不該該對 int、string 等類型使用 [FromBody] ,而應該使用一個 複雜類型
。
並且,一個 action 中,應該只能使用一個 [FromBody] 。
打開 Swagger 界面(有修改須要刷新下界面,下面再也不贅述)。
這樣纔是咱們要的結果嘛,前端提交的是 Json 對象。
用 Postman 測試下
證明了猜測,嘿嘿,嘿嘿嘿。
前端提交的是 Json 對象,遵循 Json 的格式規範,那麼 [FromBody] 把它轉爲 Object 對象。
前端 axios 寫法:
methods: {
postaaa: function () { axios.post('/api/default/bbb', { "a": 4444, "b": 5555 }) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) } }
[HttpPost("ccc")] public async Task<JsonResult> CCC([FromForm]int? a, [FromForm]int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 200, result = a + "|" + b }); }
固然,這樣寫也行,多個字段或者對象均可以
[HttpPost("ccc")] public async Task<JsonResult> CCC([FromForm]AppJson ss) { if (ss.a == null || ss.b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 200, result = ss.a + "|" + ss.b }); }
根據提示,使用 Postman 進行測試
事實上,這樣也行 ↓
form-data 和 x-www.form-urlencoded 都是鍵值形式,文件 form-data 能夠用來上傳文件。具體的區別請自行查詢。
axios 寫法(把 Content-Type 字段修改爲 form-data 或 x-www.form-urlencoded )
postccc: function () { let fromData = new FormData() fromData.append('a', 111) fromData.append('b', 222) axios.post('/api/default/ccc', fromData, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) }
[FromHeader] 不以表單形式上傳,而是跟隨 Header 傳遞參數。
[HttpPost("ddd")] public async Task<JsonResult> DDD([FromHeader]int? a, [FromHeader]int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 200, result = a + "|" + b }); }
axios 寫法
postddd: function () { axios.post('/api/default/ddd', {}, { headers: { a: 123, b: 133 } }) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) }
須要注意的是,headers 的參數,必須放在第三位。沒有要提交的表單數據,第二位就使用 {} 代替。
params 跟隨 url 一塊兒在第一位,json 或表單數據等參數放在第二位,headers 放在第三位。
因爲筆者對前端不太熟,這裏有說錯,麻煩大神評論指出啦。
前面已經說了,Action 參數不加修飾,默認就是 [FromQuery] ,參考第一小節。
有個地方須要記住, Action 參數不加修飾。默認就是 [FromQuery] ,有時幾種參數並在一塊兒放到 Action 裏,會忽略掉,調試時忘記了,形成麻煩。
獲取路由規則,這個跟前端上傳的參數無關;跟 URL 能夠說有關,又能夠說無關。
[HttpPost("fff")] public async Task<JsonResult> FFFxxx(int a,int b, [FromRoute]string controller, [FromRoute]string action) { // 這裏就不處理 a和 b了 return new JsonResult(new { code = 200, result = controller+"|"+action }); }
[FromRoute] 是根據路由模板獲取的,上面 API 的兩個參數和路由模板的名稱是對應的:
[FromRoute]string controller, [FromRoute]string action
app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
固然,還能夠加個 [FromRoute]int? id
[FromRoute] 和 [FromQuery] 區別
以此 URL 爲例
https://localhost:5123/api/Default/fff?a=111&b=22
Route 會查到 controller = Default
,action = FFFxxx
。查詢到的是代碼裏的真實名稱。
Query 會查詢到 a = 111
和 b = 22
那麼,若是路由規則裏,不在 URL 裏出現呢?
[HttpPost("/ooo")] public async Task<JsonResult> FFFooo(int a, int b, [FromRoute]string controller, [FromRoute]string action) { // 這裏就不處理 a和 b了 return new JsonResult(new { code = 200, result = controller + "|" + action }); }
那麼,訪問地址變成 https://localhost:5123/ooo
經過 Postman ,測試
說明了 [FromRoute] 獲取的是代碼裏的 Controller 和 Action 名稱,跟 URL 無關,根據測試結果推斷跟路由表規則也無關。
這個是與依賴注入容器有關,跟 URL 、路由等無關。
新建一個接口、一個類
public interface ITest { string GGG { get; } } public class Test : ITest { public string GGG { get { return DateTime.Now.ToLongDateString(); } } }
在 ConfigureServices
中 注入
services.AddSingleton<ITest, Test>();
在 DefaultController
中,建立構造函數,而後
private readonly ITest ggg; public DefaultController(ITest ttt) { ggg = ttt; }
添加一個 API
[HttpPost("ggg")] public async Task<JsonResult> GGG([FromServices]ITest t) { return new JsonResult(new { code = 200, result = t.GGG }); }
訪問時,什麼參數都不須要加,直接訪問此 API 便可。
[FromService] 跟後端的代碼有關,跟 Controller 、Action 、URL、表單數據等無關。
小結:
特性能夠幾種放在一塊兒用,不過儘可能每一個 API 的參數只使用一種特性。
優先取值 Form > Route > Query
。
IFromFile 因爲文件的上傳,本文就不談這個了。
關於數據綁定,更詳細的內容請參考:
https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/model-binding?view=aspnetcore-2.2
Microsoft.AspNetCore.Mvc
命名空間提供可用於配置 Web API 控制器的行爲和操做方法的屬性。
下表是針對於 Controller 或 Action 的特性.
特性 | 說明 |
---|---|
[Route] | 指定控制器或操做的 URL 模式。 |
[Bind] | 指定要包含的前綴和屬性,以進行模型綁定。 |
[Consumes] | 指定某個操做接受的數據類型。 |
[Produces] | 指定某個操做返回的數據類型。 |
[HttpGet] | 標識支持 HTTP GET 方法的操做。 |
... | ... |
下面使用這些屬性來指定 Controller 或 Action 接受的 HTTP 方法、返回的數據類型或狀態代碼。
在微軟文檔中,把這個特性稱爲 屬性路由
,定義:屬性路由使用一組屬性將操做直接映射到路由模板。
請教了大神,大神解釋說,ASP.NET Core 有路由規則表,路由表是全局性、惟一性的,在程序運行時,會把全部路由規則收集起來。
MVC 應用中設置路由的方法有多種,例如
app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
[Route("Home/Index")] public IActionResult Index() { return View(); }
[Route("api/[controller]")] [ApiController] public class DefaultController : ControllerBase { }
路由是全局惟一的,能夠經過不一樣形式使用,可是規則不能發生衝突,程序會在編譯時把路由表收集起來。
根據筆者經驗,發生衝突,應該就是在編譯階段直接報錯了。(注:筆者不敢肯定)
關於路由,請參考 :
筆者知道這個是綁定模型的,可是對原理不太清楚。ASP.NET Core 自動生成的可讀寫的 Controller ,默認都是使用 [Bind] 來綁定數據。
文檔定義:用於對複雜類型的模型綁定。
有下面幾種相近的特性:
[BindRequired]
[BindNever]
[Bind]
微軟文檔提示:若是發佈的表單數據是值的源,則這些屬性會影響模型綁定。
就是說,上面的特性是針對類、接口等複雜類型(下面統稱模型),對於 int、string 這些類型,可能出毛病。
[BindRequired] 、[BindNever] 只能應用於模型的屬性,如
public class TestB { [BindNever] public int ID { get; set; } [BindRequired] public string Name { get; set; } }
可是 [BindRequired] 、[BindNever] 不在討論範圍內,這裏只說 [Bind]。
[Bind] 用於類或方法(Controller、Action),指定模型綁定中應包含的模型屬性。
在微軟官方文檔,對於[Bind] 的解釋:
[Bind]
屬性可用於防止「建立」方案中的過多發佈狀況 。 因爲排除的屬性設置爲 NULL 或默認值,而不是保持不變,所以它在編輯方案中沒法很好地工做;Bind
特性將清除未在 某個 參數中列出的字段中的任何之前存在的數據。一臉懵逼。
下面是個人踩坑過程,不感興趣的話直接跳過吧。筆記筆記,記得固然是本身以爲要記的哈哈哈。
新建一個類
public class TestBind { public string A { get; set; } public string B { get; set; } public string C { get; set; } public string D { get; set; } public string E { get; set; } public string F { get; set; } public string G { get; set; } }
新建 API
[HttpPost("hhh")] public async Task<JsonResult> HHH([Bind("A,B,C")] TestBind test) { if (ModelState.IsValid == true) return new JsonResult(test); return new JsonResult(new { Code = 0, Result = "驗證不經過" }); }
使用 Postman 進行,測試,發現必須使用 Json 形式,才能訪問到這個 Action ,其它方式會直接 返回 錯誤。
{
"errors": { "": [ "A non-empty request body is required." ] }, "title": "One or more validation errors occurred.", "status": 400, "traceId": "0HLO03IFQFTQU:00000007" }
經過兩次 Postman 進行測試
通過測試,我猜測
ModelState.IsValid 跟模型裏的驗證規則有關係,跟 [Bind] 不要緊(儘管用於測試的 TestB 類中沒有寫驗證規則),所以不能使用 ModelState.IsValid 驗證 [Bind] 是否符合規則。
Action 的參數:[Bind("A,B,C")] TestBind test
,剛開始的時候我覺得請求的數據中必須包含 A、B、C。
測試後發現不是。。。再認真看了文檔 :由於 Bind
特性將清除未在 某個 參數中列出的字段中的任何之前存在的數據。
我修改一下:
[HttpPost("hhh")] public async Task<JsonResult> HHH( string D, string E,[Bind("A,B,C")] TestBind test) { if (ModelState.IsValid == true) return new JsonResult(new { data1 = test, data2 = D, data3 = E }); return new JsonResult(new { Code = 0, Result = "驗證不經過" }); }
參數變成了 string D, string E,[Bind("A,B,C")] TestBind test
使用 Swagger 進行測試:
{
"data1": { "a": "string", "b": "string", "c": "string", "d": "string", "e": "string", "f": "string", "g": "string" }, "data2": null, "data3": null }
改爲
[HttpPost("hhh")] public async Task<JsonResult> HHH([Bind("A,B,C")] TestBind test, string J, string Q) { if (ModelState.IsValid == true) return new JsonResult(new { data1 = test, data2 = J, data3 = Q }); return new JsonResult(new { Code = 0, Result = "驗證不經過" }); }
返回結果
{
"data1": { "a": "string", "b": "string", "c": "string", "d": "string", "e": "string", "f": "string", "g": "string" }, "data2": null, "data3": null }
文檔中對 [Bind] 描述最多的是:防止過多發佈。
經過上面的測試,首先確定的是一個 Action 裏,有多個參數 如
[Bind("A,B,C")] TestBind test, string D, string E string J, string Q
。
注意,下面的結論是錯的!
那麼 D、E 由於於 除了 Test, J、Q就會無效,經過百度,[Bind] 修飾的 Action ,前端請求的數據只有 Test 裏面的數據有效,其它 Query等形式一併上傳的數據都會失效,防止黑客在提交數據時摻雜其它特殊參數。應該就是這樣理解吧。
上面是一開始個人結論,直到屢次測試,我發現是錯的。
但是有一個地方不明白,
[Bind("A,B,C")]
[Bind("A,B,C,D,E,F,G")]
這二者的區別是是什麼。仍是沒搞清楚。
忽然想到 Query,當字段沒有使用特性修飾時,默認爲 Query 。
最終踩坑測試代碼
模型類
public class TestBind { public string A { get; set; } public string B { get; set; } public string C { get; set; } public string D { get; set; } public string E { get; set; } public string F { get; set; } public string G { get; set; } }
Action
[HttpPost("hhh")] public async Task<JsonResult> HHH( string A, string B, string E, string F, string G, [Bind("A,B,C,D")] TestBind test, string C, string D, string J, string Q) { if (ModelState.IsValid == true) return new JsonResult(new { data1 = test, dataA = A, dataB = B, dataC = C, dataD = D, dataE = E, dataF = F, dataG = G, dataJ = J, dataQ = Q }); return new JsonResult(new { Code = 0, Result = "驗證不經過" }); }
Swagger 測試
Postman 測試
{
"data1": { "a": "111", "b": "111", "c": "111", "d": "111", "e": "111", "f": "111", "g": "111" }, "dataA": "222", "dataB": "222", "dataC": "222", "dataD": "222", "dataE": "222", "dataF": "222", "dataG": "222", "dataJ": "222", "dataQ": "222" }
再在 Swagger 或 Postman ,換着法子嘗試各類不一樣組合的輸入。
我懵逼了。試了半天試不出什麼。
實在不理解 [Bind] 裏,「防止過多發佈」 是什麼意思
[Bind("A,B,C")]
[Bind("A,B,C,D,E,F,G")]
這二者的區別是是什麼。仍是沒搞清楚。算了,不踩了。
我再到 stackoverflow 提問題,地址 https://stackoverflow.com/questions/56884876/asp-net-core-bind-how-to-use-it/56885153#56885153
得到一個回答:
What's the difference between [Bind("A,B,C")] and [Bind("A,B,C,D,E,F,G")]? The former tells the model binder to include only the properties of TestBind named A, B and C. The latter tells the model binder to include those same properties plus D, E, F and G. Are you testing by posting data for all properties of your model? You should notice that the values you post for the excluded properties are not bound.
算了,嘿嘿,測試不出來,放棄。
[Consumes("application/json")] [Produces("application/json")] [Produces("application/xml")] [Produces("text/html")] ... ...
目前只瞭解到 [Consumes]、[Produces] 是篩選器,用來表示 Controller 或 Action 所能接受的數據類型。大概就是像下面這樣使用:
[Consumes("application/json")] [Produces("application/json")] public class DefaultTestController : ControllerBase { }
可是如何實際應用呢?我找了好久,都沒有找到什麼結果。在 stackoverflow 找到一個回答:
https://stackoverflow.com/questions/41462509/adding-the-produces-filter-globally-in-asp-net-core
修飾 Action ,用來標識這個 Action 可以經過什麼方式訪問、訪問名稱。
例如:
[Route("api/[controller]")] [ApiController] public class DefaultController : ControllerBase { [HttpPost("aaa")] public async Task<JsonResult> AAA(int? a, int? b) { if (a == null | b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 200, result = a + "|" + b }); } }
訪問地址 https://localhost:5123/api/Default/aaa
使用時,會受到 Controller 和 Action 路由的影響。
但 自己亦可控制路由。以上面的控制器爲例
[HttpPost("aaa")] //相對路徑
訪問地址 xxx:xxx/api/Default/aaa
[HttpPost("/aaa")] //絕對路徑
訪問地址 xxx:xxx/aaa
Microsoft.AspNetCore.Mvc
命名空間中,包含控制 MVC 的各類操做方法和類型,筆者從命名空間中抽出與 MVC 或 API 返回類型有關的類型,生成表格:
類型 | 描述 |
---|---|
AcceptedAtActionResult | An ActionResult that returns a Accepted (202) response with a Location header. |
AcceptedAtRouteResult | An ActionResult that returns a Accepted (202) response with a Location header. |
AcceptedResult | An ActionResult that returns an Accepted (202) response with a Location header. |
AcceptVerbsAttribute | Specifies what HTTP methods an action supports. |
ActionResult | A default implementation of IActionResult. |
ActionResult | A type that wraps either an TValue instance or an ActionResult. |
BadRequestObjectResult | An ObjectResult that when executed will produce a Bad Request (400) response. |
BadRequestResult | A StatusCodeResult that when executed will produce a Bad Request (400) response. |
ChallengeResult | An ActionResult that on execution invokes AuthenticationManager.ChallengeAsync. |
ConflictObjectResult | An ObjectResult that when executed will produce a Conflict (409) response. |
ConflictResult | A StatusCodeResult that when executed will produce a Conflict (409) response. |
ContentResult | |
CreatedAtActionResult | An ActionResult that returns a Created (201) response with a Location header. |
CreatedAtRouteResult | An ActionResult that returns a Created (201) response with a Location header. |
CreatedResult | An ActionResult that returns a Created (201) response with a Location header. |
EmptyResult | Represents an ActionResult that when executed will do nothing. |
FileContentResult | Represents an ActionResult that when executed will write a binary file to the response. |
FileResult | Represents an ActionResult that when executed will write a file as the response. |
FileStreamResult | Represents an ActionResult that when executed will write a file from a stream to the response. |
ForbidResult | An ActionResult that on execution invokes AuthenticationManager.ForbidAsync. |
JsonResult | An action result which formats the given object as JSON. |
LocalRedirectResult | An ActionResult that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), or Permanent Redirect (308) response with a Location header to the supplied local URL. |
NotFoundObjectResult | An ObjectResult that when executed will produce a Not Found (404) response. |
NotFoundResult | Represents an StatusCodeResult that when executed will produce a Not Found (404) response. |
OkObjectResult | An ObjectResult that when executed performs content negotiation, formats the entity body, and will produce a Status200OK response if negotiation and formatting succeed. |
OkResult | An StatusCodeResult that when executed will produce an empty Status200OKresponse. |
PartialViewResult | Represents an ActionResult that renders a partial view to the response. |
PhysicalFileResult | A FileResult on execution will write a file from disk to the response using mechanisms provided by the host. |
RedirectResult | An ActionResult that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), or Permanent Redirect (308) response with a Location header to the supplied URL. |
RedirectToActionResult | An ActionResult that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), or Permanent Redirect (308) response with a Location header. Targets a controller action. |
RedirectToPageResult | An ActionResult that returns a Found (302) or Moved Permanently (301) response with a Location header. Targets a registered route. |
RedirectToRouteResult | An ActionResult that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), or Permanent Redirect (308) response with a Location header. Targets a registered route. |
SignInResult | An ActionResult that on execution invokes AuthenticationManager.SignInAsync. |
SignOutResult | An ActionResult that on execution invokes AuthenticationManager.SignOutAsync. |
StatusCodeResult | Represents an ActionResult that when executed will produce an HTTP response with the given response status code. |
UnauthorizedObjectResult | An ObjectResult that when executed will produce a Unauthorized (401) response. |
UnauthorizedResult | Represents an UnauthorizedResult that when executed will produce an Unauthorized (401) response. |
UnprocessableEntityObjectResult | An ObjectResult that when executed will produce a Unprocessable Entity (422) response. |
UnprocessableEntityResult | A StatusCodeResult that when executed will produce a Unprocessable Entity (422) response. |
UnsupportedMediaTypeResult | A StatusCodeResult that when executed will produce a UnsupportedMediaType (415) response. |
ViewComponentResult | An IActionResult which renders a view component to the response. |
ViewResult | Represents an ActionResult that renders a view to the response. |
VirtualFileResult | A FileResult that on execution writes the file specified using a virtual path to the response using mechanisms provided by the host. |
留着寫 WebApi 時查詢備忘嘿嘿。
那些類型主要繼承的兩個接口:
類型 | 描述 |
---|---|
IActionResult | Defines a contract that represents the result of an action method. |
IViewComponentResult | Result type of a ViewComponent. |
注意的是,上面有些是抽象類,例如 FileResult,而 FileStreamResult 實現了 FileResult 。有些類是繼承關係。
Action 的 return ,返回的數據類型一定是上面三種。
[HttpGet]
public IEnumerable<Product> Get() { return _repository.GetProducts(); }
響應狀態碼、Json、重定向、URL 跳轉等,屬於 IActionResult。
MVC 的 Controller 與 API 的 Controller 有不少相同的地方,亦有不少不一樣的地方。
API 的 Controller 繼承 ControllerBase
MVC 的 Controller 繼承 Controller而 Controller 繼承
Controller : ControllerBase, IActionFilter, IFilterMetadata, IAsyncActionFilter, IDisposable
API 裏的 Controller 是最原始的。
API 裏的 返回類型須要實例化, new 一下; MVC 裏的返回類型,「不須要實例化」。
固然,有些例如 FileResult 是抽象類,不能被實例化。
API:
[HttpGet("returnaaa")] public async Task<IActionResult> ReturnAAA() { return new ViewResult(); return new JsonResult(new { code="test"}); return new RedirectToActionResult("DefaultController","ReturnAAA",""); return new NoContentResult("666"); return new NotFoundResult(); ... }
MVC
public async Task<IActionResult> Test() { return View(); return Json(new { code = "test" }); return RedirectToAction("DefaultController", "ReturnAAA", ""); return NoContent("666"); return NotFound(); ... }
MVC 中,Action 默認是 [HttpGet],不加也能夠被訪問到;
而 API 的Action,不加 [Httpxxx],則默認不能被訪問到。