如何在MVC项目外部获取控制器及Action名称?
问题:在基础设施层获取MVC控制器与Action名称的问题
问题详情
我希望在基础设施层的服务中获取MVC表现层的控制器与Action名称。当前实现的服务代码如下:
public class ControllerActionDiscoveryService : IControllerActionDiscoveryService { public ControllerActionDiscoveryService(Type[] assembly) { } public List<ControllerActionInfo> Discover() { // Load the assembly using the correct path var assemblyPath = @".../Server.dll"; var assembly = Assembly.LoadFrom(assemblyPath); var controllerTypes = assembly.GetTypes().Where(type => type.IsClass==true && type.FullName.Contains("Controller")); foreach (var controllerType in controllerTypes) { // Do something with each controller type Console.WriteLine(controllerType.FullName); } } }
通过该代码可筛选出控制器,但无法获取Action;而使用如下筛选条件时返回null:
var controllerTypes = assembly.GetTypes().Where(type => type.BaseType==typeof(ControllerBase));
未使用Where筛选时的结果示例:Server.Controllers.HomeController Server.Areas.Dashboard.Controllers.FileManagerController Server.Areas.Dashboard.Controllers.HomeController。想请教获取MVC项目程序集的更佳方式,以及无法获取Action是否因程序集信息转为文本文件所致。
解决方案
1. 正确筛选MVC控制器的方式
用type.BaseType==typeof(ControllerBase)返回null的核心原因:
- 你的控制器大概率继承的是
Controller类(而非直接继承ControllerBase),而Controller本身是ControllerBase的子类,直接判断BaseType会不匹配。 - 需排除抽象控制器类,避免无效结果。
正确的筛选逻辑:
var controllerTypes = assembly.GetTypes() .Where(type => type.IsClass && !type.IsAbstract && typeof(ControllerBase).IsAssignableFrom(type));
这个逻辑会匹配所有继承自ControllerBase的类(包括Controller的子类),同时过滤掉抽象类。
2. 获取控制器中的Action方法
要获取Action,需要筛选符合MVC规则的方法:公共实例方法、没有NonActionAttribute标记、非特殊方法(如构造函数、属性访问器)。示例代码:
public List<ControllerActionInfo> Discover() { var assemblyPath = @".../Server.dll"; var assembly = Assembly.LoadFrom(assemblyPath); var controllerTypes = assembly.GetTypes() .Where(type => type.IsClass && !type.IsAbstract && typeof(ControllerBase).IsAssignableFrom(type)); var result = new List<ControllerActionInfo>(); foreach (var controllerType in controllerTypes) { // 筛选符合规则的Action方法 var actionMethods = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(method => !method.IsSpecialName && !method.GetCustomAttributes(typeof(NonActionAttribute), inherit: true).Any()); foreach (var actionMethod in actionMethods) { result.Add(new ControllerActionInfo { ControllerName = controllerType.Name.Replace("Controller", ""), ControllerFullName = controllerType.FullName, ActionName = actionMethod.Name, ActionParameters = actionMethod.GetParameters().Select(p => p.ParameterType.Name).ToList() }); } } return result; }
3. 获取MVC程序集的更佳方式
硬编码路径易出错,推荐两种方案:
- 依赖注入传入程序集:在MVC项目启动时(如
Program.cs),把MVC程序集注入到基础设施服务中,避免硬编码路径:
服务中直接使用传入的程序集:// MVC项目Program.cs中 builder.Services.AddScoped<IControllerActionDiscoveryService>(sp => new ControllerActionDiscoveryService(new[] { typeof(HomeController).Assembly }));public class ControllerActionDiscoveryService : IControllerActionDiscoveryService { private readonly Assembly[] _assemblies; public ControllerActionDiscoveryService(Type[] assemblyTypes) { _assemblies = assemblyTypes.Select(t => t.Assembly).Distinct().ToArray(); } public List<ControllerActionInfo> Discover() { var result = new List<ControllerActionInfo>(); foreach (var assembly in _assemblies) { var controllerTypes = assembly.GetTypes() .Where(type => type.IsClass && !type.IsAbstract && typeof(ControllerBase).IsAssignableFrom(type)); // 后续Action筛选逻辑同上 } return result; } } - 通过程序集名称加载:如果必须动态加载,可使用
Assembly.Load("Server")(传入程序集名称而非路径),前提是该程序集在应用依赖查找路径内。
4. 无法获取Action的原因
和“程序集信息转为文本文件”无关,纯粹是之前的代码只遍历了控制器类型,没有编写筛选Action方法的逻辑。只要程序集能被正常加载(Assembly.LoadFrom执行成功),就能获取到方法信息。
内容的提问来源于stack exchange,提问作者Russel
相关产品推荐
相关产品推荐

