代码之家  ›  专栏  ›  技术社区  ›  Rosstified

ASP.NET MVC如何将JSON对象作为参数从视图传递到控制器

  •  51
  • Rosstified  · 技术社区  · 16 年前

    我有一个复杂的JSON对象,它被发送到视图中,没有任何问题(如下所示),但我无法解决当通过Ajax调用将此数据传递回控制器时如何将其序列化回.NET对象。各部分的详细信息如下。

       var ObjectA = {
            "Name": 1,
            "Starting": new Date(1221644506800),
    
            "Timeline": [
                {
                    "StartTime": new Date(1221644506800),
                    "GoesFor": 200
    
                }
                ,
                {
                    "StartTime": new Date(1221644506800),
                    "GoesFor": 100
    
                }
    
            ]
        };
    

    我不知道如何将这个对象传递给控制器方法,我在下面有一个方法,Timelines对象使用属性镜像上面的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 回复  |  直到 16 年前
        1
  •  50
  •   ChadT    14 年前

    编辑:

    随着MVC 3的到来,不再需要这种方法,因为它将被自动处理。- http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx


    可以使用此对象筛选器:

        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”,那么它将立即生效,并将值映射到您指定类型的对象。

        2
  •  12
  •   Craig Stuntz    16 年前

    你说“我没有使用表单来操作数据”,但你正在做一个帖子。因此,实际上,您使用的是一个表单,即使它是空的。

    阿贾克斯 dataType 告诉jquery服务器的类型 返回 不是你要经过的。Post只能传递表单。JQuery will convert data to key/value pairs 并将其作为查询字符串传递。来自文档:

    要发送到服务器的数据。它是 如果不是,则转换为查询字符串 已经是一个字符串。它被附加到 获取请求的URL。查看过程数据 用于阻止此自动 处理。对象必须是键/值 对。如果值是数组,则jquery 用相同的值序列化多个值 键,即foo:[“bar1”,“bar2”] 变为“&foo=bar1&foo=bar2”。

    因此:

    1. 您不会将JSON传递给服务器。您正在将JSON传递给jquery。
    2. 模型绑定的发生方式与其他情况相同。
        3
  •  10
  •   Robert Koritnik    14 年前

    一个简单的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 . 我的解决方案利用了jQueryAjax功能,在该功能中,结果可能成功或错误(如上面的代码所示)。所以当验证失败时, error 函数将按预期的方式被调用。

        4
  •  4
  •   swilliams    16 年前

    JavaScriptSerializer 你也可以用。这将允许您将JSON反序列化为.NET对象。有一个通用的 Deserialize<T> 不过,您需要.NET对象具有与JavaScript对象相似的签名。另外还有一个 DeserializeObject 简单明了的方法 object . 然后可以使用反射来获取所需的属性。

    如果你的控制器 FormCollection ,并且您没有向 data JSON应该在 form[0] :

    public ActionResult Save(FormCollection forms) {
      string json = forms[0];
      // do your thing here.
    }
    
        5
  •  2
  •   CatDadCode    14 年前

    此答案是使用对象过滤器的Darkon_uuu答案的后续:

    [ObjectFilter(Param = "postdata", RootType = typeof(ObjectToSerializeTo))]
        public JsonResult ControllerMethod(ObjectToSerializeTo postdata) { ... }
    

    我遇到了一个问题,就是如何将多个参数发送到一个操作方法,其中一个是JSON对象,另一个是纯字符串。我是MVC的新手,我刚刚忘记我已经用非半开视图解决了这个问题。

    如果一个视图上需要两个不同的对象,我会怎么做。我将创建一个ViewModel类。如果我需要Person对象和Address对象,我将执行以下操作:

    public class SomeViewModel()
    {
         public Person Person { get; set; }
         public Address Address { get; set; }
    }
    

    然后我将视图绑定到某个ViewModel。您可以对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;
         }
    });
    
        6
  •  1
  •   Crescent Fresh    11 年前

    针对丹的上述评论:

    我正在使用此方法实现 同样的,但出于某种原因我 我有个例外 readObject方法:“应为元素 命名空间“”中的“根”。…遇到 名为“”、命名空间为“”的“无”。 有什么想法吗?丹·阿普里亚德4月6日 10在17:57

    我也遇到了同样的问题(MVC 3构建3.0.11209.0),下面的文章为我解决了这个问题。基本上,JSON序列化程序正在尝试读取一个不在开头的流,因此将该流重新定位为0“fixed”…

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