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

时间:2022-11-30 17:56:25

I have a complex JSON object which is sent to the View without any issues (as shown below) but I cannot work out how Serialize this data back to a .NET object when it is passed back to the controller through an AJAX call. Details of the various parts are below.

我有一个复杂的JSON对象,它被发送到视图中,没有任何问题(如下所示),但我无法计算当它通过AJAX调用返回给控制器时,如何将这些数据序列化到。net对象。各个部分的详细信息如下。

   var ObjectA = {
        "Name": 1,
        "Starting": new Date(1221644506800),

        "Timeline": [
            {
                "StartTime": new Date(1221644506800),
                "GoesFor": 200

            }
            ,
            {
                "StartTime": new Date(1221644506800),
                "GoesFor": 100

            }

        ]
    };

I am not sure how this object can be passed to a Controller Method, I have this method below where the Timelines object mirrors the above JS object using Properties.

我不确定如何将该对象传递给控制器方法,我有下面的方法,其中Timelines对象使用属性镜像上面的JS对象。

public JsonResult Save(Timelines person)

The jQuery I am using is:

我使用的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();
            }
        });

I have seen this question which is similar, but not quite the same as I am not using a forms to manipulate the data. How to pass complex type using json to ASP.NET MVC controller

我遇到过类似的问题,但并不完全相同,因为我没有使用表单来操作数据。如何使用json将复杂类型传递给ASP。净MVC控制器

I have also seen references to using a 'JsonFilter' to manually deserialize the JSON, but was wondering if there is a way to do it nativly though ASP.NET MVC? Or what are the best practices for passing data in this way?

我也看到过使用“JsonFilter”手动反序列化JSON的引用,但我想知道是否有一种方法可以通过ASP实现它。净MVC吗?或者,以这种方式传递数据的最佳实践是什么?

6 个解决方案

#1


50  

Edit:

编辑:

This method should no longer be needed with the arrival of MVC 3, as it will be handled automatically - http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx

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


You can use this ObjectFilter:

您可以使用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;
        }

    }
}

You can then apply it to your controller methods like so:

然后你可以将它应用到你的控制器方法中,比如:

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

So basically, if the content type of the post is "application/json" this will spring into action and will map the values to the object of type you specify.

因此,基本上,如果post的内容类型是“application/json”,它就会启动并将值映射到您指定的类型的对象。

#2


12  

You say "I am not using a forms to manipulate the data." But you are doing a POST. Therefore, you are, in fact, using a form, even if it's empty.

你说"我不是在用表格来操作数据"但你是在发帖子。因此,你实际上是在使用一个表单,即使它是空的。

$.ajax's dataType tells jQuery what type the server will return, not what you are passing. POST can only pass a form. jQuery will convert data to key/value pairs and pass it as a query string. From the docs:

美元。ajax的数据类型告诉jQuery服务器将返回什么类型,而不是传递什么。POST只能通过表单。jQuery将数据转换为键/值对,并将其作为查询字符串传递。从文档:

Data to be sent to the server. It is converted to a query string, if not already a string. It's appended to the url for GET-requests. See processData option to prevent this automatic processing. Object must be Key/Value pairs. If value is an Array, jQuery serializes multiple values with same key i.e. {foo:["bar1", "bar2"]} becomes '&foo=bar1&foo=bar2'.

要发送到服务器的数据。它被转换为查询字符串(如果不是字符串的话)。它被附加到get请求的url后面。请参阅processData选项以防止此自动处理。对象必须是键/值对。如果值是一个数组,jQuery使用相同的键(比如{foo:["bar1", "bar2")}序列化多个值,成为'&foo=bar1&foo=bar2'。

Therefore:

因此:

  1. You aren't passing JSON to the server. You're passing JSON to jQuery.
  2. 您不会将JSON传递给服务器。您将JSON传递给jQuery。
  3. Model binding happens in the same way it happens in any other case.
  4. 模型绑定的发生方式与其他情况相同。

#3


10  

A different take with a simple jQuery plugin

Even though answers to this question are long overdue, but I'm still posting a nice solution that I came with some time ago and makes it really simple to send complex JSON to Asp.net MVC controller actions so they are model bound to whatever strong type parameters.

尽管这个问题的答案早该给出,但我还是发布了一个很好的解决方案,我在一段时间以前就有了这个解决方案,它使得将复杂的JSON发送给Asp.net MVC控制器操作变得非常简单,因此它们是绑定到任何强类型参数的模型。

This plugin supports dates just as well, so they get converted to their DateTime counterpart without a problem.

这个插件同样支持日期,所以它们可以毫无问题地转换为它们的DateTime对等物。

You can find all the details in my blog post where I examine the problem and provide code necessary to accomplish this.

您可以在我的博客文章中找到所有的细节,我在这里检查这个问题并提供完成这个问题所需的代码。

All you have to do is to use this plugin on the client side. An Ajax request would look like this:

你所要做的就是在客户端使用这个插件。Ajax请求如下所示:

$.ajax({
    type: "POST",
    url: "SomeURL",
    data: $.toDictionary(yourComplexJSONobject),
    success: function() { ... },
    error: function() { ... }
});

But this is just part of the whole problem. Now we are able to post complex JSON back to server, but since it will be model bound to a complex type that may have validation attributes on properties things may fail at that point. I've got a solution for it as well. My solution takes advantage of jQuery Ajax functionality where results can be successful or erroneous (just as shown in the upper code). So when validation would fail, error function would get called as it's supposed to be.

但这只是整个问题的一部分。现在我们可以将复杂的JSON发送回服务器,但是由于它是绑定到复杂类型的模型,而这些复杂类型可能具有属性的验证属性,所以在这一点上可能会失败。我也有一个解。我的解决方案利用了jQuery Ajax功能,结果可以是成功的,也可以是错误的(如上面代码所示)。当验证失败时,错误函数会被调用。

#4


4  

There is the JavaScriptSerializer class you can use too. That will let you deserialize the json to a .NET object. There's a generic Deserialize<T>, though you will need the .NET object to have a similar signature as the javascript one. Additionally there is also a DeserializeObject method that just makes a plain object. You can then use reflection to get at the properties you need.

也可以使用JavaScriptSerializer类。这将使您可以将json反序列化为. net对象。有一个通用的反序列化 ,但是需要. net对象具有与javascript相似的签名。此外,还有一个DeserializeObject方法,它只生成一个普通对象。然后可以使用反射获取所需的属性。

If your controller takes a FormCollection, and you didn't add anything else to the data the json should be in form[0]:

如果您的控制器接受一个FormCollection,并且没有向数据添加任何其他内容,那么json应该是格式[0]:

public ActionResult Save(FormCollection forms) {
  string json = forms[0];
  // do your thing here.
}

#5


2  

This answer is a follow up to DaRKoN_'s answer that utilized the object filter:

这个答案是对使用对象过滤器的DaRKoN_答案的后续回答:

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

I was having a problem figuring out how to send multiple parameters to an action method and have one of them be the json object and the other be a plain string. I'm new to MVC and I had just forgotten that I already solved this problem with non-ajaxed views.

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

What I would do if I needed, say, two different objects on a view. I would create a ViewModel class. So say I needed the person object and the address object, I would do the following:

如果我需要视图上的两个不同的对象,我会怎么做。我将创建一个ViewModel类。假设我需要person对象和address对象,我会做以下事情:

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

Then I would bind the view to SomeViewModel. You can do the same thing with JSON.

然后我将视图绑定到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);
}

Then in the view you can use a simple call with JQuery like this:

然后在视图中,您可以使用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  

in response to Dan's comment above:

针对以上丹的评论:

I am using this method to implement the same thing, but for some reason I am getting an exception on the ReadObject method: "Expecting element 'root' from namespace ''.. Encountered 'None' with name '', namespace ''." Any ideas why? – Dan Appleyard Apr 6 '10 at 17:57

我正在使用这个方法来实现同样的事情,但是出于某种原因,我得到了ReadObject方法的一个异常:“期望元素‘root’from namespace”。遇到“None”的名称是“名称空间”。任何想法为什么?——丹·阿普尔里亚4月10日17点57分

I had the same problem (MVC 3 build 3.0.11209.0), and the post below solved it for me. Basically the json serializer is trying to read a stream which is not at the beginning, so repositioning the stream to 0 'fixed' it...

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

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

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

#1


50  

Edit:

编辑:

This method should no longer be needed with the arrival of MVC 3, as it will be handled automatically - http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx

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


You can use this ObjectFilter:

您可以使用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;
        }

    }
}

You can then apply it to your controller methods like so:

然后你可以将它应用到你的控制器方法中,比如:

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

So basically, if the content type of the post is "application/json" this will spring into action and will map the values to the object of type you specify.

因此,基本上,如果post的内容类型是“application/json”,它就会启动并将值映射到您指定的类型的对象。

#2


12  

You say "I am not using a forms to manipulate the data." But you are doing a POST. Therefore, you are, in fact, using a form, even if it's empty.

你说"我不是在用表格来操作数据"但你是在发帖子。因此,你实际上是在使用一个表单,即使它是空的。

$.ajax's dataType tells jQuery what type the server will return, not what you are passing. POST can only pass a form. jQuery will convert data to key/value pairs and pass it as a query string. From the docs:

美元。ajax的数据类型告诉jQuery服务器将返回什么类型,而不是传递什么。POST只能通过表单。jQuery将数据转换为键/值对,并将其作为查询字符串传递。从文档:

Data to be sent to the server. It is converted to a query string, if not already a string. It's appended to the url for GET-requests. See processData option to prevent this automatic processing. Object must be Key/Value pairs. If value is an Array, jQuery serializes multiple values with same key i.e. {foo:["bar1", "bar2"]} becomes '&foo=bar1&foo=bar2'.

要发送到服务器的数据。它被转换为查询字符串(如果不是字符串的话)。它被附加到get请求的url后面。请参阅processData选项以防止此自动处理。对象必须是键/值对。如果值是一个数组,jQuery使用相同的键(比如{foo:["bar1", "bar2")}序列化多个值,成为'&foo=bar1&foo=bar2'。

Therefore:

因此:

  1. You aren't passing JSON to the server. You're passing JSON to jQuery.
  2. 您不会将JSON传递给服务器。您将JSON传递给jQuery。
  3. Model binding happens in the same way it happens in any other case.
  4. 模型绑定的发生方式与其他情况相同。

#3


10  

A different take with a simple jQuery plugin

Even though answers to this question are long overdue, but I'm still posting a nice solution that I came with some time ago and makes it really simple to send complex JSON to Asp.net MVC controller actions so they are model bound to whatever strong type parameters.

尽管这个问题的答案早该给出,但我还是发布了一个很好的解决方案,我在一段时间以前就有了这个解决方案,它使得将复杂的JSON发送给Asp.net MVC控制器操作变得非常简单,因此它们是绑定到任何强类型参数的模型。

This plugin supports dates just as well, so they get converted to their DateTime counterpart without a problem.

这个插件同样支持日期,所以它们可以毫无问题地转换为它们的DateTime对等物。

You can find all the details in my blog post where I examine the problem and provide code necessary to accomplish this.

您可以在我的博客文章中找到所有的细节,我在这里检查这个问题并提供完成这个问题所需的代码。

All you have to do is to use this plugin on the client side. An Ajax request would look like this:

你所要做的就是在客户端使用这个插件。Ajax请求如下所示:

$.ajax({
    type: "POST",
    url: "SomeURL",
    data: $.toDictionary(yourComplexJSONobject),
    success: function() { ... },
    error: function() { ... }
});

But this is just part of the whole problem. Now we are able to post complex JSON back to server, but since it will be model bound to a complex type that may have validation attributes on properties things may fail at that point. I've got a solution for it as well. My solution takes advantage of jQuery Ajax functionality where results can be successful or erroneous (just as shown in the upper code). So when validation would fail, error function would get called as it's supposed to be.

但这只是整个问题的一部分。现在我们可以将复杂的JSON发送回服务器,但是由于它是绑定到复杂类型的模型,而这些复杂类型可能具有属性的验证属性,所以在这一点上可能会失败。我也有一个解。我的解决方案利用了jQuery Ajax功能,结果可以是成功的,也可以是错误的(如上面代码所示)。当验证失败时,错误函数会被调用。

#4


4  

There is the JavaScriptSerializer class you can use too. That will let you deserialize the json to a .NET object. There's a generic Deserialize<T>, though you will need the .NET object to have a similar signature as the javascript one. Additionally there is also a DeserializeObject method that just makes a plain object. You can then use reflection to get at the properties you need.

也可以使用JavaScriptSerializer类。这将使您可以将json反序列化为. net对象。有一个通用的反序列化 ,但是需要. net对象具有与javascript相似的签名。此外,还有一个DeserializeObject方法,它只生成一个普通对象。然后可以使用反射获取所需的属性。

If your controller takes a FormCollection, and you didn't add anything else to the data the json should be in form[0]:

如果您的控制器接受一个FormCollection,并且没有向数据添加任何其他内容,那么json应该是格式[0]:

public ActionResult Save(FormCollection forms) {
  string json = forms[0];
  // do your thing here.
}

#5


2  

This answer is a follow up to DaRKoN_'s answer that utilized the object filter:

这个答案是对使用对象过滤器的DaRKoN_答案的后续回答:

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

I was having a problem figuring out how to send multiple parameters to an action method and have one of them be the json object and the other be a plain string. I'm new to MVC and I had just forgotten that I already solved this problem with non-ajaxed views.

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

What I would do if I needed, say, two different objects on a view. I would create a ViewModel class. So say I needed the person object and the address object, I would do the following:

如果我需要视图上的两个不同的对象,我会怎么做。我将创建一个ViewModel类。假设我需要person对象和address对象,我会做以下事情:

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

Then I would bind the view to SomeViewModel. You can do the same thing with JSON.

然后我将视图绑定到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);
}

Then in the view you can use a simple call with JQuery like this:

然后在视图中,您可以使用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  

in response to Dan's comment above:

针对以上丹的评论:

I am using this method to implement the same thing, but for some reason I am getting an exception on the ReadObject method: "Expecting element 'root' from namespace ''.. Encountered 'None' with name '', namespace ''." Any ideas why? – Dan Appleyard Apr 6 '10 at 17:57

我正在使用这个方法来实现同样的事情,但是出于某种原因,我得到了ReadObject方法的一个异常:“期望元素‘root’from namespace”。遇到“None”的名称是“名称空间”。任何想法为什么?——丹·阿普尔里亚4月10日17点57分

I had the same problem (MVC 3 build 3.0.11209.0), and the post below solved it for me. Basically the json serializer is trying to read a stream which is not at the beginning, so repositioning the stream to 0 'fixed' it...

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

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

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