ASP.NET MVC: Get all controllers

后端 未结 2 957
孤城傲影
孤城傲影 2020-12-08 05:26

Is it possible to get all controllers available to a ControllerFactory?
What I want to do is get a list of all controller types in application, but in a consistent way.<

2条回答
  •  执笔经年
    2020-12-08 06:09

    You can use reflection to enumerate all classes in an assembly, and filter only classes inherit from Controller class.

    The best reference is asp.net mvc source code. Take a look of the implementations of ControllerTypeCache and ActionMethodSelector class. ControllerTypeCache shows how to get all controller classes available.

           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 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);
                        }
                    }
                }
            }
    

    And ActionMethodSelector shows how to check if a method has desired attribute.

    private static List RunSelectionFilters(ControllerContext controllerContext, List 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 matchesWithSelectionAttributes = new List();
                List matchesWithoutSelectionAttributes = new List();
    
                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;
            }
    

提交回复
热议问题