纲手对鸣人的惩罚1,怎样重装win7系统,男人与鸡
跟同事合作前后端分离项目,自己对 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
特性 | 绑定源 |
---|---|
[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
{
}
在 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 作为返回类型。
直接写 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 });
}
也就是说,创建一个 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 ,每次请求后,这里会打印请求结果和数据。
官方文档解释:请求正文。[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);
})
}
}
[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- 都是键值形式,文件 form-data 可以用来上传文件。具体的区别请自行查询。
axios 写法(把 content-type 字段修改成 form-data 或 x- )
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);
})
}
[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 放在第三位。
由于笔者对前端不太熟,这里有说错,麻烦大神评论指出啦。
前面已经说了,action 参数不加修饰,默认就是 [fromquery] ,参考第一小节。
有个地方需要记住, action 参数不加修饰。默认就是 [fromquery] ,有时几种参数并在一起放到 action 里,会忽略掉,调试时忘记了,造成麻烦。
获取路由规则,这个跟前端上传的参数无关;跟 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 无关,根据测试结果推断跟路由表规则也无关。
参考
这个是与依赖注入容器有关,跟 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 由于文件的上传,本文就不谈这个了。
关于数据绑定,更详细的内容请参考:
microsoft.aspnetcore.mvc
命名空间提供可用于配置 web api 控制器的行为和操作方法的属性。
下表是针对于 controller 或 action 的特性.
特性 | 说明 |
---|---|
[route] | 指定控制器或操作的 url 模式。 |
[bind] | 指定要包含的前缀和属性,以进行模型绑定。 |
[consumes] | 指定某个操作接受的数据类型。 |
[produces] | 指定某个操作返回的数据类型。 |
[httpget] | 标识支持 http get 方法的操作。 |
... | ... |
下面使用这些属性来指定 controller 或 action 接受的 http 方法、返回的数据类型或状态代码。
在微软文档中,把这个特性称为 属性路由
,定义:属性路由使用一组属性将操作直接映射到路由模板。
请教了大神,大神解释说,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
{
}
路由是全局唯一的,可以通过不同形式使用,但是规则不能发生冲突,程序会在编译时把路由表收集起来。
根据笔者经验,发生冲突,应该就是在编译阶段直接报错了。(注:笔者不敢确定)
关于路由,请参考 :
笔者知道这个是绑定模型的,但是对原理不太清楚。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 提问题,地址
获得一个回答:
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.
算了,嘿嘿,测试不出来,放弃。
[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 找到一个回答:
修饰 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
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 。有些类是继承关系。
action 的 return ,返回的数据类型必定是上面三种。
[httpget]
public ienumerable<product> get()
{
return _repository.getproducts();
}
响应状态码、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],则默认不能被访问到。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Blazor server side 自家的一些开源的, 实用型项目的进度之 CEF客户端
.NET IoC模式依赖反转(DIP)、控制反转(Ioc)、依赖注入(DI)
vue+.netcore可支持业务代码扩展的开发框架 VOL.Vue 2.0版本发布
网友评论