ASP.NET MVC2 Чтение данных JSON с контроллером - PullRequest
4 голосов
/ 15 декабря 2010

У меня проблемы с получением значений json из моего запроса javascript / jQuery на мой контроллер.

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 сабвуферов в моем контроллере, но все они пусты.Что я могу сделать?

@ Дейв Уорд, @ ALL

При традиционных настройках мои 10 Subs не загружены, их нет.Количество подводных лодок равно 0 (не NULL).Я попытался изменить тип Subs из списка на IEnumerable, но это не помогло.Знаете ли вы что-нибудь еще, что я могу сделать, чтобы заполнить Subs в моем контроллере?

Хорошо, спасибо, Дейв Уорд, я буду использовать метод 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 ]

3 голосов
/ 15 декабря 2010

Прямо сейчас вы отправляете строку 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 объект в качестве параметра данных, он автоматически URLE кодирует его перед отправкой, поэтому что-то подобное будет отправлено на сервер:

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 довольно хорошо справляется с увлажнением этого типа из стандартных входных данных с кодировкой URLE:

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 голос
/ 15 декабря 2010

на подобном гвоздю Джошу, вы можете использовать json actionfilter а-ля:

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

Я использую это (довольно много !!) по всему магазину ...

1 голос
/ 15 декабря 2010

По моему опыту, я должен передать в 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
}
0 голосов
/ 15 декабря 2010

Вы можете взглянуть на статью Омара Аль-Забира о json, xml запросах и обработке ответов. Он предоставил действительно хорошее решение для решения этих распространенных ситуаций.

Создание REST API с использованием ASP.NET MVC, котороеговорит как на Json, так и на простом Xml

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...