C# WebApi 传参解惑

206 阅读4分钟

C# WebApi 接口传参解惑

正文

在学习WebApi时遇到了许多困惑,现记载并解惑。本文通过Get/Post/Put/Delete四种请求方式的传参。

Get请求传递参数

  • Get请求的特性
    • 如果Action前缀是Get则默认为Get请求方法
    • 如果Action前缀不存在Get,那么就算服务器找到Aciton,也会返回405错误,因为不能确定请求方式。因此,这种情况下请标记请求方式。 日常使用中最常用的就是Get请求了。

1.基础类型

        [HttpGet]
        [Route("GetRes")]
        public IHttpActionResult GetRes(int id ,int name)
        {
            return Ok();
        }
        $("#fr").on("submit", function (e) {
            $.ajax({
                type: "get",
                url: "/api/Student/GetRes",
                data: {id:1,name:20},
            }).done(function () {
                console.log("成功了");
            }).fail(function () {
                console.log("失败了");
            });
        })

基础类型的参数传递我们无需多说,通过查询字符串绑定参数

2.实体类型

    /// <summary>
    /// 实体类型
    /// </summary>
    public class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DateTime DateTime { get; set; }
    }
	    [HttpGet]
        [Route("GetEntity")]
        public IHttpActionResult GetEntity(Student student)
        {
            return Ok();
        }
        $("#fr").on("submit", function (e) {
            e.preventDefault();
            $.ajax({
                type: "get",
                url: "/api/Student/GetEntity",
                contentType:"application/json",
                data: { Name: "huangwei", Age: 20, DateTime: "2020-12-11" },
            }).done(function () {
                console.log("成功了");
            }).fail(function () {
                console.log("失败了");
            });
        })

如上图所示,如果我们直接将json对象传递给后台,后台无法接受到这个对象,但确实调用了这个Action。为什么会造成这种结果?

原因在于,我们通过get请求的时候,数据是通过附加在url中传递到后台的。因此,json对象属性key/value附加到了url中,然而后台action中参数列表又没有与之对应,因此参数为null。

我们可以使用FromUri特性标记参数,即可从QueryString中获取数据进行模型绑定

2.Post请求

WebApi中,Post请求一般用于提交数据

1.基础数据类型

post请求与get请求传递参数的方式是有区别的,get请求参数存放于QueryString中,而post请求传递的参数存放于http请求体中。在webApi中,post请求传递参数同样需要放于http方法体中。

错误的做法:且前台返回404状态码

        [HttpPost]
        [Route("PostName")]
        public IHttpActionResult PostName(string name)
        {
            return Ok();
        }
        $("#fr").on("submit", function (e) {
            e.preventDefault();
            $.ajax({
                type: "post",
                url: "/api/Student/PostName",
                data:{ name: "huangwei" },
            }).done(function () {
                console.log("成功了");
            }).fail(function () {
                console.log("失败了");
            });
        })

正确的做法

        [HttpPost]
        [Route("PostName")]
        public IHttpActionResult PostName([FromBody]string name)
        {
            return Ok();
        }
        $("#fr").on("submit", function (e) {
            e.preventDefault();
            $.ajax({
                type: "post",
                url: "/api/Student/PostName",
                data:{ "": "huangwei" },
            }).done(function () {
                console.log("成功了");
            }).fail(function () {
                console.log("失败了");
            });
        })

通常我们通过url去参数是key = value 的方式取出,然而webApi中 post请求的参数标记FromBody特性后,并不能通过key = value 的方式获取数据,他没有key。如果在这里写了key那么获得的参数为null。

如果我们在多个基础类型的情况下,我们该怎么办?注意一个Action中只能存在一个FromBody特性,方法如下:

        [HttpPost]
        [Route("POne")]
        public IHttpActionResult POne(dynamic argument)
        {
            var name = argument.name;
            var age = argument.age;
            return Ok();
        }
        $("#fr").on("submit", function (e) {
            e.preventDefault();
            $.ajax({
                type: "post",
                url: "/api/Student/POne",
              contentType: "application/json",
                data: JSON.stringify({ name: "huangwei", age: "20" }),
            }).done(function () {
               console.log("成功了");
            }).fail(function () {
               console.log("失败了");
            });
        })

使用dynamic 类型省略掉了[FromBody],但我们必须要注意调用属性的一致性,

在ajax中还需要注意,contentType:"application/json",表示参数类型是json

2.实体参数

        [HttpPost]
        [Route("LogIn")]
        public IHttpActionResult LogIn([FromBody]UserModel userModel)
        {
            return Ok();
        }
        $("#fr").on("submit", function (e) {
            e.preventDefault();
            let data = $(this).serializeArray();
            let obj = {};
            $.each(data, function (index, val) {
                obj[val.name] = val.value
            })
            $.ajax({
                url: "/api/Student/LogIn",
                type: "post",
                data: obj,
            }).done(function (data) {
                console.log("成功了")
            }).fail(function () {
                console.log("失败了")
            })
        })

单个实体参数时后台可以使用FromBody,也可以不使用

如果使用 contentType:"application/json",那么必须使用JSON.stringify(data)将数据转换为JSON字符串的形式。如果不指定contentType:"application/json",那么就不能使json字符串传递参数 原理解释:我们来看看它默认的contentType是什么:

  • application/x-www-form-urlencoded : <from encType = "">中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认提交数据的格式)
  • application/json : JSON数据格式 也就是说post请求默认是将表单里面的数据的key/value形式发送到服务,而我们的服务器只需要有对应的key/value属性值的对象就可以接收到。而如果使用application/json,则表示将前端的数据以序列化过的json字符串形式传递到后端,后端要把它变成实体对象。
        [HttpPost]
        [Route("LogIn")]
        public IHttpActionResult LogIn([FromBody]UserModel userModel)
        {
            return Ok();
        }
        $("#fr").on("submit", function (e) {
            e.preventDefault();
            let data = $(this).serializeArray();
            let obj = {};
            $.each(data, function (index, val) {
                obj[val.name] = val.value
            })
            $.ajax({
                url: "/api/Student/LogIn",
                type: "post",
                data: JSON.stringify(obj),
                contentType: "application/json"
            }).done(function (data) {
                console.log("成功了")
            }).fail(function () {
                console.log("失败了")
            })
        })

3. 数组参数

  • 基础类型
        [HttpPost]
        public bool SaveData(string[] ids)
        {
            return true;
        }

    var arr = ["1", "2", "3", "4"];
    $.ajax({
        type: "post",
        url: "http://localhost:27221/api/Charging/SaveData",
        contentType: 'application/json',
        data: JSON.stringify(arr),
        success: function (data, status) { }
    });
  • 集合
        [HttpPost]
        public bool SaveData(List<TB_CHARGING> lstCharging)
        {
            return true;
        }
    var arr = [
        { ID: "1", NAME: "Jim", CREATETIME: "1988-09-11" },
        { ID: "2", NAME: "Lilei", CREATETIME: "1990-12-11" },
        { ID: "3", NAME: "Lucy", CREATETIME: "1986-01-10" }
    ];
    $.ajax({
        type: "post",
        url: "http://localhost:27221/api/Charging/SaveData",
        contentType: 'application/json',
        data: JSON.stringify(arr),
        success: function (data, status) {}
    });

put和delete传参基本与 post请求一致

参考

原文作者:懒得安分