ASP.NET MVC2使用控制器读取JSON数据

时间:2010-12-14 21:47:50

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

我有问题从我的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为null:

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

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

@Dave Ward

你的第二个解决方案正在运作。但我对潜艇有问题。

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,但都是空的。我该怎么办?

@Dave Ward,@ ALL

使用传统设置我的10个子机器人是空的,它们不在那里。子计数为0(非NULL)。 我试图将Subs Type从List更改为IEnumerable,但这没有帮助。 你知道我还能做些什么来让我的控制器充满潜艇吗?

好的,谢谢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();

4 个答案:

答案 0 :(得分:3)

现在,您正在发送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一个对象作为它的数据参数时,它会在发送之前自动对其进行URLEncodes,所以这样的东西将被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);
  }
});

它更简单,并且更快,因为您在客户端删除了一层序列化并在服务器端删除了反序列化。

答案 1 :(得分:1)

根据我的经验,我必须将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
}

答案 2 :(得分:1)

对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
}

我在商店里使用这个(相当多!!)...

答案 3 :(得分:0)

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

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