Проблемы десериализации Dictionarys в MVC 3 для запроса AJAX (подход, который работает "из коробки" с классическими ASP.NET Webforms) - PullRequest
3 голосов
/ 30 июля 2011

Я успешно прошел WebForms для вызовов AJAX с относительно сложным набором параметров (вызываемых с использованием jQuery.ajax).Мы пытаемся использовать тот же подход в MVC 3, но, похоже, с первого раза сталкиваемся с тем, что MVC не удалось успешно десериализовать массивы словаря.

Подход, который работает без проблем в ASP.NET WebForms "classic"ниже:

[WebMethod]
public static JQGrid.JQGridData GetListForJQGrid(int? iPageSize, int? iPage, int? iMaxRecords, string sSortField, string sSortOrder,
  Dictionary<string, string> dSearchOptions, Dictionary<string, object>[] aOriginalColumnDefinition, string[] aExtraDataColumns)

И ниже эквивалент MVC 3: (хотя бы одно и то же имя / параметры - другой тип возвращаемого значения, но я не думаю, что это уместно)

[HttpPost]
public JSONResult GetListForJQGrid(int? iPageSize, int? iPage, int? iMaxRecords, string sSortField, string sSortOrder,
  Dictionary<string, string> dSearchOptions, Dictionary<string, object>[] aOriginalColumnDefinition, string[] aExtraDataColumns)

С помощью WebMethod все данные отлично десериализуются.Тем не менее, когда вызывается метод MVC, все простые параметры десериализуются нормально, но по неизвестной причине массив словаря поступает в виде массива нулей.

Итак, в конце этого ряда вопросов:

  • Кто-нибудь еще испытывал проблемы с десериализацией массивов словарей в MVC 3?
  • Разве MVC 3 по умолчанию не использует System.Web.Script.Serialization.JavaScriptSerializer, то есть я думаю, что веб-методы ASP.NET используют под капотом?
  • Могу ли я заставить MVC 3 использовать System.Web.Script.Serialization.JavaScriptSerializer вместо того, что он использует?
  • Или я что-то упускаю / должен ли мой подход немного отличаться?Обратите внимание, что, по крайней мере, сейчас нам нужно разделить код на стороне клиента между классическими ASP.NET WebMethods и MVC 3, и поэтому мы хотим, чтобы он оставался как есть.
  • Наконец, я могу видеть тамЭто возможный обходной путь, который можно использовать, глядя на этот вопрос: POST json dictionary .Является ли этот обходной путь единственной игрой в городе или что-то улучшилось с тех пор, как был задан этот вопрос?

jQuery AJAX call:

$.ajax(_oJQGProperties.sURL, //URL of WebService/PageMethod used
{
  data: JSON.stringify(oPostData),
  type: "POST",
  contentType: "application/json",
  complete: DataCallback
});

Пример JSON.stringify (oPostData):

{
"dSearchOptions":{},
"aOriginalColumnDefinition":
[
{"name":"ID","sortable":false,"hidedlg":true,"align":"right","title":false,"width":40},
{"name":"URL","sortable":false,"hidedlg":true,"align":"left","title":false,"width":250,"link":"javascript:DoSummat(this,'{0}');","textfield":"Name"},
{"name":"Description","sortable":false,"hidedlg":true,"align":"left","title":false,"width":620}
],
"aExtraDataColumns":["Name"],
"_search":false,
"iPageSize":-1,
"iPage":1,
"sSortField":"",
"sSortOrder":"",
"iMaxRecords":0
}

Ответы [ 3 ]

1 голос
/ 24 ноября 2011

Долгое время обновлялся, но я думал, что поделюсь, куда мы попали. Проблемой оказалась ошибка - подробности о которой можно найти здесь:

Ошибка: http://connect.microsoft.com/VisualStudio/feedback/details/636647/make-jsonvalueproviderfactory-work-with-dictionary-types-in-asp-net-mvc

Обход: POST JSON словарь

Мы использовали заявленный обходной путь, который был в порядке. Мне не очень понятно, когда будет выпущено исправление и где именно лежит ошибка. (Это зависит от .NET / зависит от MVC и т. Д.) Если кто-то еще знает, я бы хотел узнать: -)

Обновление

Я до сих пор не слышал, поставляется ли он (я полагаю, он выйдет с MVC 4?), Но пока что это может быть альтернативное решение:

http://www.dalsoft.co.uk/blog/index.php/2012/01/10/asp-net-mvc-3-improved-jsonvalueproviderfactory-using-json-net/

Обновление 2

Это было доставлено в качестве исправления с MVC 4. Проблема остается нерешенной в MVC 3, и поэтому я сейчас написал ее в блоге здесь:

http://icanmakethiswork.blogspot.com/2012/10/mvc-3-meet-dictionary.html

1 голос
/ 12 декабря 2013

Я тоже столкнулся с этой проблемой.После того, как я нашел этот пост, я подумал об обновлении до MVC4, но слишком рискованно делать все сразу в моей среде, так что поцарапайте это.

Эта ссылка , опубликованная в ответе Джонни Рейли, выглядела многообещающе, но для этого потребовалось свернуть мой словарь в строку.Поскольку моя модель MVC является двунаправленной (она используется для чтения и записи), и я действительно хотел эту структуру словаря, я решил также передать ее.Было бы очень сложно сохранить два свойства для одного значения.Мне нужно было бы добавить больше тестов, следить за крайними случаями и т. Д.

Ссылка Джонни JsonValueProviderFactory тоже казалась многообещающей, но немного загадочной.Мне также не совсем комфортно играть с такой частью MVC.У меня было всего несколько часов, чтобы разобраться с этой проблемой, поэтому я решил и эту проблему.

Затем я нашел эту ссылку где-то и подумал: «Да! Это больше похоже на то, что я хочу!».Другими словами, атакуйте проблему связывания модели с помощью пользовательского связующего.Замените неисправный чем-то другим, и используйте для этого встроенную возможность MVC.К сожалению, это не сработало, так как мой вариант использования был List T, а T была моей моделью.Это полностью не работает с образцом.Поэтому я взломал его и в конечном итоге потерпел неудачу.

Затем у меня возник момент с лампочкой - у JSON.NET такой проблемы нет.Я все время использую его для выполнения самых разных задач, от клонирования объектов до регистрации, до конечных точек службы REST.Почему не привязка модели?Таким образом, я в конечном итоге закончил с этим, и моя проблема была решена.Я думаю, что он должен работать практически с чем угодно - я верю JSON.NET =)

/// <summary>
/// Custom binder that maps JSON data in the request body to a model class using JSON.NET.
/// </summary>
/// <typeparam name="T">Model type being bound</typeparam>
/// <remarks>
/// This binder is very useful when your MVC3 model contains dictionaries, something that it can't map (this is a known bug, fixed with MVC 4)
/// </remarks>
public class CustomJsonModelBinder<T> : DefaultModelBinder
    where T : class
{
    /// <summary>
    /// Binds the model by using the specified controller context and binding context.
    /// </summary>
    /// <returns>
    /// The bound object.
    /// </returns>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><exception cref="T:System.ArgumentNullException">The <paramref name="bindingContext "/>parameter is null.</exception>
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        HttpRequestBase request = controllerContext.HttpContext.Request;
        request.InputStream.Position = 0;
        var input = new StreamReader(request.InputStream).ReadToEnd();
        T modelObject = JsonConvert.DeserializeObject<T>(input);
        return modelObject;
    }
}

Чтобы применить связыватель, я добавил атрибут в свой параметр модели.Это заставляет MVC3 использовать мой компоновщик вместо значения по умолчанию.Примерно так:

public ActionResult SomeAction(
    [ModelBinder(typeof(CustomJsonModelBinder<List<MyModel>>))] // This custom binder works around a known dictionary binding bug in MVC3
    List<MyModel> myModelList, int someId)
    {

Одно предостережение - я использовал POST с типом контента "application / json".Если вместо этого вы делаете что-то вроде формы или составных данных, они, вероятно, будут ужасно падать.

1 голос
/ 30 июля 2011

У меня нет опыта связывания с массивом словаря, но одним из возможных решений является использование пользовательского связывателя модели.Скотт Хансельман имеет сообщение в блоге на эту тему, которое может оказаться полезным: Разделение даты и времени - модульное тестирование пользовательской модели ASP.NET MVC.

...