zoukankan      html  css  js  c++  java
  • 基于.Net Framework 4.0 Web API开发(2):ASP.NET Web APIs 参数传递方式详解

    概述: 

      ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作。调用API过程中参数的传递是必须的,本节就来谈谈API使用过程中参数的传递方式。

    各种参数传递方式的实现:

          ASP.NET Web API参数有两种传递方式,一种是请求时携带QueryString,Action中没有表中标注FromUri和FromBody属性且没有默认值的参数,Request请求时必需一QueryString的方式携带参数?A=&B=&C=1,及时没有值,也得传递,否则报404错误。

      API 开发中的FromUriAttribute属性,主要是用来在GET请求中传递复杂对象,并且每个API可以含有多个此类型的参数,但每个复杂对象中的属性名不能相同,否则无法正确传值,除非两个参数的相同属性的属性值相同,不过此种方式传递有一定的局限性,就是url长度限制,变相的限定此种方式的参数数据量的大小。

         另外一种传递方式就是请求Request的发送内容携带数据,对应API开发中的FromBodyAttribute属性,此种方式主要应对POST请求参数的传递,可以传递复杂的类型,包括数组,list等,但是每个API有且仅有一个这样的参数,如果有多个,就会报无法将多个参数绑定到请求的内容

      不多上,下面上代码,一种一种讲解:

     1. 简单类型传递

      简单类型包括 int(decimal,long,float)、string(char)、bool、datetime、guid,主要就这几种

         模板: public  TResult nameOfFunction([FromUrl]int i, [FromUrl]string s, ……)

             => public  TResult nameOfFunction(int i, string s, ……)

       但模板: public  TResult nameOfFunction([FromUrl]ClassA a, [FromUrl]Class b, ……)

             ≠> public  TResult nameOfFunction(ClassA a, ClassB b, ……)

     1         [HttpGet]
     2         public ResultData TestParameter(int i, string s, bool b, DateTime t, Guid g)
     3         {
     4             try
     5             {
     6                 var data = new { i = i, s = s, b = b, t = t, g = g};
     7                 return new ResultData(data);
     8             }
     9             catch (Exception ex)
    10             {
    11                 throw ex;
    12                 //return new ResultData(ResultType.SystemException, ex.Message);
    13             }
    14         }
    15 
    16         //TestParameter
    17 function TestParameter() {
    18     var v = { i: 1, b: false, t: "2016-07-06", g: "E816F0B7-2FB7-47D9-84ED-119F58C9BEC5", s: "test"};
    19     $.ajax({
    20         type: "get",
    21         url: host + "/mobileapi/test/TestParameter",
    22         dataType: "text",
    23         data: v,
    24         success: function (data) {
    25             alert(data);
    26         },
    27         error: function (x, y, z) {
    28             alert("报错无语");
    29         }
    30     });
    31 }

    结果如下:

    注意:

     1. GET 类型请求的API不能含有[FromBody]属性的参数,虽然不会报错,但永远没为null,如果GET请求需要传递复杂参数,可以用FromUri属性修饰参数

     2. API参数没有默认值的情况下,请求的参数名称必需与API参数名称保持一致,但不区分大小写,且能对应上的参数个数一定相等,否则会报404错误。

    详细列举如下:

         a. 参数个数相等,但对应的参数少个 g,所有找不到对应API,报404错误

     1 function TestParameter() {
     2     var v = { i: 1, b: false, t: "2016-07-06", s: "test", a: "会报404错误" };
     3     $.ajax({
     4         type: "get",
     5         url: host + "/mobileapi/test/TestParameter",
     6         dataType: "text",
     7         data: v,
     8         success: function (data) {
     9             alert(data);
    10         },
    11         error: function (x, y, z) {
    12             alert("报错无语");
    13         }
    14     });
    15 }

         b. 参数个数不相等,但是能对应上的参数个数相等,不会报404错误

     1 //TestParameter
     2 function TestParameter() {
     3     var v = { i: 1, b: false, t: "2016-07-06", s: "test", g: "E816F0B7-2FB7-47D9-84ED-119F58C9BEC5", a: "不会报404错误" };
     4     $.ajax({
     5         type: "get",
     6         url: host + "/mobileapi/test/TestParameter",
     7         dataType: "text",
     8         data: v,
     9         success: function (data) {
    10             alert(data);
    11         },
    12         error: function (x, y, z) {
    13             alert("报错无语");
    14         }
    15     });
    16 }

      如何调整使上述几种方式也能找到正确的API的呢?这就需要.NET Framework的默认参数功能,API的调整如下:

     1  [HttpGet]
     2         public ResultData TestParameter(int i, string s, bool b, DateTime t, Guid? g = null)
     3         {
     4             try
     5             {
     6                 var data = new { i = i, s = s, b = b, t = t, g = g };
     7                 return new ResultData(data);
     8             }
     9             catch (Exception ex)
    10             {
    11                 throw ex;
    12                 //return new ResultData(ResultType.SystemException, ex.Message);
    13             }
    14         }

     以上代码最后一个参数g有个默认值null,这样get请求的时候可以没有g参数也能请求通过,不会报404错误。另外,值类型的参数最好定义为nullable形式(简写可以?标注),这样的参数赋值不正确的时候也不会报异常错误,只是参数值为null。特别是日期类,如果不是nullable类型,不传值和传错值都会报异常

         上面例子中的t参数如果为   TestParameter?i=1&b=false&t=2016-37-06&s=test&g=E816F0B7-2FB7-47D9-84ED-119F58C9BEC5或者

     http://192.168.1.135:1507/mobileapi/test/TestParameter?i=1&b=false&t=&s=test&g=E816F0B7-2FB7-47D9-84ED-119F58C9BEC5,都会报错,如果定义为nullable类型就一切正常:   public ResultData TestParameter(int i, string s, bool b, DateTime? t, Guid? g = null)。

    2. 复杂类型传递

     GET请求中复杂类型的传递需要FormUriAttribute属性配合,并且每个API可以有多个FromUri标示的参数,也可以在post请求中使用此属性标注的参数。

     1  [HttpGet]
     2         public ResultData TestParameter2([FromUri]List<int> ids, [FromUri]User a)
     3         {
     4             try
     5             {
     6                 var data = new { ids=ids, name=a.name };
     7                 return new ResultData(data);
     8             }
     9             catch (Exception ex)
    10             {
    11                 throw ex;
    12                 //return new ResultData(ResultType.SystemException, ex.Message);
    13             }
    14         }

       测试代码:

     1 function TestParameter2() {
     2     var v = { ids: [1, 2, 3], name='test', age=4, weight=100 };
     3     $.ajax({
     4         type: "get",
     5         url: host + "/mobileapi/test/TestParameter2",
     6         dataType: "text",
     7         data: { "": v },
     8         beforeSend: function (request) {
     9             request.setRequestHeader("token", $("#token").val());
    10         },
    11         success: function (data) {
    12             alert(data);
    13         },
    14         error: function (x, y, z) {
    15             alert("报错无语");
    16         }
    17     });
    18 }

       测试结果:GET请求中可以利用FromUri属性传递复杂类型

        POST请求中复杂类型的传递需要FormBodyAttribute属性配合,并且每个API有且仅有一个FromBody标示的参数,并且只能在post请求中使用。

     1  [HttpPost]
     2         public ResultData TestParameter2([FromBody]List<int> ids, [FromBody]List<int> ids2)
     3         {
     4             try
     5             {
     6                 var data = new { ids=ids, ids2=ids2 };
     7                 return new ResultData(data);
     8             }
     9             catch (Exception ex)
    10             {
    11                 throw ex;
    12                 //return new ResultData(ResultType.SystemException, ex.Message);
    13             }
    14         }
     1         [HttpPost]
     2         public ResultData TestParameter2([FromBody]List<int> ids, [FromBody]ProductData pd)
     3         {
     4             try
     5             {
     6                 var data = new { ids = ids, pd = pd };
     7                 return new ResultData(data);
     8             }
     9             catch (Exception ex)
    10             {
    11                 throw ex;
    12                 //return new ResultData(ResultType.SystemException, ex.Message);
    13             }
    14         }

    以上两个示例中代码编译不报错,可以正常编译,但是请求会报错,报错信息如下:

       测试代码:

     1 function TestParameter2() {
     2     var v = { ids: [1, 2, 3], ids2: [4, 5, 6] };
     3     $.ajax({
     4         type: "post",
     5         url: host + "/mobileapi/test/TestParameter2",
     6         dataType: "text",
     7         data: { "": v },
     8         beforeSend: function (request) {
     9             request.setRequestHeader("token", $("#token").val());
    10         },
    11         success: function (data) {
    12             alert(data);
    13         },
    14         error: function (x, y, z) {
    15             alert("报错无语");
    16         }
    17     });
    18 }

       

     1 function TestParameter2() {
     2     var v = { "ids": [1, 2, 3], pd: { barcode: "ddddd" } };
     3     $.ajax({
     4         type: "post",
     5         url: host + "/mobileapi/test/TestParameter2",
     6         dataType: "text",
     7         data: { "": v },
     8         beforeSend: function (request) {
     9             request.setRequestHeader("token", $("#token").val());
    10         },
    11         success: function (data) {
    12             alert(data);
    13         },
    14         error: function (x, y, z) {
    15             alert("报错无语");
    16         }
    17     });
    18 }

    测试结果:

     以上两组测试都会报无法将多个参数绑定到请求的内容异常

    3. 数组参数的正确传递

       调整一下API,只接收一个FromBody参数,并为List<int>

     1         [HttpPost]
     2         public ResultData TestParameter2([FromBody]List<int> ids)
     3         {
     4             try
     5             {
     6                 var data = new { ids = ids, pd = pd };
     7                 return new ResultData(data);
     8             }
     9             catch (Exception ex)
    10             {
    11                 throw ex;
    12                 //return new ResultData(ResultType.SystemException, ex.Message);
    13             }
    14         }

    测试一:

     1 //TestParameter
     2 function TestParameter2() {
     3     var v = { "ids": [1, 2, 3] };
     4     $.ajax({
     5         type: "post",
     6         url: host + "/mobileapi/test/TestParameter2",
     7         dataType: "text",
     8         data: { "": v },
     9         beforeSend: function (request) {
    10             request.setRequestHeader("token", $("#token").val());
    11         },
    12         success: function (data) {
    13             alert(data);
    14         },
    15         error: function (x, y, z) {
    16             alert("报错无语");
    17         }
    18     });
    19 }

    测试一的结果:

    测试二:

     1 //TestParameter
     2 function TestParameter2() {
     3     var v = { "": [1, 2, 3] };
     4     $.ajax({
     5         type: "post",
     6         url: host + "/mobileapi/test/TestParameter2",
     7         dataType: "text",
     8         data: { "": v },
     9         beforeSend: function (request) {
    10             request.setRequestHeader("token", $("#token").val());
    11         },
    12         success: function (data) {
    13             alert(data);
    14         },
    15         error: function (x, y, z) {
    16             alert("报错无语");
    17         }
    18     });
    19 }

    测试二结果:

    分析: 经过测试一和测试二结果观察,数据传递格式不能数组名,其实这个不是数组传递的问题,而是WEB API frombody参数的一种约定,所以每个API只能有一个frombody格式的参数,因为这样的参数不会依据属性名对应解析,而是把body中发送的所有数据解析成一个对象,所以无法定义多个 frombody 格式参数。

    结论: 经过frombody修饰的参数只能有一个,并且经过frombody修饰的参数无论是简单类型,还是复杂类型(包括数组,list,系统class和自定义class等),传参都不需要属性名,属性名必需为空字符串(“”),否则无法解析,参数永远为null

    参数格式的列举:

    简单类型json参数格式: {"":1} 、{"":1.0} 、{"":"test"} 、{"":"C"} 、{"":"2016-03-10"} 、{"":"BC069BF1-1382-4C5D-B3B1-9643F3F94A9D"} 

    类定义如下:

    1     public class User
    2     {
    3         public string Name { get; set; }
    4         public int Age { get; set; }
    5         public DateTime? Birthday { get; set; }
    6     }

    类类型json参数格式:{name:"Tom", age:18, birthday:"2016-03-10"}

    4. FromUrl参数和FromBody参数混合使用,这种混合使用规则参照以上使用方法,没难度。

     1         [HttpPost]
     2         public ResultData TestParameter2(int i, string s, [FromUri]bool b, DateTime? t, Guid? g = null, [FromBody]List<int> ids = null)
     3         {
     4             try
     5             {
     6                 var data = new { ids = ids };
     7                 return new ResultData(data);
     8             }
     9             catch (Exception ex)
    10             {
    11                 throw ex;
    12                 //return new ResultData(ResultType.SystemException, ex.Message);
    13             }
    14         }

    此篇到此结束,欢迎大家讨论!

     补充:API中Action参数传递方式总结说明

        1. 参数不带任何属性标签   Action F1(string a, string b)

             querystring中必需含有 a和b查询字符串   url?a=1&b=, 即使b没有值,也必需携带,否则报404错误,找不到符合请求的Action

        2. 参数带有fromuri属性  Action F2(string a, [FromUri]stirng b)

       querystring中必需含有 a查询字符串,b可以不带,因为被属性[FromUri]修饰,例: url?a=1&b=或url?a=1都能匹配到F2 action, b没有值可以不携带,但参数a必需携带

        3. 带有fromuri属性的参数可以有多个  Action F3(string a, [FromUri]stirng b,[FromUri]stirng c,[FromUri]stirng d) ,

       请求方法同2, 例如: url?a=1&b=2&d=3

        4. 带有frombody属性的参数只适应post请求,否则永远为null ,并且可以与fromuri混合使用,但每个action,frombody属性参数有且仅有一个,多个会报错

               Action F4(string a, [FromUri]stirng b,[FromUri]stirng c,[FromBody]stirng d)

        使用方法同 2, 3

          这样混合使用不报错,也能正常运行,但需要混合使用的环境比较少,基本上95% Action只用fromuri或frombody就能完成,没必要混合使用

          

  • 相关阅读:
    JS标签获取另一个页面传过来的href值
    jsp/servlet实现简单上传和下载
    servlet跳转页面后图片不显示
    Nginx 配置实例-动静分离
    将博客搬至博客园
    nginx 配置实例-反向代理
    Nginx 简介与安装、常用的命令和配置文件
    nginx 配置实例-负载均衡
    nginx 配置实例-反向代理
    Nginx 简介与安装、常用的命令和配置文件
  • 原文地址:https://www.cnblogs.com/niuww/p/5646788.html
Copyright © 2011-2022 走看看