Есть ли способ отключить JSON ModelBinder в ASP.NET MVC 3 RC2?
В ASP.NET MVC 3 RC2 по умолчанию ModelBinder автоматически анализирует тело запроса, если для параметра Content-Type
установлено значение application/json
. Проблема в том, что в конце потока остается Request.InputStream
. Это означает, что если вы попытаетесь прочитать входной поток, используя свой собственный код, сначала reset верните его в начало:
// client sends HTTP request with Content-Type: application/json and a JSON
// string in the body
// requestBody is null because the stream is already at the end
var requestBody = new StreamReader(Request.InputStream).ReadToEnd();
// resets the position back to the beginning of the input stream
var reader = new StreamReader(Request.InputStream);
reader.BaseStream.Position = 0;
var requestBody = reader.ReadToEnd();
Поскольку я использую Json.NET
для выполнения сериализации/десериализации, я бы хотел отключить стандартный ModelBinder по умолчанию для этого дополнительного анализа. Есть ли способ сделать это?
Ответы
Ответ 1
В приложении Global_asax можно добавить следующее:
ValueProviderFactories.Factories.Remove(
ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().First());
Это предполагает, что существует только один из этого типа (который по умолчанию есть), но его можно легко изменить, чтобы работать, если его больше одного. Я не верю, что есть более чистый способ, если это то, что вы ищете.
Ответ 2
Я, очевидно, довольно поздно отвечаю на это, но я разработал способ изменить IValueProvider
для определенного действия в MVC5. Я не пытался понять, возможно ли это в MVC3, поскольку этот вопрос старый, но я предполагаю, что он несколько схож.
Отказ от ответственности: это не очень.
Сначала мы создаем новый интерфейс, который мы можем реализовать в атрибуте для создания конкретных действий:
internal interface IActionConfigurator
{
void Configure(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}
Затем мы создаем пользовательский ControllerActionInvoker
(или AsyncControllerActionInvoker
, если вы используете async
), чтобы подключить наш новый интерфейс:
internal sealed class CustomControllerActionInvoker : AsyncControllerActionInvoker
{
protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
{
var actionDescriptor = base.FindAction(controllerContext, controllerDescriptor, actionName);
var configurators = actionDescriptor.GetCustomAttributes(typeof(IActionConfigurator), true).Cast<IActionConfigurator>();
foreach (var configurator in configurators)
configurator.Configure(controllerContext, actionDescriptor);
return actionDescriptor;
}
}
Теперь мы должны реализовать пользовательский DefaultControllerFactory
для установки Controller.ActionInvoker
:
internal sealed class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
var instance = base.GetControllerInstance(requestContext, controllerType);
var controller = instance as Controller;
if (controller != null)
controller.ActionInvoker = new CustomControllerActionInvoker();
return instance;
}
}
Наконец, мы устанавливаем наш пользовательский контроллер factory как значение по умолчанию в код запуска:
ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
и реализуем наш интерфейс IActionConfigurator
в пользовательском атрибуте:
internal sealed class IgnoreJsonActionConfiguratorAttribute : Attribute, IActionConfigurator
{
public void Configure(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
// Here we can configure action-specific stuff on the controller
var factories = ValueProviderFactories.Factories.Where(f => !(f is JsonValueProviderFactory)).ToList();
controllerContext.Controller.ValueProvider = new ValueProviderFactoryCollection(factories).GetValueProvider(controllerContext);
}
}
Поскольку для каждого запроса создается новый экземпляр Controller, мы можем установить определенные для конкретного действия значения на контроллере, чтобы изменить способ обработки MVC действием.
[AcceptVerbs(HttpVerbs.Post)]
[IgnoreJsonActionConfigurator]
public async Task<ActionResult> Foo() { ... }