講一下Asp.net core MVC2.1 裡面的 ApiContr

Bacer發表於2021-09-09

先貼文章

正文

ASP.NET Core MVC 2.1 特意為構建 HTTP API 提供了一些小特性,今天主角就是 ApiControllerAttribute. (注:文章是18年2月份的,所以文章提到了core2.1還沒釋出)。

0. ApiControllerAttribute 繼承自 ControllerAttribute

ASP.NET Core MVC 已經有了ControllerAttribute,這個用來標註一個型別是否是Controller。標註了之後框架就知道哪些是系統裡面的Controller了。(框架也有其他方法來獲取程式裡面的Controller,所以,這個ControllerAttribute不是必須的)。

ApiControllerAttributeControllerAttribute的子類,所以,框架在處理Controller發現的時候和ControllerAttribute標註的物件是一樣的。

但是,因為ApiControllerAttribute 實現了IApiBehaviorMetadata介面,所以提供了一些額外的特這些特性是以HTTP Api為出發點的。下面介紹一下這些特性。

1. 自動模型狀態驗證

這個是重點,框架會幫你自動驗證model的state,也就是ModelState.(注:不過我就是因為用FluentValidation的時候模型驗證不管用了出問題了才找到這篇文章的).

框架會為你自動註冊ModelStateInvalidFilter,這個會執行在OnActionExecuting事件裡面(具體來說:在action執行之前,model繫結之後)。他內部會檢查ModelState是否為Valid,如果為InValid會直接返回400 BadRequest,這樣就沒有必要執行後面的程式碼,提高效率。

它會自動把model state 放到response裡面,content type 是application/problem+json。當然你也可以自定義,因為畢竟你會有自己的驗證,後文會講。

下面,我們先來舉個例子說一下。

  • 之前的寫法

[Route("[controller]")]public class BookController : Controller{
    [HttpPost("")]    public IActionResult PostBook([FromBody]Book book)    {        if (ModelState.IsValid) //判斷狀態
        {            return BadRequest(ModelState);
        }        //其他程式碼。。。
    }
}
  • 現在可以這麼寫

[ApiController]
[Route("[controller]")]public class BookController : Controller{
    [HttpPost("")]    public IActionResult PostBook(Book book)    {        //直接寫,不用驗證modelstate
    }
}

順道說一下,ModelStateInvalidFilter是個公共類,所以,不用ApiControllerAttribute也可以使用它。

2.引數繫結策略的自動推斷

另一個非常有用的特性是action裡面的引數的模型繫結可以自動推斷。

ASP.NET Core MVC裡面有一個比較令人惱怒的問題你需要手動給引數指定[FromBody]這個特性,以便讓系統知道如何從Request body裡面反序列化他們,比如反序列化json。因此,寫了很多第三方的庫來解決這個問題,比如:

  • 其他不寫了,,就舉個例子

現在,這些可以自動解決了。

除此之外,如果一個引數在route裡面定義了,他會自動從先從path,也就是url上嘗試繫結,不行的話會去從查詢引數上繫結。IFormFlie預設從form表單上繫結獲取。

下面看程式碼:

  • 之前

[Route("[controller]")]public class BookController : Controller{
    [HttpPost("")]    public IActionResult PostBook([FromBody]Book book)    {        // 寫程式碼
    }
}
  • 現在

[ApiController]
[Route("[controller]")]public class BookController : Controller{
    [HttpPost("")]    public IActionResult PostBook(Book book)//FromBody沒必要寫了
    {        // 寫程式碼
    }
}

3. 處理multipart/form-data請求

如果你的action裡面的一個引數指定了[FromFile]特性(這通常是用於檔案上傳的),框架會自動假設請求是multipart/form-data。這個是用來解決社群裡面提的這個。

不過這個也是可選的,只要你自己定義在action上定義一下[Consumes(...)]

4.其他

有兩個注意點:

  1. ApiExplorer 的可見性。 預設所有的controller對ApiExplorer都是可見的,所以,不影響swagger 等的生成。

  2. 只是一個基於特性的路由。集中的路由機制不會應用在API controller,框架要求只能使用基於特性的路由,即在action上指定[Route("XXX")]的方式。

5. 行為自定義

像MVC框架的大部分元件一樣,ApiControllerAttribute的行為是高度可自定義的。首先,上面說的大部分內容都是可以簡單的用 on/off 來切換。

具體的設定是在startup方法裡面透過ApiBehaviorOptions來實現,先來看一下這個類。

    public class ApiBehaviorOptions
    {        public Func InvalidModelStateResponseFactory { get; set; }        public bool SuppressModelStateInvalidFilter { get; set; }        public bool SuppressInferBindingSourcesForParameters { get; set; }        public bool SuppressConsumesConstraintForFormFileParameters { get; set; }
    }

所有bool型別的屬性預設都是false。Suppres有阻止的意思。可以透過以下方法進行設定。

services.Configure(options =>
{
    options.SuppressModelStateInvalidFilter = true;
    options.SuppressConsumesConstraintForFormFileParameters = true;
});

來看一下InvalidModelStateResponseFactory屬性,他是一個返回IActionResult的Func,透過他,我們可以注入自己的委託來實現需要的返回型別,舉個例子。

services.Configure(options =>
{
    options.InvalidModelStateResponseFactory = actionContext => 
    {        var errors = actionContext.ModelState
            .Where(e => e.Value.Errors.Count > 0)
            .Select(e => new Error
            {
            Name = e.Key,
            Message = e.Value.Errors.First().ErrorMessage
            }).ToArray(); 
        return new BadRequestObjectResult(errors);
    }
}); 
class Error{    public string Name { get; set; } 
    public string Message { get; set; }
}

原文出處:https://www.cnblogs.com/sheldon-lou/p/9495377.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2768/viewspace-2811910/,如需轉載,請註明出處,否則將追究法律責任。

相關文章