最近,我们将应用程序从MVC3更新到了MVC4。在MVC4中,我们发现ViewModel中的属性名称如Studio
和StudioExecutive
会在发布时引起问题。在控制器方法中,当填充Studio = null
时,我们总是会得到StudioExecutive
。
这是我们问题的一个示例,希望对此有一个答案。
资料类别:
public class TestContact
{
public List<TestContactItem> Studio { get; set; }
public List<TestContactItem> StudioExecutive { get; set; }
public TestContact()
{
Studio = new List<TestContactItem>();
StudioExecutive = new List<TestContactItem>();
}
}
public class TestContactItem
{
public int Id { get; set; }
public string Name { get; set; }
}
控制器方法:
public ActionResult TestContactView()
{
var vm = new TestContact();
vm.Studio.Add(new TestContactItem(){Id=1, Name = "Studio Contact ID=1"});
vm.StudioExecutive.Add(new TestContactItem() { Id = 2, Name = "Studio Exec Contact ID=2" });
return View(vm);
}
[HttpPost]
public ActionResult SaveTestContact(TestContact model)
{
return Content("success");
}
使用Ajax POST查看/ JavaScript:
@using System.Web.Script.Serialization
@model TestContact
<button type="button" onclick="SaveTestContact();">Click Here to Post</button>
<script type="text/javascript">
$(document).ready(function() {
globalTestModel = @Html.Raw(new JavaScriptSerializer().Serialize(Model));
});
function SaveTestContact() {
// passing additional studio & studio executive parameter to controller because it was not mapping correctly to the server side viewmodel without it
$.ajax({
type: "POST",
url: "/Test/SaveTestContact",
data: JSON.stringify(globalTestModel),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (msg) {
}
});
}
</script>
在此示例中,我们使用至少一个
Studio
和一个StudioExecutive
填充对象并渲染视图。单击视图中的按钮时,我们将相同的对象发布到控制器方法,但是ViewModel没有正确绑定,Studio
属性设置为null。*不幸的是,我无法发布图像,但该对象的屏幕快照显示
Studio
计数为0而StudioExecutive
计数为1我们确实在POST之前放置了一个断点,以确保JavaScript上的序列化正确并且对象已填充。
我们得出的结论是,这与两个属性的命名约定有关,两个属性是另一个属性的子字符串。任何遇到相同问题并可以为我们指明正确方向的人。
最佳答案
我知道这不是问题的“完整答案”,但我认为这将使问题更加深刻,(最终希望)最终将导致“完整解决方案”。
假设如操作示例中所示,每个Studio
和StudioExecutive
字段中都有一个项目,并在js
中执行以下操作:
globalTestModel = '@Html.Raw(new JavaScriptSerializer().Serialize(Model))';
$.ajax({
type: "POST",
url: "/Test/SaveTestContact",
data: JSON.stringify(globalTestModel),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (msg) {
}
});
如前所述,控制器方法将仅接收
StudioExecutive
。现在,如果我们执行相同的操作并如下所示在js中构建对象,我们将得到相同的结果。o = {
Studio: [{
Id: 1,
Name: 'Studio Contact ID=1',
}],
StudioExecutive: [{
Id: 2,
Name: 'Studio Exec Contact ID=2',
}]
};
$.ajax({
type: "POST",
url: "/Test/SaveTestContact",
data: JSON.stringify(o),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (msg) {
}
});
现在来了有趣的部分。如果我们在
Studio
字段中添加另一个项目并以相同的方式发布,我们将获得相同的结果。// Do this in the controller and do the same ajax post
public ActionResult TestContactView()
{
var vm = new TestContact();
vm.Studio.Add(new TestContactItem(){Id=1, Name = "Studio Contact ID=1"});
vm.Studio.Add(new TestContactItem(){Id=3, Name = "Studio Contact ID=3"});
vm.StudioExecutive.Add(new TestContactItem() { Id = 2, Name = "Studio Exec Contact ID=2" });
return View(vm);
}
但是,如果我们按如下所示在
js
中构建对象,则控制器将同时收到带有2个项目的Studio
和带有一个项目的StudioExecutive
。o = {
Studio: [{
Id: 1,
Name: 'Studio Contact ID=1',
},
{
Id: 2,
Name: 'Studio Contact ID=2',
}],
StudioExecutive: [{
Id: 2,
Name: 'Studio Exec Contact ID=2',
}]
};
// then do the ajax post
所以我们学了什么
这告诉我们两件事:
默认模型联编程序存在问题,因为它无法绑定两个或多个以相同名称开头的字段
如果只有一项,则
JSON.stringify
也不能执行此操作,但是如果字段中有多个具有最短名称的项(例如Studio
),它也可以执行此操作