如何将json POST数据作为对象传递给Web API方法?

ASP.NET MVC4 Web API应用程序定义了保存客户的post方法。 客户在POST请求正文中以json格式传递。 post方法中的Customer参数包含属性的空值。

如何解决这个问题,使发布的数据将作为客户对象传递?

如果可能的话,Content-Type:application / x-www-form-urlencoded应该被使用,因为我不知道如何改变它在javascript方法中的postforms。

控制器:

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; } } 

请求:

 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"} 

编辑 :31/10/2017

同样的代码/方法也适用于Asp.Net Core 2.0 。 主要区别在于,在asp.net核心中,web api控制器和Mvc控制器都被合并到一个控制器模型中。 所以你的返回types可能是IActionResult或者它的一个实现(Ex: OkObjectResult


使用

 contentType:"application/json" 

发送时需要使用JSON.stringify方法将其转换为JSONstring,

模型联编程序将绑定json数据到您的类对象。

下面的代码将正常工作(testing)

 $(function () { var customer = {contact_name :"Scott",company_name:"HP"}; $.ajax({ type: "POST", data :JSON.stringify(customer), url: "api/Customer", contentType: "application/json" }); }); 

结果

在这里输入图像描述

contentType属性告诉服务器我们以JSON格式发送数据。 由于我们发送了一个JSON数据结构,所以模型绑定会正确的发生。

如果您检查ajax请求的标题,您可以看到Content-Type值设置为application/json

如果你不明确指定contentType,它将使用默认的内容typesapplication/x-www-form-urlencoded;


在2015年11月编辑,以解决评论中提出的其他可能的问题

发布一个复杂的对象

假设你有一个复杂的视图模型类作为你的web api动作方法参数

 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终点是一样的

 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控制器都是从Microsoft.AspNet.Mvc.Controller基类inheritance而来的。

要从客户端发送数据到方法,下面的代码应该工作正常

 //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 :) }); 

模型绑定适用于某些属性,但不是全部! 为什么?

如果不用[FromBody]属性修饰web api方法参数

 [HttpPost] public CreateUserViewModel Save(CreateUserViewModel m) { return m; } 

并发送模型(原始JavaScript对象,不是JSON格式),而不指定contentType属性值

 $.ajax({ type: "POST", data: model, url: "../product/save" }).done(function (res) { console.log('res', res); }); 

模型绑定将适用于模型上的平面属性,而不是types复杂/另一types的属性。 在我们的例子中, IdName属性将被正确绑定到参数m ,但Tags属性将是一个空列表。

如果您使用短版本$.post发送请求时将使用默认的Content-Type,则会发生同样的问题。

 $.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动词之外的自定义动作方法名称? – 执行多个post? – 发布多个简单的types? – 通过jQuery发布复杂的types?

那么以下解决scheme可能会有帮助

首先,要在Web API中使用自定义操作方法,请添加一个Web api路由:

 public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "ActionApi", routeTemplate: "api/{controller}/{action}"); } 

然后你可以创build一些操作方法,如:

 [HttpPost] public string TestMethod([FromBody]string value) { return "Hello from http post web api controller: " + value; } 

现在,从浏览器控制台中触发以下jQuery

 $.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) } }); 

其次,要执行多个post ,很简单,创build多个操作方法并用[HttpPost]属性进行装饰。 使用[ActionName(“MyAction”)]来分配自定义名称等将在下面的第四点来到jQuery

第三,首先,在单个动作中发布多个SIMPLEtypes是不可能的。 此外,还有一种特殊的格式来发布甚至一个简单的types (除了在查询string或REST风格中传递参数)。 这是让我用rest客户端(如Fiddler和Chrome的高级REST客户端扩展)敲打我的脑袋,并最终在网上狩猎近5个小时,以下URL被certificate是有帮助的。 将引用链接的相关内容可能会死亡!

 Content-Type: application/x-www-form-urlencoded in the request header and add a = before the JSON statement: ={"Name":"Turbo Tina","Email":"na@Turbo.Tina"} 

PS:注意到特殊的语法

http://forums.asp.net/t/1883467.aspx?The+received+value+is+null+when+I+try+to+Post+to+my+Web+Api

无论如何,让我们来了解一下这个故事。 继续:

第四,通过jQuery 发布复杂types ,当然,$ .ajax()会立即起到作用:

让我们说动作方法接受一个具有一个id和一个名字的Person对象。 所以,从javascript:

 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) } }); 

行动将如下所示:

 [HttpPost] public string TestMethod(Person person) { return "Hello from http post web api controller: " + person.Name; } 

以上所有,为我工作! 干杯!

我刚刚玩了这个,发现了一个相当奇怪的结果。 假设你在C#中的类上有公共属性,如下所示:

 public class Customer { public string contact_name; public string company_name; } 

那么你必须按照Shyju的build议来做JSON.stringify技巧,并且像这样调用它:

 var customer = {contact_name :"Scott",company_name:"HP"}; $.ajax({ type: "POST", data :JSON.stringify(customer), url: "api/Customer", contentType: "application/json" }); 

但是,如果你在你的类上定义getter和setter,像这样:

 public class Customer { public string contact_name { get; set; } public string company_name { get; set; } } 

那么你可以更简单地调用它:

 $.ajax({ type: "POST", data :customer, url: "api/Customer" }); 

这使用HTTP标头:

 Content-Type:application/x-www-form-urlencoded 

我不太确定这里发生了什么,但是它看起来像框架中的一个bug(特征?)。 据推测,不同的绑定方法正在调用不同的“适配器”,而application / json的适配器可以使用公共属性,而编码数据的适配器则不能。

我不知道哪一个会被认为是最好的做法。

使用JSON.stringify()获取JSON格式的string,确保在进行AJAX调用时传递下面提到的属性:

  • contentType:'application / json'
  • dataType:'json'

下面是给jquery代码做ajax post调用asp.net web api:

 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); } }); 

确保您的WebAPI服务正在等待一个结构与您传递的JSON匹配的强types对象。 并确保您将您正在发布的JSON串联起来。

这是我的JavaScript(使用AngluarJS):

 $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控制器:

 [HttpPost] [AcceptVerbs("POST")] public string POSTMe([FromBody]Models.UserActivity _activity) { return "hello"; } 

以下代码以json格式返回数据,而不是xml -Web API 2: –

将下面的行放在Global.asax文件中

 GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter); 
 @model MVCClient.Models.ProductDetails @{ ViewBag.Title = "ProductDetails"; } <script src="~/Scripts/jquery-1.8.2.min.js"></script> <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); } }); }); }); </script> <h2>ProductDetails</h2> <form id="form1" method="post"> <fieldset> <legend>ProductDetails</legend> <div class="editor-label"> @Html.LabelFor(model => model.ProductName) </div> <div class="editor-field"> <input id="txt_productName" type="text" name="fname"> @Html.ValidationMessageFor(model => model.ProductName) </div> <div class="editor-label"> @Html.LabelFor(model => model.ProductDetail) </div> <div class="editor-field"> <input id="txt_desc" type="text" name="fname"> @Html.ValidationMessageFor(model => model.ProductDetail) </div> <div class="editor-label"> @Html.LabelFor(model => model.Price) </div> <div class="editor-field"> <input id="txt_price" type="text" name="fname"> @Html.ValidationMessageFor(model => model.Price) </div> <p> <input id="Save" type="button" value="Create" /> </p> </fieldset> </form> <div> @Html.ActionLink("Back to List", "Index") </div> </form> @section Scripts { @Scripts.Render("~/bundles/jqueryval") } 

微软给出了一个很好的例子:

https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-1

首先validation请求

 if (ModelState.IsValid) 

而不是使用序列化的数据。

 Content = new StringContent(update.Status) 

这里“状态”是复杂types中的一个字段。 序列化是由.NET完成的,不需要担心。