How to pass json POST data to Web API method as an object?
ASP.NET MVC4 Web API应用程序定义了保存客户的Post方法。在Post请求主体中以JSON格式传递客户。Post方法中的客户参数包含属性的空值。
如何修复此问题,以便将已发布的数据作为客户对象传递?
如果可能的话,应该使用内容类型:application/x-www-form-urlencoded,因为我不知道如何在发布表单的javascript方法中更改它。
控制器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class CustomersController : ApiController { public object Post([FromBody] Customer customer) { return Request.CreateResponse(HttpStatusCode.OK, new { customer = customer }); } } } public class Customer { public string company_name { get; set; } public string contact_name { get; set; } } |
请求:
1 2 3 4 5 6 | POST http://localhost:52216/api/customers HTTP/1.1 Accept: application/json, text/javascript, */*; q=0.01 X-Requested-With: XMLHttpRequest Content-Type: application/x-www-form-urlencoded; charset=UTF-8 {"contact_name":"sdfsd","company_name":"ssssd"} |
编辑:2017年10月31日
同样的代码/方法也适用于ASP.NET核心2.0。主要的区别在于,在ASP.NET核心中,Web API控制器和MVC控制器都被合并到单个控制器模型中。所以您的返回类型可能是
使用
1 | contentType:"application/json" |
发送时需要使用
模型绑定器将JSON数据绑定到类对象。
以下代码可以正常工作(已测试)
1 2 3 4 5 6 7 8 9 | $(function () { var customer = {contact_name :"Scott",company_name:"HP"}; $.ajax({ type:"POST", data :JSON.stringify(customer), url:"api/Customer", contentType:"application/json" }); }); |
结果
如果检查Ajax请求的头,可以看到
如果不显式指定ContentType,它将使用默认的内容类型,即
2015年11月编辑,以解决评论中提出的其他可能问题。
发布复杂对象假设有一个复杂的视图模型类作为Web API操作方法参数,如下所示
1 2 3 4 5 6 7 8 9 10 11 | public class CreateUserViewModel { public int Id {set;get;} public string Name {set;get;} public List<TagViewModel> Tags {set;get;} } public class TagViewModel { public int Id {set;get;} public string Code {set;get;} } |
你的Web API的终点是
1 2 3 4 5 6 7 8 9 10 11 | public class ProductController : Controller { [HttpPost] public CreateUserViewMode Save([FromBody] CreateUserViewModel m) { // I am just returning the posted model as it is. // You may do other stuff and return different response. // Ex : missileService.LaunchMissile(m); return m; } } |
在编写本文时,ASP.NET MVC 6是最新的稳定版本,在MVC6中,Web API控制器和MVC控制器都继承自
要从客户端向方法发送数据,下面的代码应该可以正常工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //Build an object which matches the structure of our view model class var model = { Name:"Shyju", Id: 123, Tags: [{ Id: 12, Code:"C" }, { Id: 33, Code:"Swift" }] }; $.ajax({ type:"POST", data: JSON.stringify(model), url:"../product/save", contentType:"application/json" }).done(function(res) { console.log('res', res); // Do something with the result :) }); |
模型绑定适用于某些属性,但并非所有属性!为什么?
如果不使用
1 2 3 4 5 | [HttpPost] public CreateUserViewModel Save(CreateUserViewModel m) { return m; } |
在不指定ContentType属性值的情况下发送模型(原始javascript对象,而不是JSON格式)
1 2 3 4 5 6 7 | $.ajax({ type:"POST", data: model, url:"../product/save" }).done(function (res) { console.log('res', res); }); |
模型绑定将适用于模型上的平面属性,而不是类型复杂/其他类型的属性。在我们的例子中,
如果您使用的是短版本
1 2 3 4 | $.post("../product/save", model, function (res) { //res contains the markup returned by the partial view console.log('res', res); }); |
在webapi中使用post可能很棘手!希望添加到已经正确的答案中。
将重点放在post上,因为处理get是微不足道的。我不认为有多少人会到处寻找用webapis解决get问题的方法。不管怎样…
如果您的问题是-在MVC Web API中,如何-使用通用HTTP谓词以外的自定义操作方法名称?-执行多个职位?-发布多个简单类型?-通过jquery发布复杂类型?
那么,以下解决方案可能会有所帮助:
首先,要在Web API中使用自定义操作方法,请将Web API路由添加为:
1 2 3 4 5 6 | public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name:"ActionApi", routeTemplate:"api/{controller}/{action}"); } |
然后您可以创建如下操作方法:
1 2 3 4 5 | [HttpPost] public string TestMethod([FromBody]string value) { return"Hello from http post web api controller:" + value; } |
现在,从浏览器控制台启动以下jquery
1 2 3 4 5 6 7 8 | $.ajax({ type: 'POST', url: 'http://localhost:33649/api/TestApi/TestMethod', data: {'':'hello'}, contentType: 'application/x-www-form-urlencoded', dataType: 'json', success: function(data){ console.log(data) } }); |
第二,要执行多个日志,它很简单,创建多个操作方法,并用[httppost]attrib进行修饰。使用[actionname("myaction")]来分配自定义名称等。将在下面的第四点进入jquery。
第三,首先,在一个操作中发布多个简单类型是不可能的。此外,还有一种特殊的格式可以发布一个简单的类型(除了在查询字符串或REST样式中传递参数)。这正是我与REST客户机(如Fiddler和Chrome的高级REST客户机扩展)发生冲突并在网络上搜索了近5个小时的原因,最终,以下URL证明是有帮助的。将引用链接的相关内容可能会失效!
1 2 3 | Content-Type: application/x-www-form-urlencoded in the request header and add a = before the JSON statement: ={"Name":"Turbo Tina","Email":"[email protected]"} |
附言:注意到特殊的语法了吗?
http://forums.asp.net/t/1883467.aspx?当+i+try+to+post+to+my+web+api时,+received+value+为+null+
不管怎样,让我们把那个故事讲清楚。继续前进:
第四,通过jquery发布复杂类型,当然,$.ajax()将很快成为角色:
假设action方法接受一个具有ID和名称的Person对象。因此,从javascript:
1 2 3 4 5 6 7 8 9 | var person = { PersonId:1, Name:"James" } $.ajax({ type: 'POST', url: 'http://mydomain/api/TestApi/TestMethod', data: JSON.stringify(person), contentType: 'application/json; charset=utf-8', dataType: 'json', success: function(data){ console.log(data) } }); |
这个动作看起来像:
1 2 3 4 5 | [HttpPost] public string TestMethod(Person person) { return"Hello from http post web api controller:" + person.Name; } |
所有这些,都为我工作!干杯!
我只是在玩这个,发现了一个相当奇怪的结果。假设您在C中的类上有公共属性,如下所示:
1 2 3 4 5 | public class Customer { public string contact_name; public string company_name; } |
然后您必须按照shyju的建议执行json.stringify技巧,并按如下方式调用它:
1 2 3 4 5 6 7 | var customer = {contact_name :"Scott",company_name:"HP"}; $.ajax({ type:"POST", data :JSON.stringify(customer), url:"api/Customer", contentType:"application/json" }); |
但是,如果您像这样在类上定义getter和setter:
1 2 3 4 5 | public class Customer { public string contact_name { get; set; } public string company_name { get; set; } } |
然后你可以更简单地称之为:
1 2 3 4 5 | $.ajax({ type:"POST", data :customer, url:"api/Customer" }); |
这将使用HTTP头:
10我不太确定这里发生了什么,但它看起来像一个bug(特性?)在框架中。假设不同的绑定方法调用不同的"适配器",而application/json-one的适配器使用公共属性,而表单编码数据的适配器则不使用公共属性。
不过,我不知道哪一个是最佳实践。
使用json.stringify()获取json格式的字符串,确保在进行Ajax调用时传递以下属性:
- contenttype:'application/json'
- 数据类型:"json"
下面是用于对ASP.NET Web API进行Ajax Post调用的give jquery代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var product = JSON.stringify({ productGroup:"Fablet", productId: 1, productName:"Lumia 1525 64 GB", sellingPrice: 700 }); $.ajax({ URL: 'http://localhost/api/Products', type: 'POST', contentType: 'application/json', dataType: 'json', data: product, success: function (data, status, xhr) { alert('Success!'); }, error: function (xhr, status, error) { alert('Update Error occurred - ' + error); } }); |
1)在客户端,您可以像下面这样以字符串形式向您发送http.post请求
1 2 | var IndexInfo = JSON.stringify(this.scope.IndexTree); this.$http.post('../../../api/EvaluationProcess/InsertEvaluationProcessInputType',"'" + IndexInfo +"'" ).then((response: any) => {} |
2)然后在Web API控制器中,可以对其进行反序列化。
1 2 3 | public ApiResponce InsertEvaluationProcessInputType([FromBody]string IndexInfo) { var des = (ApiReceivedListOfObjects<TempDistributedIndex>)Newtonsoft.Json.JsonConvert.DeserializeObject(DecryptedProcessInfo, typeof(ApiReceivedListOfObjects<TempDistributedIndex>));} |
3)ApiReceivedListFobjects类应如下所示
1 2 3 4 5 | public class ApiReceivedListOfObjects<T> { public List<T> element { get; set; } } |
4)确保在步骤2中的jsonconvert.DeserializeObject命令之前,序列化字符串(此处为indexinfo)的结构如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var resp = @" { ""element"": [ { ""A"":""A Jones"", ""B"":""500015763"" }, { ""A"":""B Smith"", ""B"":""504986213"" }, { ""A"":""C Brown"", ""B"":""509034361"" } ] }"; |
微软举了一个很好的例子:
https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-1
首先验证请求
1 | if (ModelState.IsValid) |
然后使用序列化数据。
1 | Content = new StringContent(update.Status) |
这里的"status"是复杂类型中的字段。序列化是由.NET完成的,无需担心这一点。
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | @model MVCClient.Models.ProductDetails @{ ViewBag.Title ="ProductDetails"; } <script src="~/Scripts/jquery-1.8.2.min.js"> <script type="text/javascript"> $(document).ready(function () { $("#Save").click(function () { var ProductDetails = new Object(); ProductDetails.ProductName = $("#txt_productName").val(); ProductDetails.ProductDetail = $("#txt_desc").val(); ProductDetails.Price= $("#txt_price").val(); $.ajax({ url:"http://localhost:24481/api/Product/addProduct", type:"Post", dataType:'JSON', data:ProductDetails, success: function (data) { alert('Updated Successfully'); //window.location.href="../Index"; }, error: function (msg) { alert(msg); } }); }); }); ProductDetails <form id="form1" method="post"> <fieldset> <legend>ProductDetails</legend> @Html.LabelFor(model => model.ProductName) <input id="txt_productName" type="text" name="fname"> @Html.ValidationMessageFor(model => model.ProductName) @Html.LabelFor(model => model.ProductDetail) <input id="txt_desc" type="text" name="fname"> @Html.ValidationMessageFor(model => model.ProductDetail) @Html.LabelFor(model => model.Price) <input id="txt_price" type="text" name="fname"> @Html.ValidationMessageFor(model => model.Price) <p> <input id="Save" type="button" value="Create" /> </p> </fieldset> </form> @Html.ActionLink("Back to List","Index") </form> @section Scripts { @Scripts.Render("~/bundles/jqueryval") } |
以下代码返回JSON格式的数据,而不是XML-WebAPI 2:
在global.asax文件中放入以下行
1 2 | GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter); |
确保您的WebAPI服务需要一个具有与您正在传递的JSON匹配的结构的强类型对象。并确保将要发布的JSON串接起来。
这是我的javascript(使用angguarjs):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | $scope.updateUserActivity = function (_objuserActivity) { $http ({ method: 'post', url: 'your url here', headers: { 'Content-Type': 'application/json'}, data: JSON.stringify(_objuserActivity) }) .then(function (response) { alert("success"); }) .catch(function (response) { alert("failure"); }) .finally(function () { }); |
这是我的WebAPI控制器:
1 2 3 4 5 6 | [HttpPost] [AcceptVerbs("POST")] public string POSTMe([FromBody]Models.UserActivity _activity) { return"hello"; } |