111

【WebApi系列】详解WebApi如何传递参数 - Alan_beijing

 6 years ago
source link: https://www.cnblogs.com/wangjiming/p/8378108.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

【WebApi系列】详解WebApi如何传递参数

WebApi系列文章

【01】浅谈HTTP在WebApi开发中的运用

【02】聊聊WebApi体系结构

【03】详解WebApi参数的传递

【04】详解WebApi测试和PostMan

【05】浅谈WebApi Cores

【06】详解WebApi 异常处理

【07】用WebAPI写个基于EF的CURD

【08】浅谈WebAPI身份认证

【09】详解系列化和模型绑定

【10】浅谈WebApi如何配合Mvc有效工作

【11】浅谈API Reference

【12】浅谈接口在软件架构中的作用

【13】浅谈WebApi和WebService的比较

【14】浅谈如何设计一个良好的接口

                                                                     

1066923-20180127123414725-579685317.png

一     概述

二    Get

    1   基础数据类型

        1.1  方法只含一个形参

        1.2  方法含多个形参

    2   实体对象类型

    3   实体对象和基础数据类型混合

    4   最小满足原则

    5   url长度限制

    6   Get规范化

    7    关于实体作为参数传递的拓展

         7.1   借助[FromUri]特性传递实体

         7.2   系列化和反系列化传递实体

三    Post

    1   基本数据类型传递

         1.1   [FromBody]单个参数传递

         1.2  Dynamic单个参数传递

    2   实体作为参数传递

    3   实体集合作为参数传递

    4   数组作为参数传递

    5   小结

四   总结

一般地,我们在研究一个问题时,常规的思路是为该问题建模;我们在研究相似问题时,常规思路是找出这些问题的共性和异性。基于该思路,我们如何研究WebApi参数传递问题呢?

首先,从参数本身来说,种类较为多(如int,double,float,string,array,Object等),且有些类型较为复杂(如值类型和引用类型的机制等);

其次,从基于WebApi的Http请求方法来说,种类多且不尽相同(如Get,post,Delete,put,head等),在上一篇文章 :【WebApi系列】浅谈HTTP在WebApi开发中的运用  中,我们简要描述了Http请求的20个方法;

..........

如此复杂且不尽相同,关于WebApi参数传递,我们该选择什么作为切入点来研究呢?基于我们上面提到的研究思路,我们想到了.NET Framework框架,那么,我们来看看基于.NET Framework框架的的WebApi

模板是怎样的呢?

请按图中步骤操作

1066923-20180130112008281-343654863.png

我们来看看Values控制器是怎样的

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

从Values控制器,我们不难得出如下几个结论:

(1)WebApi常规方法为四个:Get,Post,Put和Delete;

(2)四种方法的参数可归结为两大类:url传递(Request-url)和Body(Request-body)传递;

(3)基于(2),我们将四种方法的参数传递归为两大类,而这两大类又集中在Get和Post中体现了(Put是Get和Post的组合,Delete与Get类似);

其实,分析到现在,我们很容易找得到了研究WebApi参数传递的切入点?研究Get和Post方法参数传递即可。是的,没错,我们本篇文章就是基于Get和Post方法的参数传递,前者对应Request-url,后者对应Reqeust-Body。

1  基础数据类型


1.1  方法只含一个形参(参数传得进去)

$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
       $.ajax({
               type: "Get",
               //url: "/api/Default/GetProductDetails?ProductCode=JX80869"
               url: "/api/Default/GetProductDetails",
               data: { "ProductCode":"JX80869"}
            })
        })           
   })

Result

1066923-20180129193429328-237488141.png

(1)当Get方法形参为一个且为基本数据类型时,Get方法能接受外部传递的值

(2)Get传值的本质是通过url字符串拼接,如上两两种url形式的传递的结果都是一样

url形式1

url: "/api/Default/GetProductDetails?ProductCode=JX80869"

url形式2

url: "/api/Default/GetProductDetails",
data: { "ProductCode":"JX80869"}

我们用Goole Chrome来看看结果,发现url形式1和url形式2均一致

1066923-20180129194626890-2112532684.png

(3)Get传递参数本质是url字符串拼接,Request-Head头部传递,Request-Body中不能传递(这是与Post方法的本质区别),我们举两个例子

例子1:我们将形参添加[FromBody]属性后,值传递不进去

1066923-20180129195536453-1209821247.png

例子2:我们用PostMan来测试,发现PostMan中,Get方法参数Body为灰色,是不能选中的

 

1066923-20180129195833609-305155289.png

1.2  方法含有多个形参(参数传得进去)

$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
      $.ajax({
               type: "Get",
               url: "/api/Default/GetProductDetails",
               data: { "ProductCode": "JX80869","ProductName":"YaGao"}
            })
        })
  })

result

1066923-20180129200421156-1739294476.png

2   实体对象类型(参数传不进去)


 model

 1  public class ProductDetail
 2     {
 3         //产品编码
 4         [Required]
 5         public string ProductCode { get; set; }
 6         //产品名称
 7         [Required]
 8         public string ProductName { get; set; }
 9         //产品价格
10         [Required]
11         public double  ProductPrice{ get; set; }
12     }
$(document).ready(function () {
    var productDetail = { "ProductName": "YaGao", "ProductCode": "JX80869", "ProductPrice": 40.5};
        $("#FindProdcutDetail").click(function () {
            $.ajax({
                    type: "Get",
                    url: "/api/Default/ProductDetails",
                    data: productDetail
                })
            })
        })

result:

1066923-20180130001859625-1117818966.png
1066923-20180129204036062-1978407741.png

3   实体对象和基础数据类型混合(实体传不进去,基础数据能传递进去)


1 $(document).ready(function () {
2    $("#FindProdcutDetail").click(function () {
3        $.ajax({
4                 type: "Get",
5                 url: "/api/Default/GetProductDetails",
6                 data: { "_productDetail": "ObjectEntity","ProductName":"YaGao"}
7              })
8         })
9     })

 result

1066923-20180130003232281-1901030757.png

4  最小满足原则(参数传得进去)


 所谓“最小满足原则”,指外部参数必须至少满足被调用方法的形参(形参个数,形参类型和形参名字),换句话说,被调用方法具有的形参,外部参数必须传递进来,被调用方法没有

的形参,外部参数传递与否都可以,否则将会产生状态码404错误,用数学集合的思路来理解的话,被调用方法的形参相当于外部参数的子集。如下例子,我们举一个真子集的例子,

即外部传递参数的个数大于被调方法的的形参个数。

 $(document).ready(function () {
    $("#FindProdcutDetail").click(function () {
       $.ajax({
                type: "Get",
                url: "/api/Default/GetProductDetails",
                data: {"ProductCode": "JX00034", "ProductName": "YaGao", "ProductPrice": 20.5, "PrudcutType": "Daily Necessities"}
                })
            })
        })

result

1066923-20180130175809203-2070595438.png

 分析:主要原因是路由规则,路由从url里面取参数与aciton参数匹配,直到匹配满足为止,具体详细深入内容,在【WebApi系列】路由章节分析。

1066923-20180130003104390-1564514912.png

5  url长度限制


 url参数长度是有一定限制的,当超过一定长度,会报404错误

 $(document).ready(function () {
            $("#FindProdcutDetail").click(function () {
                $.ajax({
                    type: "Get",
                    url: "/api/Default/GetProductDetails",
                    data: {
                        "ProductCode":
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 
                    }
                })
            })
        })

result

1066923-20180129224639062-183049714.png

6  Get规范化


 关于Get类型规范化,应注意两点,避免不必要的错误或异常:(1)方法的命名尽量采用:“Get+方法名”的形式 (2)在每个方法上加上特性[HttpGet]。

1066923-20180129231823406-2033747105.png

例子:我们去掉[HttpGet]特性和方法前的Get,看看情况什么怎样的

$(document).ready(function () {
    $("#FindProdcutDetail").click(function () {
        $.ajax({
                 type: "Get",
                 url: "/api/Default/ProductDetails",
                 data: {"ProductCode": "JX00034 "}
             })
         })
    })

Controller

1 public class DefaultController : ApiController
2     {
3         4         //[HttpGet]
5         public string ProductDetails(string ProductCode)
6         {
7             return "values";
8         }
9     }

 Result

1066923-20180129232614390-1394143048.png

7  关于实体作为参数传递的拓展


7.1  借助[FromUri]特性传递实体

$(document).ready(function () {
   var GetEntityParam = { "ProductName": "YaGao", "ProductCode": "JX80869", "ProductPrice": 40.5};
      $("#FindProdcutDetail").click(function () {
        $.ajax({
                 type: "Get",
                 url: "/api/Default/ProductDetails",
                 data: GetEntityParam
               })
           })
      })

result

1066923-20180129234834703-331731758.png

7.2  系列化与反系列化传递实体

$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
       $.ajax({
                type: "Get",
                url: "/api/Default/ProductDetails",
                data: { "productDetail": JSON.stringify({ "ProductName": "YaGao", "ProductCode": "JX80869", "ProductPrice": 40.5 }) }
             })
         })
     })

 result

1066923-20180130000258531-713702687.png

 (1)Get参数传递的本质是url字符串拼接;

 (2)url字符串长度受限制;

 (3)Get参数传递在Http请求头部传递,而不支持Request-Body传递;

 (4)Get类型的方法支持参数为基本类型,不支持实体类型;

 (5)Get类型的方法命名,应尽量采用“Get+方法名”的命名方式,且习惯性地在方法前加上[HttpGet特性];

 (6)实参与形参的匹配,遵循路由规则;

(7)Get对应DB的Select操作,从这一点来理解,就知道为什么Http不支持实体对象传递的合理性了,因为一般情况,我们都是通过简单的字段查询信息(对应基本类型),

如ID号,用户名等,而不会通过一个实体查询数据;

 三    Post 

1  基本数据类型传递


1.1  [FromBody]单个参数传递

1066923-20180130082148640-267452093.png

result

1066923-20180130081523625-1736155342.png

1.2 dynamic单个参数传递

$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
      $.ajax({
               type: "Post",
               contentType: 'application/json',
               url: "/api/Default/PostParamToProducts",
               data: JSON.stringify({"ProductCode":"JX00039"})
           })
       })
   })

result

1066923-20180130102806734-1895031856.png

Googel Chrome查看

1066923-20180130103024406-1518055997.png

2 实体作为参数传递


$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
      $.ajax({
               type: "Post",
               url: "/api/Default/PostParamToProducts",
               data: { "ProductCode": "JX00036","ProductName":"YaGao","ProductPrice":20.5}
            })
        })
    })

result

1066923-20180130092233734-498436747.png

我们用Googel  Chrome看看

1066923-20180130092848750-842148530.png

3 实体集合作为参数传递


$(document).ready(function () {
   var list_ProductDetail = [
       { "ProductCode": "JX00031", "ProductName": "ToothPaste", "ProductPrice": "20.5" },
       { "ProductCode": "JX00032", "ProductName": "ToothBrush ", "ProductPrice": "18.9" },
       { "ProductCode": "JX00033", "ProductName": "Pen", "ProductPrice": "199.9" },
       { "ProductCode": "JX00034", "ProductName": "computer", "ProductPrice": "15000.5" }
       ]
   $("#FindProdcutDetail").click(function () {
   $.ajax({
             type: "Post",
             contentType: 'application/json',
             url: "/api/Default/PostParamToProducts",
              data: JSON.stringify(list_ProductDetail)
          })
      })
  })

 result

1066923-20180130101310484-974311561.png

Google Chrome 查看

1066923-20180130101654609-680631132.png

4  数组作为参数传递


$(document).ready(function () {
   var arr = ["a", "b", "c", "d"];
   $("#FindProdcutDetail").click(function () {
      $.ajax({
               type: "Post",
               contentType: 'application/json',
               url: "/api/Default/PostParamToProducts",
               data: JSON.stringify(arr)
            })
       })
  })

Result

1066923-20180130095047484-1279677295.png

我们用Google Chrome看看

1066923-20180130095324828-174423464.png

 (1)Post参数传递本事是在Request-Body内传递,而Get参数传递本质是url拼接;

(2)Post参数传递不是key/value形式,而Get参数是key/value形式;

(3)Post传递参数时,无论是单个参数还是对象,均借助[FromBody]特性(当然,某些情况去掉[FromBody]特性也可把值传递进去,但未了规范化,尽量加上该特性);

(4)Post没长度限制,而Get有长度限制(一般为1024b);

(5)Post相对Get,较安全;

(6)Post操作相当于DB的Insert操作;

1.虽然HTTP请求方法有20多种,常用的大致为4种,即Get,Post,Put,Delete(当然,像Trace,Head等也常用);

2.Get,Post,Put,Delete分别对应DB的Select,Insert,Update和Delete操作;

3.WebApi参数类型,大致分为基本数据类类型和对象数据类型(当然你也可以理解为抽象数据类型);

4.研究WebApi参数传递,只需研究Get和Post即可,因为其他http方法参数传递基本都是有这两种组合而成(如Put有Get和Post组合而成),或者相似(如Delete与Get相似);

5.对于控制器方法,尽量参照规范格式写,如在相应控制器方法上加上对应的htt请求(Get对应[HttpGet],Post对应[HttpPost]),方法名尽量采用“Http请类型+方法名”格式(如Get请求,建议采用Get+MethodName;Post请求对应Post+MethodName);

6.WebApi参数请求,大致分为两大类型,即Request-url和Request-body;

7.文中我们还简要分析了Get和Post区别;

8.关于如何设计一个良好的接口,在文章中,我们触及了一下,但未研究,会在后续的文章中单独分析;

 有喜欢的朋友,可以看一下,不喜欢的的朋友,勿喷,谢谢!!

1066923-20180405110945712-1323607740.png
  • 感谢您的阅读,若有不足之处,欢迎指教,共同学习、共同进步。
  • 博主网址:http://www.cnblogs.com/wangjiming/。
  • 极少部分文章利用读书、参考、引用、抄袭、复制和粘贴等多种方式整合而成的,大部分为原创。
  • 如您喜欢,麻烦推荐一下;如您有新想法,欢迎提出,邮箱:[email protected]
  • 可以转载该博客,但必须著名博客来源。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK