You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 19:50:10