I'm obviously pretty late in answering this, but I've developed a way to change the IValueProvider
for a specific action in MVC5. I haven't gone through the effort of seeing if this is possible in MVC3 since this question is old, but I assume it is somewhat similar.
Disclaimer: It's not pretty.
First, we create a new interface we can implement in an attribute to make action-specific configurations:
internal interface IActionConfigurator
{
void Configure(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}
Then, we create a custom ControllerActionInvoker
(or AsyncControllerActionInvoker
if you use async
) to hook up our new interface:
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;
}
}
Now, we have to implement a custom DefaultControllerFactory
to set 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;
}
}
Finally, we set our custom controller factory as the default in the startup code:
ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
and implement our IActionConfigurator
interface in a custom attribute:
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);
}
}
Since a new Controller instance is created on each request, we are able to set action-specific values on the controller to modify how MVC processes the action.
[AcceptVerbs(HttpVerbs.Post)]
[IgnoreJsonActionConfigurator]
public async Task<ActionResult> Foo() { ... }