我正在开发一个ASP.Net MVC5应用程序,我试图通过AJAX请求将JSON数据传递给控制器的操作方法。 JSON数据包含许多表单值。由于我试图创建一个主数据表单,其中数据要在数据库中以一对多格式发布,因此我创建了一个这样的对象:
var salesmain = {
"SalesId": "",
"ReferenceNo": "",
"SalesDate": "",
"SalesPerson": "",
"SalesSubs": []
};
请注意,在上面的数据中,SalesSubs
属性是以这种方式声明的数组:
var salessub = {
"SalesId": "",
"ItemName": "",
"Qty": "",
"UnitPrice":""
};
所以,现在我发现一个salesmain
可以包含许多salessub
或salessub
数组。在我推送一些值并将AJAX请求传递给action方法后,它将SalesSubs
数组作为null
。我在那里放了一个断点来检查它:
在上面的图片salesmain.SalesSubs
中,这是一个数组null
,这就是我尝试将数据传递给动作的方式:
$.ajax({
url: '/Sales/Create',
data: addRequestVerificationToken(salesmain),
type: 'POST',
dataType: 'json',
traditional : true,
success: function (result) {
if (result.Success == "1") {
window.location.href = "/Sales/Index";
}
else {
alert(result.ex);
}
}
});
这就是我在SalesSubs
数组中推送值的方式:
salesmain.SalesId = $("#SalesId").val();
salesmain.ReferenceNo = $("#ReferenceNo").val();
salesmain.SalesDate = $("#SalesDate").val();
salesmain.SalesPerson = $("#SalesPerson").val();
$('.tbl').DataTable().rows().data().each(function (value, index) {
salessub.ItemName = value[0];
salessub.Qty = value[1];
salessub.UnitPrice = value[2];
salesmain.SalesSubs.push(salessub);
});
在上面的代码中,我使用了jQuery的datatable插件来从DataTable中获取整个salessub数据。我认为salesmain在执行ajax请求之前包含一个完整的有效数据,但不知何故ajax请求在执行后没有携带salesmain对象的数组数据(SalesSubs)。
我的AJAX部分代码有什么问题吗?使用AJAX请求将JSON数据传递给action方法的正确方法是什么?
编辑:
这是SalesMain.cs模型:
public class SalesMain
{
[Key]
public int SalesId { get; set; }
public string ReferenceNo { get; set; }
public DateTime SalesDate { get; set; }
public string SalesPerson { get; set; }
public virtual ICollection<SalesSub> SalesSubs { get; set; }
}
和SalesSub.cs模型:
public class SalesSub
{
[Key, Column(Order = 0)]
public int SalesId { get; set; }
[Key, Column(Order = 1)]
public string ItemName { get; set; }
public int Qty { get; set; }
public decimal UnitPrice { get; set; }
public virtual SalesMain SalesMain { get; set; }
}
和SalesController创建方法:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "SalesId,ReferenceNo,SalesDate,SalesPerson")] SalesMain salesmain)
{
try
{
if (ModelState.IsValid)
{
// Perform Update
if (salesmain.SalesId > 0)
{
var CurrentsalesSUb = db.SalesSubs.Where(p => p.SalesId == salesmain.SalesId);
foreach (SalesSub ss in CurrentsalesSUb)
db.SalesSubs.Remove(ss);
foreach (SalesSub ss in salesmain.SalesSubs)
db.SalesSubs.Add(ss);
db.Entry(salesmain).State = EntityState.Modified;
}
//Perform Save
else
{
db.SalesMains.Add(salesmain);
}
db.SaveChanges();
return Json(new { Success = 1, SalesID = salesmain.SalesId, ex = "" });
}
}
catch (Exception ex)
{
return Json(new { Success = 0, ex = ex.Message.ToString() });
}
return Json(new { Success = 0, ex = new Exception("Unable to save").Message.ToString() });
}
如果在发送ajax请求之前我console.log(salesmain)
,这就是我得到的:
所以,我认为上述数据可以通过ajax请求移动,但现在当它到达动作salesmain.SalesSubs
变为null
时,只有SalesMain表填充在数据库中,并且SalesSub表保持为空(未实现映射)。
进一步修改:
添加contentType : 'application/json'
和data : JSON.stringify(salesmain)
导致500内部服务器错误,在控制台窗口中检查后,错误显示:
The required anti-forgery form field “__RequestVerificationToken” is not present.
它真的不存在吗?因为我已经为此创建了一个函数:
function addRequestVerificationToken(data) {
data.__RequestVerificationToken = $('input[name=__RequestVerificationToken]').val();
return data;
};
当我使用salesmain
和contentType : "application/json"
时,上述代码不会将令牌添加到JSON.stringify()
,而是在删除这两个代码时添加。
答案 0 :(得分:1)
使用JSON.stringify方法将js对象转换为json字符串化版本。同时将contentType指定为“application / json”。
$.ajax({
data: JSON.stringify(salesmain),
contentType : "application/json",
success: function (result) { alert(result); }
// Your existing code
});
我还建议使用Url.Action
之类的Html帮助程序来生成操作方法的正确相对路径,而不是对其进行硬编码。
url: '@Url.Action("Create","Sales")',
如果您的js代码位于剃刀视图中,则上述应该有效。如果您的代码位于外部js文件中,请使用this post中描述的解决方案。
编辑:当您使用contentType='application/json'
发送数据时,您的RequestVerificationToken
无法正常工作,因为代码希望表单正常提交(其中contentType设置为默认值“{{1 }}“)。因此,您可以在HttpPost操作方法中禁用application/x-www-form-urlencoded
。
此外,我发现您使用了Bind属性仅包含某些属性。您需要将[ValidateAntiForgeryToken]
属性添加到包含列表中,以便模型绑定也适用于该属性。
以下代码应该可以正常工作。
发送数据的客户端代码。
SalesSubs
服务器代码将是
var salesmain = { SalesSubs: [] };
salesmain.SalesId =33;
salesmain.ReferenceNo ="Test";
salesmain.SalesDate ="12/12/2004";
salesmain.SalesPerson = "Shyju";
var salessub = {};
salessub.ItemName = "Test";
salessub.Qty = 2;
salessub.UnitPrice = 25.33;
salesmain.SalesSubs.push(salessub);
console.log(salesmain);
$.ajax({
url: '/Sales/Create' ,
data: JSON.stringify(salesmain),
type: 'POST',
contentType: 'application/json',
success: function (result) {
console.log('response');
console.log(result);
}
});
best way to prevent over posting是使用视图模型,其中包含您从视图中绝对需要的属性。我个人更喜欢这种方法在视图和操作方法之间传输数据,而不是使用带有Bind属性的ORM生成的实体类。