小范笔记:ASP.NET Core API 基础知识与Axios前端提交数据
跟同事合作前后端分离项目,自己对 WebApi 的很多知识不够全,虽说不必要学全栈,可是也要了解基础知识,才能合理设计接口、API,方便与前端交接。
晚上回到宿舍后,对 WebApi 的知识查漏补缺,主要补充了 WebAPi 的一些方法、特性等如何与前端契合,如何利用工具测试 API 、Axios 请求接口。
本文主要写 WebApi 前端请求数据到 API 、后端返回处理结果,不涉及登录、跨域请求、前端 UI 等。(难一点我不会了。。。看张队的公众号,篇篇都看不懂。。。)
前提:会一点点 VUE、会一点 Axios、会一点点 Asp.net Core。
工具:Visual Studio 2019(或者其它版本) + Visual Studio Code + Swagger +Postman
由于 Visual Studio 2019 写 ASP.NET Core 页面时,没有 Vue 的智能提示,所以需要使用 VSCode 来写前端页面。
本文 代码 已发布到 GitHub https://github.com/whuanle/CZGL.IKonwWebApi
一. 微软WebApi
1. 安装 Swagger
二. 数据绑定与获取
1,默认不加
2, [FromBody]
3, [FromForm]
4, [FromHeader]
5, [FromQuery]
6, [FromRoute]
7, [FromService]
三. action 特性方法
1, [Route]
2, [Bind]
3, [Consumes]、[Produces]
4, [HttpGet]、[HttpPost]、[HttpDelete]、[HttpPut]
四,返回类型
1, 查询备忘表
2, 返回的数据类型
3, 直接返回基元或复杂数据类型
4, IActionResult 类型
一. 微软WebApi
特性 | 绑定源 |
---|---|
[FromBody] | 请求正文 |
[FromForm] | 请求正文中的表单数据 |
[FromHeader] | 请求标头 |
[FromQuery] | 请求查询字符串参数 |
[FromRoute] | 当前请求中的路由数据 |
[FromServices] | 作为操作参数插入的请求服务 |
来一张 Postman 的图片:
HTTP 请求中,会携带很多参数,这些参数可以在前端设置,例如表单、Header、文件、Cookie、Session、Token等。
那么,上面的表格正是用来从 HTTP 请求中获取数据的 “方法”
或者说 “手段”
。HttpContext 等对象不在本文讨论范围。
Microsoft.AspNetCore.Mvc
命名空间提供很多用于配置Web API 控制器的行为和操作方法的属性:
特性 | 说明 |
---|---|
[Route] | 指定控制器或操作的 URL 模式。 |
[Bind] | 指定要包含的前缀和属性,以进行模型绑定。 |
[Consumes] | 指定某个操作接受的数据类型。 |
[Produces] | 指定某个操作返回的数据类型。 |
[HttpGet] | 标识支持 HTTP GET 方法的操作。 |
[HttpPost] | 标识支持 HTTP POST 方法的操作。 |
... ... ... | ... ... ... |
WebApi 应用
首先创建一个 Asp.Net Core MVC 应用,然后在 Controllers 目录添加一个 API 控制器 DefaultController.cs
。(这里不创建 WebApi 而是 创建 MVC,通过 MVC 创建 API 控制器)。
创建后默认代码:
[Route("api/[controller]")] [ApiController] public class DefaultController : ControllerBase { }
1. 安装 Swagger
在 Nuget 中搜索 Swashbuckle.AspNetCore
,或打开 程序包管理器控制台 -> 程序包管理器控制台
,输入以下命令进行安装
Install-Package Swashbuckle.AspNetCore -Version 5.0.0-rc2
打开 Startup
文件,添加引用
using Microsoft.OpenApi.Models;
在 ConfigureServices
中添加服务,双引号文字内容随便改。
services.AddSwaggerGen(c =>{c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); });
添加中间件
app.UseHttpsRedirection();app.UseStaticFiles();app.UseCookiePolicy(); // 添加下面的内容 app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); });
访问 /swagger
可以访问到 Swagger 的 UI 界面。
为了便于查看输出和固定端口,打开 Progarm,cs
,修改内容
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseUrls("https://*:5123") .UseStartup<Startup>();
不要使用 IIS 托管运行。
注意:本文全部使用 [HttpPost] ;全局使用 JsonResult 作为返回类型。
二. 数据绑定与获取
1,默认不加
直接写 action
,不使用特性
[HttpPost("aaa")]public async Task<JsonResult> AAA(int? a, int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 2000, result = a + "|" + b }); }
打开 https://localhost:5123/swagger/index.html 查看 UI 界面
也就是说,创建一个 action
,什么都不加,默认是 query
。
通过 Postman 提交数据、测试接口
对于 Query 的 action 来说, axios 的写法
postaaa: function () {axios.post('/api/default/aaa?a=111&b=222' ) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) }
在网上查找资料时,发现有人说通过 params 添加数据也可以,不过笔者测试,貌似不行。
讲道理,别人可以,为啥我不行。。。
axios 代码:
postaaa: function () {axios.post('/api/default/aaa', { params: { a: 123, b: 234 } } ) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) }
包括下面的,都试过了,不行。
axios.post('/api/default/aaa', {a:1234,b:1122}axios.post('/api/default/aaa', {data:{a:1234,b:1122}}
把 [HttpPost]
改成 [HttpGet]
,则可以使用
axios.post('/api/default/aaa', {params: { a: 123, b: 234 } } ... ...
提示:
... ....then(res => {console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); })
.then
当请求成功时触发,请求失败时触发 catch
。res
是请求成功后返回的信息,res.data
是请求成功后服务器返回的信息。即是 action
处理数据后返回的信息。
在浏览器,按下 F12 打开控制台,点击 Console ,每次请求后,这里会打印请求结果和数据。
2, [FromBody]
官方文档解释:请求正文。[FromBody] 针对复杂类型参数进行推断。 [FromBody] 不适用于具有特殊含义的任何复杂的内置类型,如 IFormCollection 和 CancellationToken。 绑定源推理代码将忽略这些特殊类型。
算了,看得一头雾水,手动实际试试。
刚刚开始的时候,我这样使用:
public async Task<JsonResult> BBB([FromBody]int? a, [FromBody]int? b)
结果编译时就报错,提示只能使用一个 [FromBody],于是改成
[HttpPost("bbb")]public async Task<JsonResult> BBB([FromBody]int? a, int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 2000, result = a + "|" + b }); }
打开 Swagger UI 界面,刷新一下
从图片中发现,只有 b,没有 a,而且右上角有下拉框,说明了加 [FromBody] 是 json 上传。
那么说明 [FromBody] 修饰得应当是对象,而不是 字段。
修改程序如下:
// 增加一个类型public class AppJson{public int? a { get; set; } public int? b { get; set; } } [HttpPost("bbb")] public async Task<JsonResult> BBB([FromBody]AppJson ss) { if (ss.a == null || ss.b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 2000, result = ss.a + "|" + ss.b }); }
再看看微软的文档:[FromBody] 针对复杂类型参数进行推断。
,这下可理解了。。。
即是不应该对 int、string 等类型使用 [FromBody] ,而应该使用一个 复杂类型
。
而且,一个 action 中,应该只能使用一个 [FromBody] 。
打开 Swagger 界面(有修改需要刷新下界面,下面不再赘述)。
这样才是我们要的结果嘛,前端提交的是 Json 对象。
用 Postman 测试下
证实了猜想,嘿嘿,嘿嘿嘿。
前端提交的是 Json 对象,遵循 Json 的格式规范,那么 [FromBody] 把它转为 Object 对象。
前端 axios 写法:
methods: {postaaa: function () {axios.post('/api/default/bbb', { "a": 4444, "b": 5555 }) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) } }
3, [FromForm]
[HttpPost("ccc")]public async Task<JsonResult> CCC([FromForm]int? a, [FromForm]int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 200, result = a + "|" + b }); }
当然,这样写也行,多个字段或者对象都可以
[HttpPost("ccc")]public async Task<JsonResult> CCC([FromForm]AppJson ss) { if (ss.a == null || ss.b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 200, result = ss.a + "|" + ss.b }); }
根据提示,使用 Postman 进行测试
事实上,这样也行 ↓
form-data 和 x-www.form-urlencoded 都是键值形式,文件 form-data 可以用来上传文件。具体的区别请自行查询。
axios 写法(把 Content-Type 字段修改成 form-data 或 x-www.form-urlencoded )
postccc: function () {let fromData = new FormData() fromData.append('a', 111) fromData.append('b', 222) axios.post('/api/default/ccc', fromData, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) }
4, [FromHeader]
[FromHeader] 不以表单形式上传,而是跟随 Header 传递参数。
[HttpPost("ddd")]public async Task<JsonResult> DDD([FromHeader]int? a, [FromHeader]int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 200, result = a + "|" + b }); }
axios 写法
postddd: function () {axios.post('/api/default/ddd', {}, { headers: { a: 123, b: 133 } }) .then(res => { console.log(res.data) console.log(res.data.code) console.log(res.data.result) }) .catch(err => { console.error(err); }) }
需要注意的是,headers 的参数,必须放在第三位。没有要提交的表单数据,第二位就使用 {} 代替。
params 跟随 url 一起在第一位,json 或表单数据等参数放在第二位,headers 放在第三位。
由于笔者对前端不太熟,这里有说错,麻烦大神评论指出啦。
5, [FromQuery]
前面已经说了,Action 参数不加修饰,默认就是 [FromQuery] ,参考第一小节。
有个地方需要记住, Action 参数不加修饰。默认就是 [FromQuery] ,有时几种参数并在一起放到 Action 里,会忽略掉,调试时忘记了,造成麻烦。
6, [FromRoute]
获取路由规则,这个跟前端上传的参数无关;跟 URL 可以说有关,又可以说无关。
[HttpPost("fff")]public async Task<JsonResult> FFFxxx(int a,int b, [FromRoute]string controller, [FromRoute]string action) { // 这里就不处理 a和 b了 return new JsonResult(new { code = 200, result = controller+"|"+action }); }
[FromRoute] 是根据路由模板获取的,上面 API 的两个参数和路由模板的名称是对应的:
[FromRoute]string controller, [FromRoute]string action
app.UseMvc(routes =>{routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
当然,还可以加个 [FromRoute]int? id
[FromRoute] 和 [FromQuery] 区别
以此 URL 为例
https://localhost:5123/api/Default/fff?a=111&b=22
Route 会查到 controller = Default
,action = FFFxxx
。查询到的是代码里的真实名称。
Query 会查询到 a = 111
和 b = 22
那么,如果路由规则里,不在 URL 里出现呢?
[HttpPost("/ooo")]public async Task<JsonResult> FFFooo(int a, int b, [FromRoute]string controller, [FromRoute]string action) { // 这里就不处理 a和 b了 return new JsonResult(new { code = 200, result = controller + "|" + action }); }
那么,访问地址变成 https://localhost:5123/ooo
通过 Postman ,测试
说明了 [FromRoute] 获取的是代码里的 Controller 和 Action 名称,跟 URL 无关,根据测试结果推断跟路由表规则也无关。
7, [FromService]
参考 https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection?view=aspnetcore-2.2
这个是与依赖注入容器有关,跟 URL 、路由等无关。
新建一个接口、一个类
public interface ITest{string GGG { get; } } public class Test : ITest { public string GGG { get { return DateTime.Now.ToLongDateString(); } } }
在 ConfigureServices
中 注入
services.AddSingleton<ITest, Test>();
在 DefaultController
中,创建构造函数,然后
private readonly ITest ggg;public DefaultController(ITest ttt) { ggg = ttt; }
添加一个 API
[HttpPost("ggg")]public async Task<JsonResult> GGG([FromServices]ITest t) { return new JsonResult(new { code = 200, result = t.GGG }); }
访问时,什么参数都不需要加,直接访问此 API 即可。
[FromService] 跟后端的代码有关,跟 Controller 、Action 、URL、表单数据等无关。
小结:
特性可以几种放在一起用,不过尽量每个 API 的参数只使用一种特性。
优先取值 Form > Route > Query
。
IFromFile 由于文件的上传,本文就不谈这个了。
关于数据绑定,更详细的内容请参考:
https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/model-binding?view=aspnetcore-2.2
三. action 特性方法
Microsoft.AspNetCore.Mvc
命名空间提供可用于配置 Web API 控制器的行为和操作方法的属性。
下表是针对于 Controller 或 Action 的特性.
特性 | 说明 |
---|---|
[Route] | 指定控制器或操作的 URL 模式。 |
[Bind] | 指定要包含的前缀和属性,以进行模型绑定。 |
[Consumes] | 指定某个操作接受的数据类型。 |
[Produces] | 指定某个操作返回的数据类型。 |
[HttpGet] | 标识支持 HTTP GET 方法的操作。 |
... | ... |
下面使用这些属性来指定 Controller 或 Action 接受的 HTTP 方法、返回的数据类型或状态代码。
1, [Route]
在微软文档中,把这个特性称为 属性路由
,定义:属性路由使用一组属性将操作直接映射到路由模板。
请教了大神,大神解释说,ASP.NET Core 有路由规则表,路由表是全局性、唯一性的,在程序运行时,会把所有路由规则收集起来。
MVC 应用中设置路由的方法有多种,例如
app.UseMvc(routes =>{routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
[Route("Home/Index")]public IActionResult Index() { return View(); }
[Route("api/[controller]")][ApiController]public class DefaultController : ControllerBase { }
路由是全局唯一的,可以通过不同形式使用,但是规则不能发生冲突,程序会在编译时把路由表收集起来。
根据笔者经验,发生冲突,应该就是在编译阶段直接报错了。(注:笔者不敢确定)
关于路由,请参考 :
https://docs.microsoft.com/zh-cn/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.2#token-replacement-in-route-templates-controller-action-area
2, [Bind]
笔者知道这个是绑定模型的,但是对原理不太清楚。ASP.NET Core 自动生成的可读写的 Controller ,默认都是使用 [Bind] 来绑定数据。
文档定义:用于对复杂类型的模型绑定。
有下面几种相近的特性:
[BindRequired]
[BindNever]
[Bind]
微软文档提示:如果发布的表单数据是值的源,则这些属性会影响模型绑定。
就是说,上面的特性是针对类、接口等复杂类型(下面统称模型),对于 int、string 这些类型,可能出毛病。
[BindRequired] 、[BindNever] 只能应用于模型的属性,如
public class TestB{[BindNever]public int ID { get; set; } [BindRequired] public string Name { get; set; } }
但是 [BindRequired] 、[BindNever] 不在讨论范围内,这里只说 [Bind]。
[Bind] 用于类或方法(Controller、Action),指定模型绑定中应包含的模型属性。
在微软官方文档,对于[Bind] 的解释:
[Bind]
属性可用于防止“创建”方案中的过多发布情况 。 由于排除的属性设置为 NULL 或默认值,而不是保持不变,因此它在编辑方案中无法很好地工作;- 因为
Bind
特性将清除未在 某个 参数中列出的字段中的任何以前存在的数据。
一脸懵逼。
下面是我的踩坑过程,不感兴趣的话直接跳过吧。笔记笔记,记得当然是自己觉得要记的哈哈哈。
新建一个类
public class TestBind{public string A { get; set; } public string B { get; set; } public string C { get; set; } public string D { get; set; } public string E { get; set; } public string F { get; set; } public string G { get; set; } }
新建 API
[HttpPost("hhh")]public async Task<JsonResult> HHH([Bind("A,B,C")] TestBind test) { if (ModelState.IsValid == true) return new JsonResult(test); return new JsonResult(new { Code = 0, Result = "验证不通过" }); }
使用 Postman 进行,测试,发现必须使用 Json 形式,才能访问到这个 Action ,其它方式会直接 返回 错误。
{"errors": {"": [ "A non-empty request body is required." ] }, "title": "One or more validation errors occurred.", "status": 400, "traceId": "0HLO03IFQFTQU:00000007" }
通过两次 Postman 进行测试
经过测试,我猜想
ModelState.IsValid 跟模型里的验证规则有关系,跟 [Bind] 没关系(尽管用于测试的 TestB 类中没有写验证规则),因此不能使用 ModelState.IsValid 验证 [Bind] 是否符合规则。
Action 的参数:[Bind("A,B,C")] TestBind test
,刚开始的时候我以为请求的数据中必须包含 A、B、C。
测试后发现不是。。。再认真看了文档 :因为 Bind
特性将清除未在 某个 参数中列出的字段中的任何以前存在的数据。
我修改一下:
[HttpPost("hhh")]public async Task<JsonResult> HHH( string D, string E,[Bind("A,B,C")] TestBind test) { if (ModelState.IsValid == true) return new JsonResult(new { data1 = test, data2 = D, data3 = E }); return new JsonResult(new { Code = 0, Result = "验证不通过" }); }
参数变成了 string D, string E,[Bind("A,B,C")] TestBind test
使用 Swagger 进行测试:
返回结果
{"data1": {"a": "string", "b": "string", "c": "string", "d": "string", "e": "string", "f": "string", "g": "string" }, "data2": null, "data3": null }
改成
[HttpPost("hhh")]public async Task<JsonResult> HHH([Bind("A,B,C")] TestBind test, string J, string Q) { if (ModelState.IsValid == true) return new JsonResult(new { data1 = test, data2 = J, data3 = Q }); return new JsonResult(new { Code = 0, Result = "验证不通过" }); }
返回结果
{"data1": {"a": "string", "b": "string", "c": "string", "d": "string", "e": "string", "f": "string", "g": "string" }, "data2": null, "data3": null }
文档中对 [Bind] 描述最多的是:防止过多发布。
通过上面的测试,首先肯定的是一个 Action 里,有多个参数 如
[Bind("A,B,C")] TestBind test, string D, string E string J, string Q
。
注意,下面的结论是错的!
那么 D、E 因为于 除了 Test, J、Q就会无效,通过百度,[Bind] 修饰的 Action ,前端请求的数据只有 Test 里面的数据有效,其它 Query等形式一并上传的数据都会失效,防止黑客在提交数据时掺杂其它特殊参数。应该就是这样理解吧。
上面是一开始我的结论,直到多次测试,我发现是错的。
可是有一个地方不明白,
[Bind("A,B,C")]
[Bind("A,B,C,D,E,F,G")]
这两者的区别是是什么。还是没搞清楚。
突然想到 Query,当字段没有使用特性修饰时,默认为 Query 。
最终踩坑测试代码
模型类
public class TestBind{public string A { get; set; } public string B { get; set; } public string C { get; set; } public string D { get; set; } public string E { get; set; } public string F { get; set; } public string G { get; set; } }
Action
[HttpPost("hhh")]public async Task<JsonResult> HHH( string A, string B, string E, string F, string G, [Bind("A,B,C,D")] TestBind test, string C, string D, string J, string Q) { if (ModelState.IsValid == true) return new JsonResult(new { data1 = test, dataA = A, dataB = B, dataC = C, dataD = D, dataE = E, dataF = F, dataG = G, dataJ = J, dataQ = Q }); return new JsonResult(new { Code = 0, Result = "验证不通过" }); }
Swagger 测试
Postman 测试
{"data1": {"a": "111", "b": "111", "c": "111", "d": "111", "e": "111", "f": "111", "g": "111" }, "dataA": "222", "dataB": "222", "dataC": "222", "dataD": "222", "dataE": "222", "dataF": "222", "dataG": "222", "dataJ": "222", "dataQ": "222" }
再在 Swagger 或 Postman ,换着法子尝试各种不同组合的输入。
我懵逼了。试了半天试不出什么。
实在不理解 [Bind] 里,“防止过多发布” 是什么意思
[Bind("A,B,C")]
[Bind("A,B,C,D,E,F,G")]
这两者的区别是是什么。还是没搞清楚。算了,不踩了。
我再到 stackoverflow 提问题,地址 https://stackoverflow.com/questions/56884876/asp-net-core-bind-how-to-use-it/56885153#56885153
获得一个回答:
What's the difference between [Bind("A,B,C")] and [Bind("A,B,C,D,E,F,G")]?The former tells the model binder to include only the properties of TestBind named A, B and C. The latter tells the model binder to include those same properties plus D, E, F and G.Are you testing by posting data for all properties of your model? You should notice that the values you post for the excluded properties are not bound.
算了,嘿嘿,测试不出来,放弃。
3, [Consumes]、[Produces]
[Consumes("application/json")][Produces("application/json")] [Produces("application/xml")] [Produces("text/html")] ... ...
目前只了解到 [Consumes]、[Produces] 是筛选器,用来表示 Controller 或 Action 所能接受的数据类型。大概就是像下面这样使用:
[Consumes("application/json")][Produces("application/json")]public class DefaultTestController : ControllerBase{}
但是如何实际应用呢?我找了很久,都没有找到什么结果。在 stackoverflow 找到一个回答:
https://stackoverflow.com/questions/41462509/adding-the-produces-filter-globally-in-asp-net-core
4, [HttpGet]、[HttpPost]、[HttpDelete]、[HttpPut]
修饰 Action ,用来标识这个 Action 能够通过什么方式访问、访问名称。
例如:
[Route("api/[controller]")][ApiController]public class DefaultController : ControllerBase { [HttpPost("aaa")] public async Task<JsonResult> AAA(int? a, int? b) { if (a == null | b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 200, result = a + "|" + b }); } }
访问地址 https://localhost:5123/api/Default/aaa
使用时,会受到 Controller 和 Action 路由的影响。
但 本身亦可控制路由。以上面的控制器为例
[HttpPost("aaa")] //相对路径
访问地址 xxx:xxx/api/Default/aaa
[HttpPost("/aaa")] //绝对路径
访问地址 xxx:xxx/aaa
四,返回类型
1, 查询备忘表
Microsoft.AspNetCore.Mvc
命名空间中,包含控制 MVC 的各种操作方法和类型,笔者从命名空间中抽出与 MVC 或 API 返回类型有关的类型,生成表格:
类型 | 描述 |
---|---|
AcceptedAtActionResult | An ActionResult that returns a Accepted (202) response with a Location header. |
AcceptedAtRouteResult | An ActionResult that returns a Accepted (202) response with a Location header. |
AcceptedResult | An ActionResult that returns an Accepted (202) response with a Location header. |
AcceptVerbsAttribute | Specifies what HTTP methods an action supports. |
ActionResult | A default implementation of IActionResult. |
ActionResult |
A type that wraps either an TValue instance or an ActionResult.
|
BadRequestObjectResult | An ObjectResult that when executed will produce a Bad Request (400) response. |
BadRequestResult | A StatusCodeResult that when executed will produce a Bad Request (400) response. |
ChallengeResult | An ActionResult that on execution invokes AuthenticationManager.ChallengeAsync. |
ConflictObjectResult | An ObjectResult that when executed will produce a Conflict (409) response. |
ConflictResult | A StatusCodeResult that when executed will produce a Conflict (409) response. |
ContentResult | |
CreatedAtActionResult | An ActionResult that returns a Created (201) response with a Location header. |
CreatedAtRouteResult | An ActionResult that returns a Created (201) response with a Location header. |
CreatedResult | An ActionResult that returns a Created (201) response with a Location header. |
EmptyResult | Represents an ActionResult that when executed will do nothing. |
FileContentResult | Represents an ActionResult that when executed will write a binary file to the response. |
FileResult | Represents an ActionResult that when executed will write a file as the response. |
FileStreamResult | Represents an ActionResult that when executed will write a file from a stream to the response. |
ForbidResult | An ActionResult that on execution invokes AuthenticationManager.ForbidAsync. |
JsonResult | An action result which formats the given object as JSON. |
LocalRedirectResult | An ActionResult that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), or Permanent Redirect (308) response with a Location header to the supplied local URL. |
NotFoundObjectResult | An ObjectResult that when executed will produce a Not Found (404) response. |
NotFoundResult | Represents an StatusCodeResult that when executed will produce a Not Found (404) response. |
OkObjectResult | An ObjectResult that when executed performs content negotiation, formats the entity body, and will produce a Status200OK response if negotiation and formatting succeed. |
OkResult | An StatusCodeResult that when executed will produce an empty Status200OKresponse. |
PartialViewResult | Represents an ActionResult that renders a partial view to the response. |
PhysicalFileResult | A FileResult on execution will write a file from disk to the response using mechanisms provided by the host. |
RedirectResult | An ActionResult that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), or Permanent Redirect (308) response with a Location header to the supplied URL. |
RedirectToActionResult | An ActionResult that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), or Permanent Redirect (308) response with a Location header. Targets a controller action. |
RedirectToPageResult | An ActionResult that returns a Found (302) or Moved Permanently (301) response with a Location header. Targets a registered route. |
RedirectToRouteResult | An ActionResult that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), or Permanent Redirect (308) response with a Location header. Targets a registered route. |
SignInResult | An ActionResult that on execution invokes AuthenticationManager.SignInAsync. |
SignOutResult | An ActionResult that on execution invokes AuthenticationManager.SignOutAsync. |
StatusCodeResult | Represents an ActionResult that when executed will produce an HTTP response with the given response status code. |
UnauthorizedObjectResult | An ObjectResult that when executed will produce a Unauthorized (401) response. |
UnauthorizedResult | Represents an UnauthorizedResult that when executed will produce an Unauthorized (401) response. |
UnprocessableEntityObjectResult | An ObjectResult that when executed will produce a Unprocessable Entity (422) response. |
UnprocessableEntityResult | A StatusCodeResult that when executed will produce a Unprocessable Entity (422) response. |
UnsupportedMediaTypeResult | A StatusCodeResult that when executed will produce a UnsupportedMediaType (415) response. |
ViewComponentResult | An IActionResult which renders a view component to the response. |
ViewResult | Represents an ActionResult that renders a view to the response. |
VirtualFileResult | A FileResult that on execution writes the file specified using a virtual path to the response using mechanisms provided by the host. |
留着写 WebApi 时查询备忘嘿嘿。
那些类型主要继承的两个接口:
类型 | 描述 |
---|---|
IActionResult | Defines a contract that represents the result of an action method. |
IViewComponentResult | Result type of a ViewComponent. |
注意的是,上面有些是抽象类,例如 FileResult,而 FileStreamResult 实现了 FileResult 。有些类是继承关系。
2, 返回的数据类型
- 特定类型
- IActionResult 类型
- ActionResult 类型
Action 的 return ,返回的数据类型必定是上面三种。
3, 直接返回基元或复杂数据类型
[HttpGet] public IEnumerable<Product> Get() {return _repository.GetProducts(); }
4, IActionResult 类型
响应状态码、Json、重定向、URL 跳转等,属于 IActionResult。
MVC 的 Controller 与 API 的 Controller 有很多相同的地方,亦有很多不同的地方。
API 的 Controller 继承 ControllerBase
MVC 的 Controller 继承 Controller而 Controller 继承
Controller : ControllerBase, IActionFilter, IFilterMetadata, IAsyncActionFilter, IDisposable
API 里的 Controller 是最原始的。
API 里的 返回类型需要实例化, new 一下; MVC 里的返回类型,“不需要实例化”。
当然,有些例如 FileResult 是抽象类,不能被实例化。
API:
[HttpGet("returnaaa")]public async Task<IActionResult> ReturnAAA() { return new ViewResult(); return new JsonResult(new { code="test"}); return new RedirectToActionResult("DefaultController","ReturnAAA",""); return new NoContentResult("666"); return new NotFoundResult(); ... }
MVC
public async Task<IActionResult> Test(){return View(); return Json(new { code = "test" }); return RedirectToAction("DefaultController", "ReturnAAA", ""); return NoContent("666"); return NotFound(); ... }
MVC 中,Action 默认是 [HttpGet],不加也可以被访问到;
而 API 的Action,不加 [Httpxxx],则默认不能被访问到。
转载于:https://www.cnblogs.com/whuanle/p/11135299.html
小范笔记:ASP.NET Core API 基础知识与Axios前端提交数据相关推荐
- 客户要求ASP.NET Core API返回特定格式,怎么办?
当ASP.NET Core API提供给到外部系统使用时,在某些情况下,可能需要根据这些外部系统的要求来格式化数据. 比如,客户就要求API的返回值属性名必须是PascalCase(如UserName ...
- 基于ASP.NET Core api 的服务器事件发送
现如今程序员对Web API的调用已经是轻车熟路.但是传统的api调用都是拉模式,也就是主动发起请求去调用一个api. 但是程序员往往对另一种很有用的模式很陌生,即推模式. 拉模式 - 主动调用并获取 ...
- 自动给 Asp.Net Core Api 增加 ApiVersionNeutral
自动给 Asp.Net Core Api 增加 ApiVersionNeutral Intro 新增加一个 Controller 的时候,经常忘记在 Controller 上增加 ApiVersion ...
- AutoWrapper:通过有意义的响应来美化您的ASP.NET Core API
目录 介绍 默认的ASP.NET Core API响应 AutoWrapper.Core的救援 主要特点: TL,DR 给我看代码 定义自己的自定义消息 定义自己的Api异常 选项 版本1.0.0 1 ...
- ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法
ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法 一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类 ...
- 在Asp.NET Core中如何优雅的管理用户机密数据
在Asp.NET Core中如何优雅的管理用户机密数据 背景 回顾 在软件开发过程中,使用配置文件来管理某些对应用程序运行中需要使用的参数是常见的作法. 在早期VB/VB.NET时代,经常使用.ini ...
- iOS Core Bluetooth_2 基础知识
章节连接 iOS Core Bluetooth_1 概述 iOS Core Bluetooth_2 基础知识 iOS Core Bluetooth_3 用作中央设备的常用方法(1/2)[swift实现 ...
- datagrid出现相同两组数据_stata 数据操作基础知识:以一篇论文数据操作为例
stata 数据操作基础知识:以一篇论文数据操作为例 上节回顾及问题 统计学学习大图景 数据描述 分位数回归 存在的问题: 1.学了就要多使用,哪怕生搬硬套也要多用 2.时间序列的方法,大家可以操作, ...
- [WPF 基础知识系列] —— 绑定中的数据校验Vaildation
[WPF 基础知识系列] -- 绑定中的数据校验Vaildation 原文:[WPF 基础知识系列] -- 绑定中的数据校验Vaildation 前言: 只要是有表单存在,那么就有可能有对数据的校验需 ...
最新文章
- 乖乖给行人让路?学界推出无人机控制技术NMPC,可在低空中实现自主导航和避障...
- tempfile PermissionError: [Errno 13] Permission denied
- java设计模式--观察者模式(Observer)
- UCOS中断函数的编写
- Luogu P1031 均分纸牌(贪心)
- 程序员面试金典 - 面试题 17.15. 最长单词(排序+递归)
- 一个java类可以有_一个.java文件中可以有几个同级类?
- simulink接收串口数据_JLink RTT连接Simulink
- MultipartFile多文件上传
- 事业单位资产管理系统广西某单位案例:实现资产动态全过程管理
- 什么IT项目可以兼职在学校做
- jquery实现歌词滚动
- python程序填空_pygame实现成语填空游戏
- 241个jquery插件—jquery插件大全
- Poj 1125 Stockbroker Grapevine(Floyd算法求结点对的最短路径问题)
- 2022年茶艺师(中级)考试模拟100题模拟考试平台操作
- 计算机专业的一些推荐书籍
- [MSDN版本][32bit/64bit]Windows 2003 R2 With Sp2[中/英][标准/企业/数据中心]
- 【UE5】自定义环形进度条、方形进度条
- 京东新通路,零售价值增量发展的新范式