2014-12-03 2 views
3

В нашем приложении MVC 2 мы имеем JSON модель связующие реализованы следующим образом:Выросших Request.InputStream до достижения ModelBinder

public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     string input; 

     using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream)) 
     { 
      input = reader.ReadToEnd(); 
     } 

     return JsonConvert.DeserializeObject(
      input, 
      bindingContext.ModelType); 
    } 

После обновления MVC 4, я заметил, что мы получали нулевые входящие модели для входящих сообщений JSON , Когда рытье в нем стало очевидным, что что-то вверх по потоку продвигало поток. Этого было достаточно легко зафиксировать, так вот

public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     string input; 

     //something upstream after MVC 4 upgrade is advancing the stream to end before we can read it 
     controllerContext.HttpContext.Request.InputStream.Position = 0; 

     using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream)) 
     { 
      input = reader.ReadToEnd(); 
     } 

     return JsonConvert.DeserializeObject(
      input, 
      bindingContext.ModelType); 
    } 

Но мне интересно, что произошло, что сделало необходимым изменение? Была ли предыдущая реализация работает только по совпадению?

+1

Что такое значение Request.Content? Это уже заселено? Если это так, это может объяснить, почему InputStream необходимо переместить. MVC4 также добавил Restful WebAPI, который обеспечивает прямую поддержку для разбора тела запроса в параметрах модели. – B2K

ответ

3

Нет, предыдущая реализация не работала по совпадению.

ASP.NET MVC 3 введен встроенный JSON связывание поддержки, которая позволяет методы действий получить JSON-кодированные данные и модель-привязать его к параметрам действия методы.

JsonValueProviderFactory зарегистрирован по умолчанию в ASP.NET MVC 3 и далее. Поставщик значений JSON работает до привязки модели и сериализует данные запроса в словарь. Затем данные словаря передаются в model binder.

Давайте посмотрим, как JsonValueProviderFactory works.Here Ссылка на исходный код JsonValueProviderFactory представленной в ASP.NET MVC Open Source кода JsonValueProviderFactory.cs

GetDeserializedObject метод, определенный в JsonValueProviderFactory.cs, читает stream если Content-Type установлен в application/json и, следовательно, он оставляет Request.InputStream в конце потока. Итак, здесь GetDeserializedObject вызывается первым, а затем вызывается BindModel. Поскольку GetDeserializedObject уже прочитал поток один раз и продвинул Request.InputStream до конца потока, нам нужно сбросить Request.InputStream снова в BindModel

private static object GetDeserializedObject(ControllerContext controllerContext) 
{ 
    if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) 
    { 
      // not JSON request 
      return null; 
    } 
    StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream); 
    string bodyText = reader.ReadToEnd(); 
    if (String.IsNullOrEmpty(bodyText)) 
    { 
     // no JSON data 
     return null; 
    } 
    JavaScriptSerializer serializer = new JavaScriptSerializer(); 
    object jsonData = serializer.DeserializeObject(bodyText); 
    return jsonData; 
} 
+0

Спасибо, это имеет большой смысл. Является ли словарь, на который вы ссылаетесь, так же, как и Request.Content, на который ссылается комментарий @ B2K? Должен ли я менять свою реализацию связующего объекта для работы с этим словарем? – AlexCuse

Смежные вопросы