ASP.NET MVC: Get all controllers

徘徊边缘 提交于 2019-11-28 05:06:00

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

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

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

I don't think it's possible to give a simple answer to this question, because it depends on a lot of different things, including the implementation of IControllerFactory.

For instance, if you have a completely custom-built IControllerFactory implementation, all bets are off, because it may use any sort of mechanism to create Controller instances.

However, the DefaultControllerFactory looks after the appropriate Controller type in all the assemblies defined in the RouteCollection (configured in global.asax).

In this case, you could loop through all the assemblies associated with the RouteCollection, and look for Controllers in each.

Finding Controllers in a given assembly is relatively easy:

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

where asm is an Assembly instance.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!