Jestem oczywiście dość późno, odpowiadając na to, ale opracowałem sposób na zmianę IValueProvider
dla określonej akcji w MVC5. Nie starałem się sprawdzić, czy jest to możliwe w MVC3, ponieważ to pytanie jest stare, ale zakładam, że jest nieco podobny.
Nota prawna: Nie jest ładna.
Najpierw tworzymy nowy interfejs możemy realizować w atrybucie zrobić konfiguracje działania specyficzne:
internal interface IActionConfigurator
{
void Configure(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}
Następnie tworzymy niestandardowe ControllerActionInvoker
(lub AsyncControllerActionInvoker
jeśli używasz async
) zahaczyć nasz nowy interfejs:
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;
}
}
teraz musimy wdrożyć zwyczaj DefaultControllerFactory
ustawić 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;
}
}
Wreszcie ruszyliśmy naszą fabrykę zwyczaj kontrolera jako domyślny w kodzie startowym:
ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
i realizować naszą IActionConfigurator
interfejs w atrybutu niestandardowego:
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);
}
}
Od nowej instancji kontrolera jest tworzony na każde żądanie, jesteśmy w stanie ustawić na sterowniku określone wartości, aby zmodyfikować sposób, w jaki MVC przetwarza akcję.
[AcceptVerbs(HttpVerbs.Post)]
[IgnoreJsonActionConfigurator]
public async Task<ActionResult> Foo() { ... }
Dzięki, to się udało! Czy to jest nieudokumentowana funkcja, czy po prostu coś mi umknęło? –
MVC domyślnie zawiera zestaw fabryk dostawców wartości. W MVC3 uwzględnili JsonValueProviderFactory jako jedną z wartości domyślnych. Cały powyższy kod wykonuje go i usuwa, gdy aplikacja się uruchomi. Innym sposobem obejścia tego problemu może być nieuzyskanie żądań ajaxowych za pomocą aplikacji typu content/json, ale uważam, że usunięcie fabryki dostawców wartości jest prawdopodobnie bardziej poprawne. –
Dzięki za wyjaśnienie. Nie wiedziałem nawet, że istnieją fabryki dostawców dla takich rzeczy, jak zapytania i trasy. Zakładałem, że modelBinder to wszystko obsługuje. –