Опубликовать массив объектов через JSON в ASP.Net MVC3 - PullRequest
65 голосов
/ 25 января 2011

Я ищу решение для размещения массива объектов в MVC3 через JSON.

Пример кода, над которым я работаю: http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx

JS:

var data = { ItemList: [ {Str: 'hi', Enabled: true} ], X: 1, Y: 2 };

$.ajax({
    url: '/list/save',
    data: JSON.stringify(data),
    success: success,
    error: error,
    type: 'POST',
    contentType: 'application/json, charset=utf-8',
    dataType: 'json'
});

ListViewModel.cs:

public class ListViewModel
{
    public List<ItemViewModel> ItemList { get; set; }
    public float X { get; set; }
    public float Y { get; set; }
}

ItemViewModel.cs:

public class ItemViewModel
{
    public string Str;   // originally posted with: { get; set; }
    public bool Enabled; // originally posted with: { get; set; }
}

ListController.cs:

public ActionResult Save(ListViewModel list)
{
    // Do something
}

Результат этого POST:

список установлен в ListViewModel
Его свойства X и Y установлены
Базовое свойство ItemList установлено
ItemList содержит один элемент, как и должно быть
Элемент в этом ItemList не инициализирован. Str - ноль, а Enabled - ложь.

Другими словами, это то, что я получаю из привязки модели MVC3:

list.X == 1
list.Y == 2
list.ItemList != null
list.ItemList.Count == 1
list.ItemList[0] != null
list.ItemList[0].Str == null

Казалось бы, MVC3 JsonValueProvider не работает для сложных объектов. Как мне заставить это работать? Нужно ли мне модифицировать существующий JC-файл MVC3 JsonValueProvider и исправить его? Если да, то как мне получить его и заменить в проекте MVC3?

Связанные вопросы StackOverflow, которые я уже преследовал безрезультатно:

Asp.net Mvc Ajax Json (post Array) Использует MVC2 и более старую кодировку на основе форм - этот подход не работает с объектом, который содержит массив объектов (JQuery не может правильно его кодировать).

Отправка массива сложных объектов с помощью JSON, JQuery в ASP.NET MVC Controller Использует хак, который я бы хотел избежать, когда Контроллер вместо этого получает простую строку, которую он затем сам десериализует, а не используя каркас.

Привязка сообщения MVC3 RC2 JSON работает неправильно Не установлен его тип контента - он установлен в моем коде.

Как опубликовать массив сложных объектов с помощью JSON, jQuery в ASP.NET MVC Controller? Этот бедняга должен был написать JsonFilter только для разбора массива. Еще один взлом, который я бы предпочел избежать.

Итак, как мне это сделать?

Ответы [ 6 ]

43 голосов
/ 21 марта 2011

В дополнение к { get; set; } вот некоторые из условий для поддержки связывания JSON:

  1. Это новая функция в ASP.NET MVC 3 (см. « Улучшения JavaScript и AJAX» «).
  2. Строки объекта JSON (« X »,« Y »,« Str »и« Enabled ») должны соответствовать свойствам объекта ViewModel.
  3. Свойства объекта ViewModel должныесть метод { get; set; }.
  4. В запросе необходимо указать тип содержимого как «application / json».
  5. Если он все еще не работает, проверьте строку JSON, чтобы убедиться, что она действительна.

Подробнее на моем посте .

Надеюсь, что поможет!

30 голосов
/ 03 февраля 2011

Проблема заключалась в том, что свойства в моделях, которые были в Списке, не имели get / set для своих общедоступных свойств.Иными словами, автоматическое связывание JSON MVC3 работает только со свойствами объекта, которые имеют get и set.

Это не будет привязывать:

public string Str;

Это будет привязывать:

public string Str { get; set; }
29 голосов
/ 25 января 2011

Странно.Я не могу воспроизвести ваше поведение.Вот мои настройки (ASP.NET MVC 3 RTM):

Модель:

public class ItemViewModel
{
    public string Str { get; set; }
    public bool Enabled { get; set; }
}

public class ListViewModel
{
    public List<ItemViewModel> ItemList { get; set; }
    public float X { get; set; }
    public float Y { get; set; }
}

Контроллер:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Save(ListViewModel list)
    {
        return Json(list);
    }
}

Вид:

@{
    ViewBag.Title = "Home Page";
}

<script type="text/javascript">
    $(function () {
        var data = { ItemList: [{ Str: 'hi', Enabled: true}], X: 1, Y: 2 };

        $.ajax({
            url: '@Url.Action("save", "home")',
            data: JSON.stringify(data),
            type: 'POST',
            contentType: 'application/json',
            dataType: 'json',
            success: function (result) {
                alert(result.ItemList[0].Str);
            }
        });
    });
</script>

Запуск этого оповещения "hi" и внутри действия Save все правильно инициализировано.

И только для записи, что не работает, это словари.Я открыл билет о проблеме.

3 голосов
/ 18 сентября 2011

У меня была похожая проблема, и я обнаружил, что для сложного объекта числовые значения пропускаются.Они входили в нули.то есть

    var person = {
        Name: "john",
        Age: 9
    }

был получен контроллером MVC как объект Person, где свойства были заполнены как Name=John и Age=0.

Затем я установил значение Age в Javascript длябыть строкой ... то есть

    var person = {
        Name: "john",
        Age: "9"
    }

И это прошло очень хорошо ...

0 голосов
/ 15 января 2015

Все предыдущие ответы были великолепны, чтобы указать мне на решение подобной проблемы. Мне пришлось POST x-www-form-urlencoding вместо application/json (опция по умолчанию, если параметр contentType отсутствует), чтобы можно было передать __RequestVerificationToken и одновременно столкнуться с проблемой, когда свойства объекта, находящиеся в массиве, не связывают свои значения. Чтобы решить эту проблему, нужно понять внутреннюю работу связующего для модели MVC.

Таким образом, в основном, когда вам необходимо предоставить токен подтверждения, вы ограничены атрибутом проверки. И вы должны предоставить токен как параметр, а не как часть JSON-объекта, который вы отправляете. Если бы вы не использовали ValidateAntiForgeryToken, вы могли бы ужиться с JSON.stringify. Но если бы вы могли, вы не могли бы передать токен.

Я понюхал трафик до бэкэнда, когда ContentType был x-www-form-urlencoding, и заметил, что мой массив сложных объектов был сериализован в нечто подобное: klo[0][Count]=233&klo[0][Blobs]=94. Этот массив изначально был частью корневого объекта, скажем, некоторой модели. Выглядело это так: model.klo = [{ Count: 233, Blobs: 94}, ...].

Со стороны сервера это свойство klo создавалось связывателем MVC с тем же количеством элементов, которое я отправил. Но сами эти элементы не получили значений для своих свойств.

РЕШЕНИЕ

Чтобы справиться с этим, я исключил свойство klo из объекта модели на стороне клиента. В функции ajax я написал этот код:

data: $.param(model) + "&" + arrayOfObjectsToFormEncoding("klo", [{ Count: 233, Blobs: 94}, ...])
....

    function arrayOfObjectsToFormEncoding (modelPropertyName, arrayOfObjects) {
        var result = "";
        if (arrayOfObjects && typeof arrayOfObjects == "object") {
            for (var i = 0; i < arrayOfObjects.length; i++) {
                var obj = arrayOfObjects[i];
                if (obj) {
                    for (var p in obj) {
                        if (obj.hasOwnProperty(p)) {
                            result += encodeURIComponent(modelPropertyName + "[" + i + "]." + p) + "=" + encodeURIComponent(obj[p]) + "&";
                        }
                    }
                }
            }
        }

        if (result[result.length - 1] == "&") {
            result = result.substr(0, result.length - 1);
        }

        return result;
    }

Функция преобразует массив сложного объекта в форму, которая распознается MVC-связывателем. Форма: klo[0].Count=233&klo[0].Blobs=94.

0 голосов
/ 09 января 2012

Это потому, что связующие MVC отстой.Тем не менее, они работают довольно хорошо, если все значения JSON отображаются в виде строки.

В JS, если вы сделаете это

var myObject = {thisNumber:1.6};

myObject.thisNumber=myObject.thisNumber-.6;

Значение будет равно 1, а не 1,0

Поэтому, когда вы отправляете его на сервер, оно будет пытаться привязатьсяfloat с таким именем, и он не найдет его, так как он пришел как 1 вместо 1.0.Очень глупо и безумно, что инженеры MS не придумали для этого решения по умолчанию.Я нахожу, если вы строите все строки, то привязки достаточно умны, чтобы что-то находить.

Поэтому перед отправкой данных запустите их, хотя и строковый преобразователь, который также преобразует все значения в строки.

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