Создание MVC3 ValueProviderFactories, которые требуют информацию о типе? - PullRequest
2 голосов
/ 01 августа 2011

Я пытаюсь написать Protobuf ValueProviderFactory для ASP MVC3. Мне удалось решить , как добавить фабрики , но теперь я наткнулся на более насущную проблему. Здесь текущая сериализация происходит в JsonValueProviderFactory.cs

    JavaScriptSerializer serializer = new JavaScriptSerializer();
    object jsonData = serializer.DeserializeObject(bodyText);
    return jsonData;

То есть десериализация осуществляется без какой-либо информации о типе? Какой тип объекта возвращает DeserializeObject? Динамический? Откуда он знает тип данных? Я надеялся разместить здесь protobuf-net, но ему явно нужен тип, чтобы творить чудеса!

Я не просмотрел весь источник MVC3, но я предполагаю, что сопоставление с типами происходит на последнем этапе, и нет способа узнать типы в ValueProviderFactories?

Должен ли я сдаться и совершить преобразование в действиях?

Ответы [ 2 ]

2 голосов
/ 01 августа 2011

Здесь есть несколько вопросов.

Чтобы узнать, как работает JavaScriptSerializer, прочитайте документацию . Класс пытается определить тип для базовых типов (int, bool, date и т. Д.) И возвращает Dictionary<string, object> для более сложных случаев. Кроме того, если BLOB-объект JSON содержит специальное свойство «__type», десериализатор попытается создать объект этого типа.

Теперь о том, как это работает в MVC. Процесс отображения значений из запроса на экземпляр объекта, используемый в вашем контроллере, называется привязкой модели. Это разделено на два компонента: ModelBinder и ValueProviders. Связыватель модели знает целевой тип (например, Product), пытается создать его экземпляр, а затем заполняет его свойства значениями из запроса. Это делается путем запроса ValueProviders. Например, чтобы установить свойство Name в экземпляре Product, он запрашивает у поставщиков значения значение «Name». Поставщики значений запрашиваются последовательно и возвращают совпадение (из строки запроса, данных публикации, тела запроса JSON и т. Д.).

В Интернете есть много ресурсов по этому поводу, но у поставщиков услуг с короткими значениями на самом деле не следует беспокоиться о типах.

1 голос
/ 01 августа 2011

Вот быстрый пример решения, использующего ModelBinder, как предлагает marcind. Это не проверено, но это начало. В этом случае FromProtobuf<T> - это простой byte[] метод расширения объекта.

public class ProtobufModelBinder<T> : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/x-protobuf", StringComparison.OrdinalIgnoreCase))
            return null;

        using (MemoryStream ms = new MemoryStream())
        {
            controllerContext.HttpContext.Request.InputStream.CopyTo(ms);
            return ms.ToArray().FromProtobuf<T>();
        }
    }
}

Это можно настроить следующим образом:

ModelBinders.Binders.Add(typeof(MyClass), new ProtobufModelBinder<MyClass>());
...