ASP.NET MVC4 Web API 应用程序定义了 post 方法来保存客户。客户在 POST 请求正文中以 json 格式传递。 post 方法中的客户参数包含属性的空值。
如何解决这个问题,以便发布的数据将作为客户对象传递?
如果可能的话 Content-Type: application/x-www-form-urlencoded 应该使用,因为我不知道如何在发布表单的 javascript 方法中更改它。
控制器:
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"}
编辑:2017 年 10 月 31 日
同样的代码/方法也适用于 Asp.Net Core 2.0。主要区别在于,在 asp.net core 中,web api 控制器和 Mvc 控制器都合并为单个控制器模型。因此,您的返回类型可能是 IActionResult
或其实现之一(例如:OkObjectResult
)
利用
contentType:"application/json"
发送时需要使用 JSON.stringify
方法将其转换为 JSON 字符串,
模型绑定器会将 json 数据绑定到您的类对象。
下面的代码可以正常工作(经过测试)
$(function () {
var customer = {contact_name :"Scott",company_name:"HP"};
$.ajax({
type: "POST",
data :JSON.stringify(customer),
url: "api/Customer",
contentType: "application/json"
});
});
结果
https://i.stack.imgur.com/69yQt.png
contentType
属性告诉服务器我们正在以 JSON 格式发送数据。由于我们发送了 JSON 数据结构,模型绑定将正确发生。
如果您检查 ajax 请求的标头,您可以看到 Content-Type
值设置为 application/json
。
如果您没有明确指定 contentType,它将使用默认的内容类型,即 application/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 CreateUserViewModel 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
基类。
要从客户端向方法发送数据,下面的代码应该可以正常工作
//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;
}
并在不指定 contentType 属性值的情况下发送模型(原始 javascript 对象,不是 JSON 格式)
$.ajax({
type: "POST",
data: model,
url: "../product/save"
}).done(function (res) {
console.log('res', res);
});
模型绑定将适用于模型上的平面属性,而不是类型为复杂/其他类型的属性。在我们的例子中,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 是微不足道的。我不认为很多人会四处寻找解决 GET 与 webapis 的问题。无论如何..
如果您的问题是 - 在 MVC Web Api 中,如何 - 使用通用 HTTP 动词以外的自定义操作方法名称? - 执行多个帖子? - 发布多种简单类型? - 通过 jQuery 发布复杂类型?
那么以下解决方案可能会有所帮助:
首先,要在 Web API 中使用自定义操作方法,请添加一个 Web api 路由:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}");
}
然后您可以创建操作方法,例如:
[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,很简单,创建多个action方法并用[HttpPost]属性装饰。使用 [ActionName("MyAction")] 来分配自定义名称等。下面第四点会来到jQuery
第三,首先,不可能在单个操作中发布多个 SIMPLE 类型。此外,有一种特殊的格式可以发布一个简单的类型(除了在查询字符串或 REST 样式中传递参数)。这就是让我与 Rest Clients(如 Fiddler 和 Chrome 的 Advanced REST 客户端扩展)并在网上搜寻近 5 个小时的原因,最终,以下 URL 被证明是有帮助的。会引用相关内容的链接可能会死机!
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 发布复杂类型,当然 $.ajax() 将立即发挥作用:
假设 action 方法接受一个 Person 对象,它有一个 id 和一个名字。所以,从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 的建议执行 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
我不太确定这里发生了什么,但它看起来像是框架中的一个错误(功能?)。据推测,不同的绑定方法正在调用不同的“适配器”,而用于 application/json 的适配器与公共属性一起使用,而用于表单编码数据的适配器则不能。
我不知道哪个会被认为是最佳实践。
使用 JSON.stringify() 获取 JSON 格式的字符串,确保在进行 AJAX 调用时传递以下提到的属性:
内容类型:'应用程序/json'
下面是给 ajax 后调用 asp.net web api 的 jquery 代码:
var product = JSON.stringify({ productGroup: "Fablet", productId: 1, productName: "Lumia 1525 64 GB", sellPrice: 700 }); $.ajax({ URL: 'http://localhost/api/Products', type: 'POST', contentType: 'application/json', data: product, success: function (data, status, xhr) { alert( '成功!'); }, error: function (xhr, status, error) { alert('发生更新错误 - ' + error); } });
确保您的 WebAPI 服务期望具有与您传递的 JSON 匹配的结构的强类型对象。并确保将要发布的 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
首先验证请求
if (ModelState.IsValid)
而不是使用序列化的数据。
Content = new StringContent(update.Status)
这里的“状态”是复杂类型中的一个字段。序列化由 .NET 完成,无需担心。
1)在您的客户端,您可以向您发送 http.post 请求,如下所示
var IndexInfo = JSON.stringify(this.scope.IndexTree);
this.$http.post('../../../api/EvaluationProcess/InsertEvaluationProcessInputType', "'" + IndexInfo + "'" ).then((response: any) => {}
2)然后在你的web api控制器中你可以反序列化它
public ApiResponce InsertEvaluationProcessInputType([FromBody]string IndexInfo)
{
var des = (ApiReceivedListOfObjects<TempDistributedIndex>)Newtonsoft.Json.JsonConvert.DeserializeObject(DecryptedProcessInfo, typeof(ApiReceivedListOfObjects<TempDistributedIndex>));}
3)您的 ApiReceivedListOfObjects 类应如下所示
public class ApiReceivedListOfObjects<T>
{
public List<T> element { get; set; }
}
4)确保您的序列化字符串(此处为 IndexInfo)在步骤 2 中的 JsonConvert.DeserializeObject 命令之前变为如下结构
var resp = @"
{
""element"": [
{
""A"": ""A Jones"",
""B"": ""500015763""
},
{
""A"": ""B Smith"",
""B"": ""504986213""
},
{
""A"": ""C Brown"",
""B"": ""509034361""
}
]
}";