• 讲一下Asp.net core MVC2.1 里面的 ApiControllerAttribute (转载)


    ASP.NET Core MVC 2.1 特意为构建 HTTP API 提供了一些小特性,今天主角就是 ApiControllerAttribute. (注:文章是18年2月份的,所以文章提到了core2.1还没发布)。

    本文参考自:Exploring the ApiControllerAttribute and its features for ASP.NET Core MVC 2.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")]的方式。

    顺便说一下,[Route("XXX")]特性标签是支持定义[controller][action]路由参数的,例如:

    [ApiController]
    [Route("api/[controller]/[action]")]
    public class BookController : Controller
    {
        [HttpPost]
        public Book AddBook(Book book)
        {
            //模拟做一些数据操作
    
            return book;
        }
    
        [HttpPost]
        public Book UpdateBook(Book book)
        {
            //模拟做一些数据操作
    
            return book;
        }
    
        [HttpGet]
        public Book GetBookById(string bookId)
        {
            //模拟做一些数据操作
            var book = new Book();
    
            return book;
        }
    
        [HttpGet]
        public Book GetBookByName(string bookName)
        {
            //模拟做一些数据操作
            var book = new Book();
    
            return book;
        }
    }

    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; }
    }

    原文链接

  • 相关阅读:
    指令周期与机器周期
    MFC使用Access数据库
    函数指针的用途
    大端模式和小端模式
    Matlab信号展开
    EL表达式的11个内置对象
    JSP 4个域对象、7个动作指令、9个内置对象
    阿里巴巴java代码规范
    HDDATA基本注意事项
    SVN相关
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/10346802.html
Copyright © 2020-2023  润新知