如何将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的属性。 在我们的例子中, Id
和Name
属性将被正确绑定到参数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完成的,不需要担心。