我们先创建一个 WebAPI 项目,看看官方给的模板到底有哪些东西

 

官方给出的模板:

  1. [Route("api/[controller]")]
  2. [ApiController]
  3. public class ValuesController : ControllerBase
  4. {
  5. // GET api/values
  6. [HttpGet]
  7. public ActionResult<IEnumerable<string>> Get()
  8. {
  9. return new string[] { "value1", "value2" };
  10. }
  11. // GET api/values/5
  12. [HttpGet("{id}")]
  13. public ActionResult<string> Get(int id)
  14. {
  15. return "value";
  16. }
  17. // POST api/values
  18. [HttpPost]
  19. public void Post([FromBody] string value)
  20. {
  21. }
  22. // PUT api/values/5
  23. [HttpPut("{id}")]
  24. public void Put(int id, [FromBody] string value)
  25. {
  26. }
  27. // DELETE api/values/5
  28. [HttpDelete("{id}")]
  29. public void Delete(int id)
  30. {
  31. }
  32. }

同时,在 Startup 类中注册了 Mvc 中间件.

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  2. {
  3. if (env.IsDevelopment())
  4. {
  5. app.UseDeveloperExceptionPage();
  6. }
  7. else
  8. {
  9. // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
  10. app.UseHsts();
  11. }
  12. app.UseHttpsRedirection();
  13. app.UseMvc();
  14. }

 

实际上, 继承 ControllerBase ,特性 [Route] [ApiController] 都是为了提供一些便利功能,一个最”轻量”的 WebAPI 是这样的:

新建一个 TestController:

  1. public class TestController
  2. {
  3. public string Get()
  4. {
  5. return "hello world";
  6. }
  7. }

啥也没有,很干净.

注册 Mvc 中间件时添加路由:

  1. //app.UseMvc(route => { route.MapRoute("default", "api/{controller}"); });//不能这样写,这种最轻量的方式,不支持 Restful 风格的请求方式
  2. app.UseMvc(route => { route.MapRoute("default", "api/{controller}/{action}"); });

测试:

 

当然,我们也可以不在 注册 Mvc 中间件的时候添加路由,还是像官方推荐的那样,在控制器上利用路由特性,这种方式就支持 Restful 风格的请求方式了.

  1. [Route("api/[controller]")]
  2. public class TestController
  3. {
  4. public string Get()
  5. {
  6. return "hello world";
  7. }
  8. }

 

 

那 ControllerBase 提供了哪些便利功能呢?看源码就明白了:

截一小部分图:

 

[ApiController] 特性则提供如下便利功能:

当没有[ApiController]特性时,参数绑定都默认从QueryString获取.假设有如下控制器和实体类:

  1. [Route("api/[controller]")]
  2. public class TestController
  3. {
  4. public string Get(Person person, int id, string name, Student student)
  5. {
  6. var temp = new { person, id, name, student };
  7. return JsonConvert.SerializeObject(temp);
  8. }
  9. }
  1. public class Person
  2. {
  3. public int Id { get; set; }
  4. public string Name { get; set; }
  5. }
  6. public class Student
  7. {
  8. public int Id { get; set; }
  9. public string Name { get; set; }
  10. }

请求结果:

 

可以看到,所有的参数都绑定上了.

但工作中,复杂类型我们一般都是 post 提交,写在 body 里面.

现在我们改用post提交 ,稍微修改一下 action :

  1. [Route("api/[controller]")]
  2. public class TestController
  3. {
  4. public string Get(Person person)
  5. {
  6. return JsonConvert.SerializeObject(person);
  7. }
  8. }

请求:

 

结果没有绑定上:

 

 这也证明了 在没有 [ApiController] 特性时,默认都是从 QueryString 获取参数来绑定.

 上述例子要想绑定成功,需要给 action 的入参打上 [FromBody] 特性:

  1. public string Get([FromBody]Person person)
  2. {
  3. return JsonConvert.SerializeObject(person);
  4. }

请求结果:

 

 

ASP.NET Core 的绑定特性似乎比 ASP.NET 多了一些,下面是官网给的:

 

如果 Controller 上应用了 [ApiController] 特性,那么框架会根据参数类型自动选择绑定特性.

现在我们给 TestController 应用 [ApiController] 特性,同时删掉 Action 上的 [FromBody] 特性:

  1. [Route("api/[controller]")]
  2. [ApiController]
  3. public class TestController
  4. {
  5. public string Get(Person person)
  6. {
  7. return JsonConvert.SerializeObject(person);
  8. }
  9. }

 

 请求结果:

 

至于自动选择绑定特性的规则,我也没有全部测试,不过我感觉应该和 ASP.NET 是一样的.

但是,有个地方不一样,不知道算不算 ASP.NET Core 的优化:

对于之前的 ASP.NET WebAPI ,如果 QueryString 的参数没有涵盖 Action 上定义的所有参数,那么是请求不到该 Action 的.

比如,这是一个 ASP.NET WebAPI 控制器,Get 方法定义了两个入参:

  1. public class TestController : ApiController
  2. {
  3. public string Get(int id,string name)
  4. {
  5. var temp = new {id, name};
  6. return JsonConvert.SerializeObject(temp);
  7. }
  8. }

那么,如果我们的 QueryString 只传递了其中一个,是请求不到 Get 方法的.

 

但是, ASP.NET Core 是可以的:

 

 

上面提到的这个自动选择绑定特性的规则,可以通过代码来禁止(红色部分,其余的是禁用 [ApiController] 特性提供的其他便利功能的):

  1. services.AddMvc()
  2. .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
  3. .ConfigureApiBehaviorOptions(options =>
  4. {
  5. options.SuppressConsumesConstraintForFormFileParameters = true;
  6. options.SuppressInferBindingSourcesForParameters = true;
  7. options.SuppressModelStateInvalidFilter = true;
  8. options.SuppressMapClientErrors = true;
  9. options.ClientErrorMapping[404].Link =
  10. "https://httpstatuses.com/404";
  11. });

至于其他便利功能,可以查看官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/?view=aspnetcore-2.2

其实我写的这些,大多数都是抄的官方文档.

posted on 2019-01-07 17:40 热敷哥 阅读() 评论() 编辑 收藏

版权声明:本文为refuge原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/refuge/p/10232544.html