ASP.NET MVC如何将JSON对象从View传递给Controller作为参数

时间:2009-02-18 10:49:07

标签: asp.net-mvc json

我有一个复杂的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进行本地化操作?或者以这种方式传递数据的最佳做法是什么?

6 个答案:

答案 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'。

因此:

  1. 您没有将JSON传递给服务器。你正在将JSON传递给jQuery。
  2. 模型绑定的发生方式与其他情况相同。

答案 2 :(得分:10)

使用简单的jQuery插件

的另一种看法

即使这个问题的答案早就应该了,但是我仍然发布了一个很好的解决方案,这是我前面提到的,并且非常简单将复杂的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'固定'它...

http://nali.org/asp-net-mvc-expecting-element-root-from-namespace-encountered-none-with-name-namespace/