简体   繁体   English

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

[英]ASP.NET MVC2 Reading JSON data with controller

I have problems to receive json values from my javascript/jQuery request to my controller. 我有问题从我的javascript / jQuery请求到我的控制器接收json值。

MyClass looks like the following: MyClass如下所示:

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

My Request looks like the following: 我的请求如下所示:

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);
    }
});

Now I have a controller: 现在我有一个控制器:

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

With the following class: 使用以下课程:

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

All names in jsonData are exactly the same like in my class "MyClass". jsonData中的所有名称与我的“MyClass”类中的名称完全相同。 But there are no values in myObj. 但是myObj中没有值。

Where is the Problem. 问题出在哪儿。 Is there anything I can do to get this mapping working correctly? 有什么办法可以让这个映射正常工作吗?

Thank you very much in advance, 非常感谢你提前,

Chris 克里斯

UPDATE: 更新:

Thank you for your repley. 谢谢你的反馈。 I have used the JavascriptSerializer. 我使用过JavascriptSerializer。 But I have the problem, that myString is null: 但我有问题,myString为null:

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

Where is the value? 价值在哪里? Should I take the value from the request-data? 我应该从请求数据中获取值吗?

@Dave Ward @Dave Ward

You second solution is working. 你的第二个解决方案是工作 But I have a problem with the subs. 但我对潜艇有问题。

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);
}

I get 10 Subs in my controller, but all are empty. 我的控制器中有10个Subs,但都是空的。 What can I do? 我能做什么?

@Dave Ward, @ALL @Dave Ward,@ ALL

Using the traditional settings my 10 Subs are bot empty, they are not there. 使用传统设置我的10个子机器人是空的,它们不存在。 Subs count is 0 (not NULL). 子计数为0(非NULL)。 I tried to change the Subs Type from List to IEnumerable but that didn't help. 我试图将Subs Type从List更改为IEnumerable,但这没有帮助。 Do you know anything else I can do to get Subs filled in my controller? 你知道我还能做些什么来让我的控制器填充Subs吗?

Ok, thank you Dave Ward, I will use the JSON method. 好的,谢谢Dave Ward,我将使用JSON方法。

For somebody else having the same problem this controller code could be from help: 对于其他有相同问题的人来说,这个控制器代码可以来自帮助:

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

Right now, you're sending the JSON string as the entire body of your POST. 现在,您将发送JSON字符串作为POST的整个主体。 MVC has no way to connect the dots and understand that you wanted it to provide that entire string as a parameter named myString. MVC无法连接点并理解您希望它将整个字符串作为名为myString的参数提供。

To do that, change your client-side data parameter like this: 为此,请更改您的客户端数据参数,如下所示:

$.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);
  }
});

When you provide jQuery an object as its data parameter, it automatically URLEncodes that before sending, so something like this will be POSTed to the server: 当你提供jQuery一个对象作为它的数据参数时,它会在发送之前自动对其进行URLEncodes,所以这样的东西将被POST到服务器:

myString={json:data, here:etc}

MVC will pick that up as the myString parameter as desired then, and you can proceed with deserializing it with JavaScriptSerializer. 然后,MVC将根据需要将其选为myString参数,然后您可以继续使用JavaScriptSerializer对其进行反序列化。

Also, unless you're doing something more complicated on the client-side than you're showing, the JavaScript class is unnecessary. 此外,除非您在客户端执行的操作比您显示的更复杂,否则JavaScript类是不必要的。 Something like this would work: 像这样的东西会起作用:

var testData2 = {
  MyInt: 5678,
  MyString: "GHIjkl",
}

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

All that said, why are you using JSON for the request? 所有这一切,为什么你使用JSON的请求? If you accept a parameter of the custom type in your action, MVC's model binder is pretty good at hydrating that type from standard URLEncoded input data: 如果您在动作中接受自定义类型的参数,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);
}

Then, calling it doesn't require the client-side JSON serialization: 然后,调用它不需要客户端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);
  }
});

It's a bit simpler all around, and is faster since you've removed a layer of serialization on the client-side and deserialization on the server-side. 它更简单,并且更快,因为您在客户端删除了一层序列化,在服务器端删除了反序列化。

In my experience I have to pass in the json as a string and then deserialize it. 根据我的经验,我必须将json作为字符串传递,然后反序列化它。 I use Newtonsoft to do this. 我用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
}

on a similar tack to josh's, you can use a json actionfilter a la: 在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;
            }
    }
}

usage (in this case typeof(IList)) but can be ANY class ie typeof(myClass): 用法(在本例中为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
}

i use this (rather too much!!) all over the shop... 我在整个商店使用这个(相当多!!)

You can take a look Omar Al Zabir's article about json, xml request and response handling he provided a really good solution for solving this common situations. 你可以看看Omar Al Zabir关于json,xml请求和响应处理的文章,他为解决这种常见情况提供了一个非常好的解决方案。

Create REST API using ASP.NET MVC that speaks both Json and plain Xml 使用兼容Json和plain Xml的ASP.NET MVC创建REST API

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM