講一下Asp.net core MVC2.1 里面的 ApiControllerAttribute


先貼文章鏈接

正文

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<ActionContext, IActionResult> InvalidModelStateResponseFactory { get; set; }

        public bool SuppressModelStateInvalidFilter { get; set; }

        public bool SuppressInferBindingSourcesForParameters { get; set; }

        public bool SuppressConsumesConstraintForFormFileParameters { get; set; }
    }

所有bool類型的屬性默認都是false。Suppres有阻止的意思。可以通過以下方法進行設置。

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

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

services.Configure<ApiBehaviorOptions>(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; }
}


免責聲明!

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



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