有没有办法在ASP.NET MVC 3 RC2中禁用JSON ModelBinder?

在ASP.NET MVC 3 RC2中,如果Content-Type设置为application/json ,则默认的ModelBinder将自动解析请求主体。 问题是,这会在流的末尾留下Request.InputStream 。 这意味着如果您尝试使用自己的代码读取输入流,则首先将其重置为开头:

 // 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进行额外的解析。 有没有办法做到这一点?

您可以在Global.asax中的Application_Start中添加以下内容:

 ValueProviderFactories.Factories.Remove( ValueProviderFactories.Factories.OfType().First()); 

这假设只有一种类型(默认情况下有),但如果有多种类型,可以很容易地将其更改为有效。 如果那是你想要的,我不相信有一个更清洁的方式。

我显然很晚才回答这个问题,但我已经开发出一种方法来改变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(); 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; } } 

最后,我们将自定义控制器工厂设置为启动代码中的默认值:

 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 Foo() { ... }