我有一个复杂的JSON对象,它被发送到View而没有任何问题(如下所示)但我无法弄清楚当通过AJAX调用将数据传递回控制器时如何将此数据序列化回.NET对象。各部分的详细信息如下。
var ObjectA = {
"Name": 1,
"Starting": new Date(1221644506800),
"Timeline": [
{
"StartTime": new Date(1221644506800),
"GoesFor": 200
}
,
{
"StartTime": new Date(1221644506800),
"GoesFor": 100
}
]
};
我不确定如何将此对象传递给Controller方法,我在下面使用此方法,其中Timelines对象使用Properties镜像上述JS对象。
public JsonResult Save(Timelines person)
我使用的jQuery是:
var encoded = $.toJSON(SessionSchedule);
$.ajax({
url: "/Timeline/Save",
type: "POST",
dataType: 'json',
data: encoded,
contentType: "application/json; charset=utf-8",
beforeSend: function() { $("#saveStatus").html("Saving").show(); },
success: function(result) {
alert(result.Result);
$("#saveStatus").html(result.Result).show();
}
});
我已经看到这个问题与我没有使用表单操作数据相似,但不完全相同。 How to pass complex type using json to ASP.NET MVC controller
我也看到了使用'JsonFilter'手动反序列化JSON的引用,但是想知道是否有办法通过ASP.NET MVC进行本地化操作?或者以这种方式传递数据的最佳做法是什么?
答案 0 :(得分:50)
修改
随着MVC 3的到来,不再需要这种方法,因为它将自动处理 - http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx
您可以使用此ObjectFilter:
public class ObjectFilter : ActionFilterAttribute {
public string Param { get; set; }
public Type RootType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if ((filterContext.HttpContext.Request.ContentType ?? string.Empty).Contains("application/json")) {
object o =
new DataContractJsonSerializer(RootType).ReadObject(filterContext.HttpContext.Request.InputStream);
filterContext.ActionParameters[Param] = o;
}
}
}
然后您可以将它应用于您的控制器方法,如下所示:
[ObjectFilter(Param = "postdata", RootType = typeof(ObjectToSerializeTo))]
public JsonResult ControllerMethod(ObjectToSerializeTo postdata) { ... }
所以基本上,如果帖子的内容类型是“application / json”,这将会生效,并将值映射到您指定类型的对象。
答案 1 :(得分:12)
你说“我没有使用表单来操纵数据。”但你正在做一个POST。因此,实际上,您使用的是表格,即使它是空的。
$ .ajax的dataType告诉jQuery服务器将返回的类型,而不是你传递的内容。 POST只能传递一个表单。 jQuery will convert data to key/value pairs并将其作为查询字符串传递。来自文档:
要发送到服务器的数据。它是 转换为查询字符串,如果没有 已经是一个字符串它被附加到了 GET请求的网址。请参阅processData 防止这种自动化的选项 处理。对象必须是键/值 对。如果value是一个数组,那么jQuery 用相同的序列化多个值 键即{foo:[“bar1”,“bar2”]} 成为'& foo = bar1& foo = bar2'。
因此:
答案 2 :(得分:10)
即使这个问题的答案早就应该了,但是我仍然发布了一个很好的解决方案,这是我前面提到的,并且非常简单将复杂的JSON发送到Asp.net MVC 控制器动作,因此它们是模型绑定到任何强类型参数。
此插件也支持日期,因此它们会毫无问题地转换为DateTime
版本。
您可以在my blog post中找到我检查问题的所有详细信息,并提供完成此操作所需的代码。
您所要做的就是在客户端使用此插件。 Ajax请求看起来像这样:
$.ajax({
type: "POST",
url: "SomeURL",
data: $.toDictionary(yourComplexJSONobject),
success: function() { ... },
error: function() { ... }
});
但这只是整个问题的一部分。现在我们可以将复杂的JSON发布回服务器,但由于它将模型绑定到可能在属性上具有验证属性的复杂类型,因此事情可能会失败。我有一个solution for it as well。我的解决方案利用了jQuery Ajax功能,其结果可能是成功的或错误的(正如上面的代码所示)。因此,当验证失败时,error
函数将被调用,因为它应该是。
答案 3 :(得分:4)
您也可以使用JavaScriptSerializer课程。这将允许您将json反序列化为.NET对象。虽然你需要.NET对象具有与javascript类似的签名,但是有一个通用Deserialize<T>
。此外,还有一个DeserializeObject
方法,只是简单object
。然后,您可以使用反射来获取所需的属性。
如果您的控制器使用FormCollection
,并且您没有向data
添加任何其他内容,则json应位于form[0]
中:
public ActionResult Save(FormCollection forms) {
string json = forms[0];
// do your thing here.
}
答案 4 :(得分:2)
这个答案是DaRKoN_使用对象过滤器的答案的后续行动:
[ObjectFilter(Param = "postdata", RootType = typeof(ObjectToSerializeTo))]
public JsonResult ControllerMethod(ObjectToSerializeTo postdata) { ... }
我在解决如何将多个参数发送到action方法时遇到问题,并且其中一个参数是json对象而另一个是纯字符串。我是MVC的新手,我忘记了我已经用非ajaxed视图解决了这个问题。
如果我需要一个视图上的两个不同的对象,我会怎么做。我会创建一个ViewModel类。所以说我需要person对象和地址对象,我会做以下事情:
public class SomeViewModel()
{
public Person Person { get; set; }
public Address Address { get; set; }
}
然后我将视图绑定到SomeViewModel。你可以用JSON做同样的事情。
[ObjectFilter(Param = "jsonViewModel", RootType = typeof(JsonViewModel))] // Don't forget to add the object filter class in DaRKoN_'s answer.
public JsonResult doJsonStuff(JsonViewModel jsonViewModel)
{
Person p = jsonViewModel.Person;
Address a = jsonViewModel.Address;
// Do stuff
jsonViewModel.Person = p;
jsonViewModel.Address = a;
return Json(jsonViewModel);
}
然后在视图中你可以使用JQuery这样的简单调用:
var json = {
Person: { Name: "John Doe", Sex: "Male", Age: 23 },
Address: { Street: "123 fk st.", City: "Redmond", State: "Washington" }
};
$.ajax({
url: 'home/doJsonStuff',
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(json), //You'll need to reference json2.js
success: function (response)
{
var person = response.Person;
var address = response.Address;
}
});
答案 5 :(得分:1)
回应丹的上述评论:
我正在使用此方法来实现 同样的事情,但出于某种原因我 我正在接受例外 ReadObject方法:“期待元素 'root'来自命名空间''..遇到了 '无',名称'',名称空间''。“ 有什么想法吗? - Dan Appleyard 4月6日 '10在17:57
我有同样的问题(MVC 3 build 3.0.11209.0),下面的帖子为我解决了。基本上json序列化器试图读取一个不在开头的流,所以将流重新定位为0'固定'它...