2009-12-10 5 views
14

Возможно ли, чтобы все контроллеры были доступны для ControllerFactory?
Что я хочу сделать, так это получить список всех типов контроллеров в приложении, но последовательно.ASP.NET MVC: получить все контроллеры

Так что все контроллеры, которые я получаю, являются теми же, что и разрешение по умолчанию.

(Фактическая задача - найти все методы действий, которые имеют данный атрибут).

ответ

12

Вы можете использовать отражение, чтобы перечислять все классы в сборке и фильтровать только классы, наследуемые от класса Controller.

Лучшая рекомендация asp.net mvc source code. Взгляните на реализации классов ControllerTypeCache и ActionMethodSelector. ControllerTypeCache показывает, как получить все классы контроллеров.

 internal static bool IsControllerType(Type t) { 
      return 
       t != null && 
       t.IsPublic && 
       t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) && 
       !t.IsAbstract && 
       typeof(IController).IsAssignableFrom(t); 
     } 

public void EnsureInitialized(IBuildManager buildManager) { 
      if (_cache == null) { 
       lock (_lockObj) { 
        if (_cache == null) { 
         List<Type> controllerTypes = GetAllControllerTypes(buildManager); 
         var groupedByName = controllerTypes.GroupBy(
          t => t.Name.Substring(0, t.Name.Length - "Controller".Length), 
          StringComparer.OrdinalIgnoreCase); 
         _cache = groupedByName.ToDictionary(
          g => g.Key, 
          g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase), 
          StringComparer.OrdinalIgnoreCase); 
        } 
       } 
      } 
     } 

И ActionMethodSelector показывает, как проверить, имеет ли метод желаемый атрибут.

private static List<MethodInfo> RunSelectionFilters(ControllerContext controllerContext, List<MethodInfo> methodInfos) { 
      // remove all methods which are opting out of this request 
      // to opt out, at least one attribute defined on the method must return false 

      List<MethodInfo> matchesWithSelectionAttributes = new List<MethodInfo>(); 
      List<MethodInfo> matchesWithoutSelectionAttributes = new List<MethodInfo>(); 

      foreach (MethodInfo methodInfo in methodInfos) { 
       ActionMethodSelectorAttribute[] attrs = (ActionMethodSelectorAttribute[])methodInfo.GetCustomAttributes(typeof(ActionMethodSelectorAttribute), true /* inherit */); 
       if (attrs.Length == 0) { 
        matchesWithoutSelectionAttributes.Add(methodInfo); 
       } 
       else if (attrs.All(attr => attr.IsValidForRequest(controllerContext, methodInfo))) { 
        matchesWithSelectionAttributes.Add(methodInfo); 
       } 
      } 

      // if a matching action method had a selection attribute, consider it more specific than a matching action method 
      // without a selection attribute 
      return (matchesWithSelectionAttributes.Count > 0) ? matchesWithSelectionAttributes : matchesWithoutSelectionAttributes; 
     } 
+1

Внутренний, мне жаль, что они этого не сделали. Но хорошо, это ответ. –

7

Я не думаю, что можно дать простой ответ на этот вопрос, потому что это зависит от множества различных факторов, включая реализацию IControllerFactory.

Например, если у вас есть полностью выполненная на заказ реализация IControllerFactory, все ставки отключены, так как он может использовать любой способ создания экземпляров Controller.

Однако DefaultControllerFactory ищет соответствующий тип контроллера во всех сборках, определенных в RouteCollection (настроенных в global.asax).

В этом случае вы можете пропустить все сборки, связанные с RouteCollection, и искать контроллеры в каждом.

Нахождение контроллеров в данной сборке относительно легко:

var controllerTypes = from t in asm.GetExportedTypes() 
         where typeof(IController).IsAssignableFrom(t) 
         select t; 

asm где находится экземпляр Assembly.

Смежные вопросы