В asp.net mvc возможно ли сделать универсальный контроллер?

Я пытаюсь создать универсальный контроллер, а именно:

public class MyController<T> : Controller where T : SomeType
{ ... }

Однако, когда я пытаюсь использовать его, я сталкиваюсь с этой ошибкой везде...

Имя контроллера должно заканчиваться на "Контроллер"

Итак, мой вопрос, возможно ли сделать универсальный контроллер в asp.net mvc?

Спасибо!

5 ответов

Решение

Если я правильно вас понимаю, то, что вы пытаетесь сделать, это направлять все запросы для данной Модели через универсальный контроллер типа T.

Вы хотели бы, чтобы T варьировался в зависимости от запрашиваемой модели.

Вы хотели бы /Product/Index для запуска MyController<Product>.Index()

Это можно сделать, написав свой собственный IControllerFactory и реализации CreateController метод как это:

public IController CreateController(RequestContext requestContext, string controllerName)
{
    Type controllerType = Type.GetType("MyController")
                              .MakeGenericType(Type.GetType(controllerName));
    return Activator.CreateInstance(controllerType) as IController;
}

Да, вы можете, это хорошо, и я сам много их использовал.

Вам нужно убедиться, что когда вы наследуете от MyController, вы по-прежнему заканчиваете имя типа контроллером:

public class FooController :  MyController<Foo>
{ 
 ...
}

Это дубликат универсального контроллера asp.net mvc, который на самом деле содержит правильный ответ. Ответ Джеффа Фрица абсолютно неверен. Создание собственного IControllerFactory не обойдет ограничение в ExpressionHelper.GetRouteValuesFromExpression, которое генерирует ошибку, которую вы видите. Реализация собственного IControllerFactory по-прежнему будет вызывать ошибки при вызове RedirectToAction, BuildUrlFromExpression, ActionLink, RenderAction, BeginForm, любых любых методов, которые их вызывают.

Что меня интересует, так это то, что "ограничение по соглашению" Microsoft уже соблюдается ограничением "где TController: Controller", которое накладывается на тип в методе ExpressionHelper.GetRouteValuesFromExpression. Ни один универсальный никогда не будет удовлетворять валидации конвенции:

string controllerName = typeof(TController).Name;
if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {
    throw new ArgumentException(MvcResources.ExpressionHelper_TargetMustEndInController, "action");
}

если он не наследуется классом, оканчивающимся на "Controller", потому что typeof(AnyGeneric).Name никогда не заканчивается на "Controller".

Фабрика контроллеров по умолчанию использует "соглашение" вокруг имен контроллеров, когда пытается найти контроллер для отправки запроса. При желании вы можете переопределить эту функцию поиска, что позволит вашему универсальному контроллеру работать.

Эта статья MSDN...

http://msdn.microsoft.com/en-us/magazine/dd695917.aspx

... имеет хорошее описание того, что происходит.

Если бы я был вами, я бы взял исходный код MVC и создал бы тестовый проект MVC с исходным кодом, чтобы вы могли проверить, где генерируется исключение, и посмотреть, что вы можете сделать с вашей общей идеей и принудительным соглашением об именовании "*controller".,

Другие вопросы по тегам