您现在的位置是:首页 > 技术教程 正文

【.Net core】ajax+.Net core Web API 场景下的请求参数传递示例

admin 阅读: 2024-03-27
后台-插件-广告管理-内容页头部广告(手机)

写在前面

在文档开始前需要明确的是两个问题:
1、http协议下的 Get方式可不可以携带body参数?
2、jquery ajax发起请求使用get方式,可不可以携带body参数?
在面试题中最常见的,就是get请求和post请求有什么不同,回答一般是,get通过url传递参数,post通过body传递参数。get传参大小有限制,post无限制。但实际上,Http协议中 Get是可以通过body携带参数的。具体自行百度,文中不做赘述。
至于为什么我们使用ajax发起get请求时,并不能将参数放到body中。原因是ajax是基于XMLHttpRequest封装的请求插件。而XmlHttpRequest的官方规范中声明了,当方法为get head 时。会将请求body置为null,如下图
image.png
我们知道ajax post参数是放到data中,而get请求中的data参数ajax是如何处理的呢?源码如下:我们可以看到先判断当前请求是否存在content也就是通过判断当前请求的方法来判断当前是否存在请求正文,然后会将data拼接到url后,再删除data属性
image.png


image.png
所以我们可以得出,两点结论:
1、Http协议中Get请求可以通过body传递参数
2、jquery ajax 并不支持get通过body参数,会将data编入url中
此外,我们都知道ajax 默认请求方式是get ,默认内容类型contentType 是:contentType: “application/x-www-form-urlencoded; charset=UTF-8”,而这种内容类型会将将请求参数以key1=value1&key2=value2这种键值对的方式进行组织,并放入到请求体中。
在明确这两点的基础上,再来看使用ajax请求webApi时如何传参

1、Get方式请求

1、GET-基础类型参数

正确后端代码

/// /// 基础类型做参数 /// /// /// [HttpGet] [Route("GetParam")] public string GetParam(string param,int param1,DateTime param2) { return param,param1,param2; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

正确前端代码示例

// GET请求使用data传递参数,实际上ajax会将data内键值对追加到url上 // 需要注意,这里 contentType不要指定"application/json",因为参数都是通过url传递的 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetParam", data: {param: 1,param1:2,param2:new Date().toDateString()}, success: function (data) { layer.msg(JSON.stringify(data)); } }); // 或url拼接 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetParam?param=1¶m1=2¶m2=2023-02-09", success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

调试代码截图

GIF 2023-2-9 11-15-51.gif

2、GET-实体类型参数(不推荐)

首先阐明不推荐这样传参的原因:
Get请求长度限制问题。
此处简单介绍get post 参数长度问题,要明确的一点是,HTTP协议对于GET \POST 传参并无任何长度限制。那么为什么面试题中get和post 的不同点都会提到,get方式传参,长度有限制?这是因为针对get请求,浏览器层面进行了参数的长度限制,确切的说是url长度限制。因为当我们使用ajax时,即使通过data传递参数,ajax还是会将data中的参数追加到请求的url中去。并且不同的浏览器get请求url长度限制不同。
同样的,对于post请求的参数大小限制,HTTP协议并无要求,但不同的服务器,不同的后台框架,都会有默认的大小限制。但是这个限制要远比浏览器层面对于get请求长度限制大得多。
所以当我们传递复杂类型参数时,如果我们能够预估到参数会很大,就尽量选择post方式传递参数,从而避免浏览器层面对get请求进行url长度限制。

错误后端代码示例

/// /// 实体类型做参数 /// /// /// [HttpGet] [Route("GetEntity")] public string GetEntity(ParamEntity entity) { return entity.Param1 + entity.Param2 +entity.Param2; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

错误前端代码示例

// 通过data传递,我们知道ajax会将data中参数自动以&形式追加到请求url中,所以此方式等同与下面 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetParam", data: {param: 1,param1:2,param2:new Date().toDateString()}, success: function (data) { layer.msg(JSON.stringify(data)); } }); // 或url拼接 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetParam?param=1¶m1=2¶m2=2023-02-09", success: function (data) { layer.msg(JSON.stringify(data)); } }); // 或contenetType = application/json + url拼接 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetEntity", contentType: "application/json", data: {param: 1,param1:2,param2:'2023-02-09'}, success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

错误调试代码截图

当使用ajax 默认的contentType 时,会发现错误代码415,也就是咱们的contentType不对
GIF 2023-2-9 16-31-00.gif
将contentType配置为application/json时,请求结果如下
image.png
错误代码为400,为参数类型不匹配。

综上可以看出,当WebApi 的get请求参数为实体类时,前端ajax 并不能进行正确请求。这个时候就我们可以通过[FromUri] 和[FromQuery] [FromBody]绑定源特性,来获取实体类型参数。
1、[FromUri] 是.net Framework版本 中提供的一个绑定源特性,
2、[FromQuery]是net core 提供。与前者作用相同,都是从url?后的查询字符串中,进行模型绑定。下文中以FromQuery 进行演示。

FromQuery特性获取实体参数

正确后端代码示例
/// /// FromQuery 接受实体类型做参数 /// /// /// [HttpGet] [Route("GetEntity")] public string GetEntity([FromQuery]ParamEntity entity) { return entity.Param1 + entity.Param2 +entity.Param2; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
正确前端代码示例
$.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetEntity", data: {param: 1,param1:2,param2:'2023-02-09'}, success: function (data) { layer.msg(JSON.stringify(data)); } }); // 或contentType:'application/json' 依然可以 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetEntity", contentType:'application/json', data: {param: 1,param1:2,param2:'2023-02-09'}, success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
调试代码截图

image.png

3、GET-数组类型参数(不推荐)

我们知道,string[] arrays 这种数据类型当然不属于基础类型,所以我们直接使用FromQuery 方式来接收数组参数。

正确后端代码示例

/// /// FromQuery 接收数组类型 /// /// /// [HttpGet] [Route("GetArrays")] public string GetEntity([FromQuery]string[] arrays) { return arrays.ToString(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

错误前端代码示例

// 后端参数名称arrays ,请求实际url为 http://localhost:5000/TestGet/GetArrays?arrays%5B%5D=1&arrays%5B%5D=2&arrays%5B%5D=3 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetArrays", data: {arrays:[1,2,3]}, success: function (data) { layer.msg(JSON.stringify(data)); } }); // 直接传递数组,请求实际url为 http://localhost:5000/TestGet/GetArrays?undefined=&undefined=&undefined= $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetArrays", data: [1,2,3], success: function (data) { layer.msg(JSON.stringify(data)); } }); // 我们知道FromQuery 是从url中获取值,然后绑定到对应的model中,观察这两种方式的实际url,发现名称都不是arrays
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

正确前端代码示例

// 1 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetArrays?arrays=1&arrays=2", success: function (data) { layer.msg(JSON.stringify(data)); } }); // 2 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetArrays?arrays[0]=1&arrays[1]=2", success: function (data) { layer.msg(JSON.stringify(data)); } }); // 3 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetArrays?[0]=1&[1]=2", success: function (data) { layer.msg(JSON.stringify(data)); } }); // 4 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetArrays?arrays[a]=1&arrays[b]=2&arrays.index=a&arrays.index=b", // contentType:'application/json', success: function (data) { layer.msg(JSON.stringify(data)); } }); // 5 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetArrays?[a]=1&[b]=2&index=a&index=b", // contentType:'application/json', success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

调试代码截图

image.png

4、GET-实体List参数(不推荐)

正确后端代码示例

/// /// FromQuery 接收实体List类型 /// /// /// [HttpGet] [Route("GetEntityList")] public string GetEntityList([FromQuery]List<ParamEntity> entities) { return entities.Count.ToString(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

正确前端代码示例

// 1 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetEntityList?entities[0].param=1&entities[0].param1=2&entities[0].param2=2023-02-09", success: function (data) { layer.msg(JSON.stringify(data)); } }); // 2 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetEntityList?[0].param=1&[0].param1=2&[0].param2=2023-02-09", success: function (data) { layer.msg(JSON.stringify(data)); } }); // 3 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetEntityList?entities[a].param=1&entities[a].param1=2&entities.index=a", // contentType:'application/json', success: function (data) { layer.msg(JSON.stringify(data)); } }); // 4 $.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetEntityList?[a].param=1&[a].param1=2&index=a", // contentType:'application/json', success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

调试代码截图

image.png

5、GET-Dictionary参数(不推荐)

正确后端代码示例

/// /// FromQuery Dictionary参数 /// /// /// [HttpGet] [Route("GetDictionary")] public string GetDictionary([FromQuery] Dictionary<string,string> dict) { return dict.ToString(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

正确前端代码示例

$.ajax({ type: "get", url: "http://localhost:5000/TestGet/GetDictionary", data: {param:1,param1:2,param2:'2023-02-09'}, success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

调试代码截图

image.png

2、Post方式请求

如果你使用的版本是net core 3.0 ,请手动安装Microsoft.AspNetCore.Mvc.NewtonsoftJson,注意不是NewtonsoftJson包,因为从ASP.NET Core 3.0开始,默认使用了微软内置的JSON序列化和反序列化类库:System.Text.Json,此类库中并没有像Json.NET中实现这些特殊数据类型的JSON转换,在使用复杂类型接收参数时,会出现转换错误。
安装
Microsoft.AspNetCore.Mvc.NewtonsoftJson后,

在stratup.cs 中services.AddControllers().AddNewtonsoftJson();

1、POST-基础类型参数

1、通过在post请求的url中追加查询字符串
正确后端代码
/// /// FromQuery Dictionary参数 /// /// /// [HttpPost] [Route("PostString")] public string PostString(string param,string param1) { return param1+param1; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
错误前端代码示例
$.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostString", data: {"param":1,"param1":2}, success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
正确前端代码示例
$.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostString?param=1¶m1=2", success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
调试代码截图

image.png

2、通过在post请求的body中传递参数(不推荐!!)
错误后端代码
// 错误是因为FormBody在一个action中仅允许出现一次,因为请求主体在流中,而流只能打开一次 // 这样会导致编译失败 [HttpPost] [Route("PostString")] public string PostString([FromBody]string param,[FromBody]string param1) { return param1+param1; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
正确后端代码
/// /// string参数 /// /// /// [HttpPost] [Route("PostString")] public string PostString([FromBody]string param,[FromQuery] string param1) { return param.ToString(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
错误前端代码示例
// 错误原因是因为ajax 的body 是 =1,参数绑定时会报400错 $.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostString?param1=2", contentType: 'application/json', data: {"":"1"}, success: function (data) { layer.msg(JSON.stringify(data)); } }); // 错误原因是 这样传递,前台传递的是int类型,后台int 与 string不匹配,导致400报错 $.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostString?param1=2", contentType: 'application/json', data: "1", success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
正确前端代码示例
// 这里必须与后端的参数的类型对应,若string ,参数就要手动加上双引号,如果直接 data:'1' 或data:1 // 会导致400参数类型错误 $.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostString?param1=2", contentType: 'application/json', data: '"'+1+'"', success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
调试代码截图

image.png

2、POST-实体类型参数

正确后端代码

/// /// Post 接收 entity参数 /// /// /// [HttpPost] [Route("PostEntity")] public string PostEntity(ParamEntity entity) { return entity.Param; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

错误前端代码示例

$.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostEntity", contentType:'application/json', data: {Param: 1,Param1:2,Param2:'2023-02-09'}, success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

正确前端代码示例

必须要将data使用JSON.stringify()包一下

$.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostEntity", contentType:'application/json', data: JSON.stringify({Param: 1,Param1:2,Param2:'2023-02-09'}), success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

调试代码截图

image.png

3、POST-数组类型参数

正确后端代码

/// /// Post 接收 entity参数 /// /// /// [HttpPost] [Route("PostEntity")] public string PostEntity(ParamEntity entity) { return entity.Param; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

正确前端代码示例

必须要将data使用JSON.stringify()包一下

$.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostArrays", contentType:'application/json', data: JSON.stringify([1,2,3,4]), success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

调试代码截图

image.png

4、POST-实体List参数

正确后端代码示例

/// /// Post接收实体类集合 /// /// /// [Route("PostEntityList")] public string PostEntityList(List<ParamEntity> entities) { return entities.Count.ToString(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

正确前端代码示例

$.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostEntityList", contentType:'application/json', data: JSON.stringify([{Param: 1,Param1:2,Param2:'2023-02-09'},{Param: 1,Param1:2,Param2:'2023-02-09'}]), success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

调试代码截图

image.png

5、POST-动态类型参数

当我们不想new 一个临时类做参数时,或参数属性是动态时,我们可以使用dynamic类做参数接收类型,但不推荐使用object类做参数类型。因为只要你使用object,就意味着你必须要进行类型强制转换,这就增加了系统异常的风险,使用object还不如使用字符串,然后后端字符串反序列化成对象。当我们使用Post接收基础数据类型时,完全可以使用dynamic来接收,因为基础数据类型没有属性的不确定性,而且避免了将参数放到url中。

正确后端代码示例

/// /// Post接收动态类型参数 /// /// /// [Route("PostDynamic")] public string PostDynamic(dynamic obj) { return obj.Param1; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

正确前端代码示例

$.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostDynamic", contentType:'application/json', data: JSON.stringify({Param: 1,Param1:2,Param2:'2023-02-09'}), success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

调试代码截图

image.png

6、POST-Dictionary类型参数(value为基础数据类型)

正确后端代码示例

/// /// Post接收Dictionary类型参数 /// /// /// [Route("PostDictionary")] public string PostDictionary(Dictionary<string,string> dictionary) { return dictionary.Keys.ToString(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

正确前端代码示例

$.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostDictionary", contentType: 'application/json', data: JSON.stringify({param: 1, param1: 2, param2: '2023-02-09'}), success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

调试代码截图

image.png

7、POST-Dictionary类型参数(value为实体数据类型)

正确后端代码示例

/// /// Post接收Dictionary value为实体类型参数 /// /// /// [Route("PostDictionaryValueEntity")] public string PostDictionaryValueEntity(Dictionary<string,ParamEntity> dictionary) { return dictionary.Keys.ToString(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

正确前端代码示例

$.ajax({ type: "post", url: "http://localhost:5000/TestPost/PostDictionaryValueEntity", contentType: 'application/json', data: JSON.stringify({ param: {param: 1, param1: 2, param2: '2023-02-09'}, param1: {param: 1, param1: 2, param2: '2023-02-09'}, param2: {param: 1, param1: 2, param2: '2023-02-09'} }), success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

调试代码截图

image.png

3、绑定源特性

以net core 3.0 为例,存在以下绑定源特性:
image.png

微软官方文档:https://learn.microsoft.com/zh-cn/aspnet/core/web-api/?view=aspnetcore-7.0&viewFallbackFrom=aspnetcore-3

特性绑定源
[FromBody]请求正文
[FromForm]请求正文中的表单数据
[FromHeader]请求标头
[FromQuery]请求查询字符串参数
[FromRoute]当前请求中的路由数据

那么到底什么是绑定源特性?按照微软官方文档解释来理解,感觉晦涩难懂。个人理解为从请求的不同位置获取源数据,并且通过不同的绑定方式将数据绑定到使用了[FromBody]这种特性的参数上。

1、[FromBody]用法

1、post请求
2、基础数据类型参数,且必须要在post请求的body中传递。其他场景中不推荐使用。因为以post 传递实体类型参数为例,即使不加此标记,依然可以实现自动绑定

/// /// FromBody FromQuery /// /// /// /// [HttpPost] [Route("PostString")] public string PostString([FromBody] string param, [FromQuery] string param1) { return param.ToString(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2、[FromForm]用法

1、使用原始表单提交
2、ajax 指定contentType: application/x-www-form-urlencoded

<form action="http://localhost:5000/TestPost/PostEntity" method="post" id="test_form"> <input type="text" name="param" value="" /> <input type="text" name="param1" value="" /> form> <button onclick="submit()">提交button> function submit(val){ document.getElementById('test_form').submit(); return false } /// <summary> /// FromForm /// summary> /// <param name="entity">param> /// <returns>returns> [Route("PostEntity")] public string PostEntity([FromForm] ParamEntity entity) { return entity.Param; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

3、[FromQuery]用法

1、从查询字符串中获取参数,自动绑定
2、常用于多个参数的请求,用于区分哪些参数需要从url中绑定

/// /// FromBody FromQuery /// /// /// /// [HttpPost] [Route("PostString")] public string PostString([FromBody] string param, [FromQuery] string param1) { return param.ToString(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4、[FromRoute]用法

从路由,实际上也是从url,中获取参数,自动绑定

// 1、可以通过Route中指定 /// /// TestRoute /// /// /// /// /// [Route("TestRoute/{param}/{param1}/{param2}")] public string TestRoute(string param, string param1,string param2) { return param; } // 2、也可以通过实体类接收,在实体类中指定属性的绑定源 /// /// TestRoute /// /// /// /// /// // [Route("TestRoute/{param}/{param1}/{param2}")] [Route("{param}/{param1}/{param2}/TestRoute")] public string TestRoute([FromQuery]RouteEntity entity) { return entity.Param; } public class RouteEntity { [FromRoute(Name = "param")] public string Param { get; set; } [FromRoute(Name = "param1")] public string Param1 { get; set; } [FromRoute(Name = "param2")] public string Param2 { get; set; } [FromQuery] public string Param3 { get; set; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
$.ajax({ type: "post", url: "http://localhost:5000/TestPost/1/2/3/TestRoute?param3=4", contentType: 'application/json', success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

image.png

5、[FromHeader]用法

从Header中获取参数,自动绑定

/// /// TestHeader /// /// /// [Route("TestHeader")] public string TestHeader([FromHeader]string param) { return param; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
$.ajax({ headers:{ "param": "1" }, type: "post", url: "http://localhost:5000/TestPost/TestHeader", contentType: 'application/json', success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

image.png

4、WebApi 参数内置校验特性及自定义

对于参数校验,我们一般的方式如下:

/// /// TestValidate /// /// /// [Route("TestValidate")] public string TestValidate(ParamEntity entity) { if (string.IsNullOrEmpty(entity.Param)) { return "entity.param should not be null or empty"; } return entity.Param; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

但实际上,c# WebApi提供了很多内置的校验特性,继承自
System.ComponentModel.DataAnnotations.ValidationAttributede的一些特性如下:
image.png
其中System.ComponentModel.DataAnnotations.DataTypeAttribute 还有不同的子类,如下:
image.png

1、使用c# 内置校验特性实现接口参数校验

后端代码

相比与传统的校验方式,我们可以发现,通过校验特性来进行参数校验,大大减少了代码冗余,将复杂且冗余的逻辑判断,使用特性代替,代码如下:

/// /// TestValidate /// /// /// [Route("TestValidate")] public string TestValidate(ParamEntity entity) { return entity.Param; } public class ParamEntity { [Required(ErrorMessage = "这个参数是必须的!")] [MaxLength(length:20,ErrorMessage = "这个参数最大长度不得超过20!")] public string Param { get; set; } /// /// 3位数字 /// [RegularExpression(pattern:"^\\d{3}$",ErrorMessage = "必须是3位数字")] public string Param1 { get; set; } public string Param2 { get; set; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

前端代码

$.ajax({ type: "post", url: "http://localhost:5000/TestPost/TestValidate", contentType:'application/json', data: JSON.stringify({Param: "1",Param1:"22222",Param2:'2023-02-09'}), success: function (data) { layer.msg(JSON.stringify(data)); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这个时候,请求就不会进入后台接口,直接返回400参数类型错误,截图如下:
image.png

image.png

2、使用自定义校验特性实现接口参数校验

c# 内置的校验特性都是继承自System.ComponentModel.DataAnnotations.ValidationAttributede类,那么我们要编写自己的校验特性,首先需要继承这个类,然后在自己的类中重写校验方法即可。代码如下,以校验EmpNO为例:

后端代码

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] public class EmpNoValidateAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var empNo = value.ToString(); return !empNo.StartsWith("E") ? new ValidationResult("EmpNo必须要以E开头") : base.IsValid(value, validationContext); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

使用方式如下:
image.png

3、对于参数校验400错误,统一返回格式

为什么需要统一的返回格式,在网上找的文章如下:
image.png

1、编写自己的过滤器

/// /// 参数校验过滤器 /// 返回统一格式消息 /// public class ValidateReqModelFilter : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { if (!context.ModelState.IsValid) { // 在响应体中返回验证错误信息 var errors = new Dictionary>(); foreach (KeyValuePair keyValue in context.ModelState) { errors[keyValue.Key] = keyValue.Value.Errors.Select(e => e.ErrorMessage); } context.Result = new JsonResult(new { code = -1, errmsg = errors }); } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2、禁用c#自带的参数验证过滤器

如果不禁用自带过滤器,则会直接返回400,导致我们自己定义的过滤器虽然注册,但是不会执行

services.Configure(options => options.SuppressModelStateInvalidFilter = true);
  • 1

3、注册自己的过滤器

红色代码部分:
services.AddControllers(options => options.Filters.Add(typeof(ValidateReqModelFilter))).AddNewtonsoftJson();

4、接口返回截图

状态码:200
image.png
示例:
image.png

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索
排行榜