【问题标题】:ASP.NET MVC2 Reading JSON data with controllerASP.NET MVC2 使用控制器读取 JSON 数据
【发布时间】:2011-05-25 13:58:18
【问题描述】:

我无法从我的 javascript/jQuery 请求接收 json 值到我的控制器。

MyClass 如下所示:

function MyClass() {
    this.MyString = null;
    this.MyInt = null;
    this.Subs = null;
}

我的请求如下所示:

var testData1 = new MyClass();
testData1.MyInt = 1234;
testData1.MyString = "abcDEF";
testData1.Subs = new Array();
var testData2 = new MyClass();
testData2.MyInt = 5678;
testData2.MyString = "GHIjkl";
testData1.Subs.push(testData2);
var jsonData = JSON.stringify(testData1);
var self = this;
$.ajax({
    url: '/Home/Request',
    type: 'POST',
    dataType: 'json',
    data: jsonData,
    contentType: 'application/json; charset=utf-8',
    success: function (x) {
        self.ParseResult(x);
    }
});

现在我有了一个控制器:

public JsonResult Request(MyClass myObj)
{
    var answer = ...
    return Json(answer, JsonRequestBehavior.DenyGet);
}

使用以下类:

public class  MyClass
{
    public string MyString { get; set; }
    public int MyInt { get; set; }
    public List<MyClass> Subs { get; set; }
}

jsonData 中的所有名称都与我的类“MyClass”中的名称完全相同。但是 myObj 中没有值。

问题出在哪里。我可以做些什么来让这个映射正常工作吗?

非常感谢您,

克里斯

更新:

感谢您的回复。我使用了 JavascriptSerializer。但我有问题,myString 为空:

public JsonResult Data(string myString)
{
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    var data = serializer.Deserialize<MyClass>(myString);
var answer = ...
    return Json(answer, JsonRequestBehavior.DenyGet);
}

价值在哪里?我应该从请求数据中获取值吗?

@戴夫·沃德

您的第二个解决方案正在工作。但我的潜艇有问题。

var testData1 = new MyClass();
testData1.MyInt = 1234;
testData1.MyString = "abcDEF";
testData1.Subs = new Array();
for (var i = 0; i < 10; i++) {
    var testData2 = new MyClass();
    testData2.MyInt = i;
    testData2.MyString = "abcDEF";
    testData1.Subs.push(testData2);
}

我的控制器中有 10 个 Subs,但都是空的。我能做什么?

@戴夫·沃德,@ALL

使用传统设置,我的 10 个 Subs 是空的,它们不存在。订阅数为 0(非 NULL)。 我试图将 Subs Type 从 List 更改为 IEnumerable 但这没有帮助。 你知道我还能做些什么来让 Subs 填充到我的控制器中吗?

好的,谢谢 Dave Ward,我将使用 JSON 方法。

对于遇到相同问题的其他人,此控制器代码可能来自帮助:

MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(myString));
var serializer = new DataContractJsonSerializer(typeof(MyClass));
MyClass se = serializer.ReadObject(ms) as MyClass;
ms.Close();

【问题讨论】:

    标签: jquery asp.net-mvc json asp.net-mvc-2


    【解决方案1】:

    现在,您将 JSON 字符串作为整个 POST 正文发送。 MVC 无法连接这些点并理解您希望它提供整个字符串作为名为 myString 的参数。

    为此,请像这样更改您的客户端数据参数:

    $.ajax({
      url: '/Home/Request',
      type: 'POST',
      dataType: 'json',
      data: { myString: jsonData },
      contentType: 'application/json; charset=utf-8',
      success: function (x) {
        // If ParseResult is some sort of JSON deserializing, don't do that.
        // When the dataType is set to 'json', jQuery handles this for you 
        //  automatically before the success handler is called.
        self.ParseResult(x);
      }
    });
    

    当你为 jQuery 提供一个对象作为它的数据参数时,它会在发送之前自动对其进行 URLEncode,所以这样的东西会被 POST 到服务器:

    myString={json:data, here:etc}
    

    MVC 将根据需要将其作为 myString 参数,然后您可以使用 JavaScriptSerializer 继续对其进行反序列化。

    此外,除非您在客户端执行的操作比您所展示的更复杂,否则 JavaScript 类是不必要的。像这样的东西会起作用:

    var testData2 = {
      MyInt: 5678,
      MyString: "GHIjkl",
    }
    
    var testData1 = {
      MyInt: 1234,
      MyString: "abcDEF",
      Subs: [ testData2 ]
    }
    

    说了这么多,为什么要使用 JSON 来处理请求?如果您在操作中接受自定义类型的参数,MVC 的模型绑定器非常擅长从标准 URLEncoded 输入数据中混合该类型:

    public JsonResult Data(MyClass request)
    {
      // request.MyInt, request.MyString, etc should exist here.
    
      var answer = ...
    
      // It's okay to accept URLEncoded input parameters, but still return JSON.
      return Json(answer, JsonRequestBehavior.DenyGet);
    }
    

    那么,调用它就不需要客户端JSON序列化了:

    var testData2 = {
      MyInt: 5678,
      MyString: "GHIjkl",
    }
    
    var testData1 = {
      MyInt: 1234,
      MyString: "abcDEF",
      Subs: [ testData2 ]
    }
    
    $.ajax({
      url: '/Home/Request',
      type: 'POST',
      traditional: true,
      dataType: 'json',
      data: testData1
      success: function (x) {
        self.ParseResult(x);
      }
    });
    

    它更简单一些,而且速度更快,因为您删除了客户端的序列化层和服务器端的反序列化层。

    【讨论】:

    • 感谢您的回答。您的第二个解决方案运行良好。我唯一的问题是“潜艇”。我已经更新了我的原始帖子以更好地格式化我的帖子。
    • 我相信您还需要使用 jQuery 的“传统”序列化。我更新了答案中的 $.ajax() 代码。
    • 使用“传统”序列化时,控制器的 Subs-count 为 0。
    • 不幸的是,嵌套对象可能太深而无法使用“传统”urlencoding 进行序列化(至少在 ASP.NET MVC 下;“非传统”jQuery 序列化是解决深度嵌套问题的一种实现,但 ASP.NET MVC 不支持它)。使用 JSON。
    • 感谢您的所有帮助。我正在使用带有 stringify 的 JSON 方法,它适用于您发布的更改。
    【解决方案2】:

    根据我的经验,我必须将 json 作为字符串传递,然后对其进行反序列化。我使用Newtonsoft 来执行此操作。

    public ActionResult DoAjax(string jsonRequest)
    {
        JsonSerializer serializer = new JsonSerializer();
    
        StringReader sr = new StringReader(jsonRequest);
        Newtonsoft.Json.JsonTextReader reader = new JsonTextReader(sr);
    
        MyClass obj = (MyClass)serializer.Deserialize(reader, typeof(MyClass));
    
        //...do other stuff
    }
    

    【讨论】:

    • 我同意这种做法。我要补充一点,您还可以使用 .NET 中的内置 JavaScriptSerializer 进行反序列化。有关更多信息,请参阅此链接msdn.microsoft.com/en-us/library/…
    • @Hector - 非常酷。我不知道有一个内置的 json 序列化程序。 +1 教我一些新东西。 :)
    • 我从来没有这样做过,但是围绕 MVC 的 json 反序列化有一些技巧。基本上,如果你混合整数、小数和字符串,事情会变得一团糟。 int 作为字符串(“1”)将绑定到字符串或 int,但作为字符串的小数只会反序列化为字符串。我无法让“1.1”绑定到十进制属性。我不知道 MVC 团队是如何错过这些用例的。嵌套结构也有一些奇怪之处,但我不记得我遇到的具体用例。
    • 感谢您的回答。无论我选择哪种解决方案(Joshs 或 (Hectors),myString 都是 null。
    • 顺便说一句 - 如果您要使用内置序列化程序,请使用 DataContractJsonSerializer。它是最新的,是 WCF 使用的。关于这个问题——你能先把事情简单化吗,删除Subs属性——并确保你可以先传递一个只有string和int的JSON对象。
    【解决方案3】:

    与 josh 类似,您可以使用 json actionfilter a la:

    // requires newtonsoft.json.dll 
    public class JsonFilter : ActionFilterAttribute
    {
        public string Param { get; set; }
        public Type JsonDataType { get; set; }
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext
                .Request.ContentType.Contains("application/json"))
            {
                string inputContent;
                using (var sr = new StreamReader(filterContext.HttpContext
                                    .Request.InputStream))
                {
                    inputContent = sr.ReadToEnd();
                }
    
                var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
                filterContext.ActionParameters[Param] = result;
            }
            else
                try
                {
                    // we should do a loop looking for json here ONLY if there's a callback
                    // i.e. we're calling jsonP
                    if (filterContext.HttpContext.Request.QueryString["callback"] != null)
                    {
                        string inputContent = 
                            Enumerable.Where(filterContext.HttpContext
                                            .Request.QueryString.Keys.Cast<string>()
                                            .Select(qs => filterContext.HttpContext
                                            .Request.QueryString[qs]), query => !string.IsNullOrEmpty(query))
                                            .FirstOrDefault(query => query.IndexOf("{") == 0);
    
                        var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
                        filterContext.ActionParameters[Param] = result;
                    }
                }
                catch (Exception e)
                {
                    // do nothing
                    filterContext.ActionParameters[Param] = null;
                }
        }
    }
    

    用法(在本例中为 typeof(IList)),但可以是任何类,即 typeof(myClass):

    [JsonFilter(Param = "jsonData", JsonDataType = typeof(IList<FundPropertyWeekSplit>))]
    public virtual ActionResult AddFundPropertyWeekSplit(IList<FundPropertyWeekSplit> jsonData)
    {
        // code to deal with the newly created strongly typed object
    }
    

    我在整个店里都用这个(太多了!!)...

    【讨论】:

      【解决方案4】:

      您可以查看 Omar Al Zabir 关于 json、xml 请求和响应处理的文章,他为解决这种常见情况提供了一个非常好的解决方案。

      Create REST API using ASP.NET MVC that speaks both Json and plain Xml

      【讨论】:

        猜你喜欢
        • 2014-07-17
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多