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

原文链接

讲一下Asp.net core MVC2.1 里面的 ApiControllerAttribute (转载)的更多相关文章

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

    先贴文章链接 正文 ASP.NET Core MVC 2.1 特意为构建 HTTP API 提供了一些小特性,今天主角就是 ApiControllerAttribute. (注:文章是18年2月份的, ...

  2. 在ASP.NET Core中怎么使用HttpContext.Current (转载)

    一.前言 我们都知道,ASP.NET Core作为最新的框架,在MVC5和ASP.NET WebForm的基础上做了大量的重构.如果我们想使用以前版本中的HttpContext.Current的话,目 ...

  3. 如何ASP.NET Core Razor中处理Ajax请求[转载]

    在ASP.NET Core Razor(以下简称Razor)刚出来的时候,看了一下官方的文档,一直没怎么用过. 今天闲来无事,准备用Rozor做个项目熟练下,结果写第一个页面就卡住了..折腾半天才搞好 ...

  4. ASP.NET Core StaticFiles中间件修改wwwroot(转载)

    ASP.NET Core 开发,中间件(StaticFiles)的使用,我们开发一款简易的静态文件服务器.告别需要使用文件,又需要安装一个web服务器.现在随时随地打开程序即可使用,跨平台,方便快捷. ...

  5. spring源码分析-core.io包里面的类

    前些日子看<深入理解javaweb开发>时,看到第一章java的io流,发觉自己对io流真的不是很熟悉.然后看了下JDK1.7中io包的一点点代码,又看了org.springframewo ...

  6. asp.net core合并压缩资源文件(转载)

    在asp.net core中使用BuildBundlerMinifier合并压缩资源文件 在asp.net mvc中可以使用Bundle来压缩合并css,js 不知道的见:http://www.cnb ...

  7. ASP.NET Core MVC/WebAPi 模型绑定探索 转载https://www.cnblogs.com/CreateMyself/p/6246977.html

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  8. ASP.NET Core 发布至Linux生产环境 Ubuntu 系统

    ASP.NET Core 发布至Linux生产环境 Ubuntu 系统,之前跟大家讲解了 dotnet publish 发布,而没有将整个系统串起来. 今天就跟大家综合的讲一下ASP.NET Core ...

  9. ASP.NET Core 应用程序Startup类介绍

    Startup类配置服务和应用程序的请求管道. Startup 类 ASP.NET Core应用程序需要一个启动类,按照惯例命名为Startup.在主程序的Web Host生成器(WebHostBui ...

随机推荐

  1. ​《数据库系统概念》4-DDL、集合运算、嵌套子查询

    一.DDLa) SQL Data DefinitionSQL的基本数据类型有char(n).varchar(n).int.smallint.numeric(p,d).real,double preci ...

  2. Django中使用bookstarp框架(4)

    Django中使用bookstarp框架(4) 注意:要使用bookstarp框架前,要先有css的基础 因为主要是研究后台的使用方法,就引入前端的框架,简化html上的耗时(主要是不想把时间浪费在前 ...

  3. python进程间通信--信号Signal

    信号signal 是python进程间通信多种机制中的其中一种机制.可以对操作系统进程的控制,当进程中发生某种原因而中断时,可以异步处理这个异常. 信号通过注册的方式‘挂’在一个进程中,并且不会阻塞该 ...

  4. JavaScript大杂烩17 - 性能优化

    在上一节推荐实践中其实很多方面是与效率有关的,但那些都是语言层次的优化,这一节偏重学习大的方面的优化,比如JavaScript脚本的组织,加载,压缩等等. 当然在此之前,分析一下浏览器的特征还是很有意 ...

  5. Backbone.js学习之旅(一)

    前言 刚到粑粑公司,就学习各种框架,进行各种开发,为了纪念挥泪的青春,只好写下…… 希望能合您胃口^_^!!! The First(文件准备) backobone 强制依赖于 underscore.j ...

  6. 洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

    type函数的隐藏属性 相信大家都知道内置函数type是用来查看对象的数据类型的.例: 那比如我对int类查看类型呢? 有朋友会说,int是内置类啊,用自定义的应该不会这样,我们自定义一个类呢? 还是 ...

  7. 微信小程序-下拉事件(onPullDownRefresh)不触发

    1.app.json 没有配置 "window": { /* 其他配置信息 */ "enablePullDownRefresh":true } 2.scroll ...

  8. iptable用法

    一:添加屏蔽IP #禁止此IP访问服务器iptables -I INPUT -s 1.2.3.4 -j DROP或iptables -A INPUT -s 1.2.3.4 -j DROP#禁止服务器访 ...

  9. 用Python实现数据结构之树

    树 树是由根结点和若干颗子树构成的.树是由一个集合以及在该集合上定义的一种关系构成的.集合中的元素称为树的结点,所定义的关系称为父子关系.父子关系在树的结点之间建立了一个层次结构.在这种层次结构中有一 ...

  10. Windows 10更新后频繁死机、假死(SSD)

    问题详情: 新版的Windows改变了更新策略,无法设置为不更新系统.在系统更新后,之前的部分设定也会神奇丢失,包括之前设定的解决的这个卡顿问题.于是重新爬文章找解决方案,在这里做个备份. 本文章内容 ...