我们先创建一个 webAPI 项目, 看看官方给的模板到底有哪些东西
官方给出的模板:
- [Route("api/[controller]")]
- [ApiController]
- public class ValuesController : ControllerBase
- {
- // GET API/values
- [HttpGet]
- public ActionResult<IEnumerable<string>> Get()
- {
- return new string[] { "value1", "value2" };
- }
- // GET API/values/5
- [HttpGet("{id}")]
- public ActionResult<string> Get(int id)
- {
- return "value";
- }
- // POST API/values
- [HttpPost]
- public void Post([FromBody] string value)
- {
- }
- // PUT API/values/5
- [HttpPut("{id}")]
- public void Put(int id, [FromBody] string value)
- {
- }
- // DELETE API/values/5
- [HttpDelete("{id}")]
- public void Delete(int id)
- {
- }
- }
同时, 在 Startup 类中注册了 Mvc 中间件.
- public void Configure(IApplicationBuilder App, IHostingEnvironment env)
- {
- if (env.IsDevelopment())
- {
- App.UseDeveloperExceptionPage();
- }
- else
- {
- // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
- App.UseHsts();
- }
- App.UseHttpsRedirection();
- App.UseMvc();
- }
实际上, 继承 ControllerBase , 特性 [Route] [ApiController] 都是为了提供一些便利功能, 一个最 "轻量" 的 WebAPI 是这样的:
新建一个 TestController:
- public class TestController
- {
- public string Get()
- {
- return "hello world";
- }
- }
啥也没有, 很干净.
注册 Mvc 中间件时添加路由:
- //App.UseMvc(route => { route.MapRoute("default", "api/{controller}"); });// 不能这样写, 这种最轻量的方式, 不支持 Restful 风格的请求方式
- App.UseMvc(route => { route.MapRoute("default", "api/{controller}/{action}"); });
测试:
当然, 我们也可以不在 注册 Mvc 中间件的时候添加路由, 还是像官方推荐的那样, 在控制器上利用路由特性, 这种方式就支持 Restful 风格的请求方式了.
- [Route("api/[controller]")]
- public class TestController
- {
- public string Get()
- {
- return "hello world";
- }
- }
那 ControllerBase 提供了哪些便利功能呢? 看源码就明白了:
截一小部分图:
[ApiController] 特性则提供如下便利功能:
绑定源参数推理
当没有 [ApiController] 特性时, 参数绑定都默认从 QueryString 获取. 假设有如下控制器和实体类:
- [Route("api/[controller]")]
- public class TestController
- {
- public string Get(Person person, int id, string name, Student student)
- {
- var temp = new { person, id, name, student };
- return JsonConvert.SerializeObject(temp);
- }
- }
- public class Person
- {
- public int Id { get; set; }
- public string Name { get; set; }
- }
- public class Student
- {
- public int Id { get; set; }
- public string Name { get; set; }
- }
请求结果:
可以看到, 所有的参数都绑定上了.
但工作中, 复杂类型我们一般都是 post 提交, 写在 body 里面.
现在我们改用 post 提交 , 稍微修改一下 action :
- [Route("api/[controller]")]
- public class TestController
- {
- public string Get(Person person)
- {
- return JsonConvert.SerializeObject(person);
- }
- }
请求:
结果没有绑定上:
这也证明了 在没有 [ApiController] 特性时, 默认都是从 QueryString 获取参数来绑定.
上述例子要想绑定成功, 需要给 action 的入参打上 [FromBody] 特性:
- public string Get([FromBody]Person person)
- {
- return JsonConvert.SerializeObject(person);
- }
请求结果:
ASP.NET Core 的绑定特性似乎比 ASP.NET 多了一些, 下面是官网给的:
如果 Controller 上应用了 [ApiController] 特性, 那么框架会根据参数类型自动选择绑定特性.
现在我们给 TestController 应用 [ApiController] 特性, 同时删掉 Action 上的 [FromBody] 特性:
- [Route("api/[controller]")]
- [ApiController]
- public class TestController
- {
- public string Get(Person person)
- {
- return JsonConvert.SerializeObject(person);
- }
- }
请求结果:
至于自动选择绑定特性的规则, 我也没有全部测试, 不过我感觉应该和 ASP.NET 是一样的.
但是, 有个地方不一样, 不知道算不算 ASP.NET Core 的优化:
对于之前的 ASP.NET WebAPI , 如果 QueryString 的参数没有涵盖 Action 上定义的所有参数, 那么是请求不到该 Action 的.
比如, 这是一个 ASP.NET WebAPI 控制器, Get 方法定义了两个入参:
- public class TestController : ApiController
- {
- public string Get(int id,string name)
- {
- var temp = new {id, name};
- return JsonConvert.SerializeObject(temp);
- }
- }
那么, 如果我们的 QueryString 只传递了其中一个, 是请求不到 Get 方法的.
但是, ASP.NET Core 是可以的:
上面提到的这个自动选择绑定特性的规则, 可以通过代码来禁止(红色部分, 其余的是禁用 [ApiController] 特性提供的其他便利功能的):
- services.AddMvc()
- .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
- .ConfigureApiBehaviorOptions(options =>
- {
- options.SuppressConsumesConstraintForFormFileParameters = true;
- options.SuppressInferBindingSourcesForParameters = true;
- options.SuppressModelStateInvalidFilter = true;
- options.SuppressMapClientErrors = true;
- options.ClientErrorMapping[404].Link =
- "https://httpstatuses.com/404";
- });
至于其他便利功能, 可以查看官方文档:
其实我写的这些, 大多数都是抄的官方文档.
来源: https://www.cnblogs.com/refuge/p/10232544.html