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

如何在.NET 8.0项目的Startup.cs中获取所有ProjectReference并转为数组

如何在.NET 8.0项目的Startup.cs中获取所有ProjectReference并转为数组

当然可以搞定!不用再手动硬编码每个类库的程序集名称啦,我给你两种实用的方案,帮你自动获取所有项目引用的类库程序集,轻松注册里面的服务:

方案一:通过程序集依赖关系自动筛选

这种方案的核心思路是:我们自己的类库项目都会引用定义了IService的Common库,而第三方包不会。所以可以通过当前Web程序集的依赖项,筛选出符合这个条件的程序集,完全不用硬编码任何名称。

public static void ConfigureServices(this IServiceCollection services)
{
    // 获取当前Web项目的程序集
    var webAssembly = Assembly.GetExecutingAssembly();
    // 获取定义了IService的Common程序集,作为筛选依据
    var commonAssembly = typeof(IService).Assembly;

    // 筛选出所有引用了Common程序集的依赖程序集(即我们的项目类库)
    var referencedAssemblies = webAssembly.GetReferencedAssemblies()
        .Select(asmName => 
        {
            try
            {
                return Assembly.Load(asmName);
            }
            catch
            {
                // 加载失败的跳过(比如第三方包的程序集)
                return null;
            }
        })
        .Where(asm => asm != null && asm.GetReferencedAssemblies().Any(r => r.FullName == commonAssembly.FullName))
        .Select(asm => asm!)
        // 把Web程序集和Common程序集也加进去
        .Concat(new[] { webAssembly, commonAssembly })
        .Distinct()
        .ToArray();

    // 从所有筛选到的程序集中,找出所有IService的实现类
    var serviceTypes = referencedAssemblies
        .SelectMany(asm => asm.GetTypes())
        .Where(t => typeof(IService).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)
        .ToArray();

    // 批量注册服务
    foreach (var serviceType in serviceTypes)
    {
        // 获取对应的服务接口(排除IService本身,取它的子接口)
        var interfaceType = serviceType.GetInterfaces()
            .FirstOrDefault(i => typeof(IService).IsAssignableFrom(i) && i != typeof(IService));

        if (interfaceType != null)
        {
            services.AddScoped(interfaceType, serviceType);
        }
    }
}

方案优势

  • 完全自动适配项目引用的变化,新增/删除类库项目时,代码不需要任何修改
  • 不会误把第三方包的程序集加进来,筛选逻辑精准

方案二:通过MSBuild提前收集项目引用

如果你的项目结构比较固定,也可以通过MSBuild在编译时自动收集所有ProjectReference的名称,然后在代码里读取这个列表,这种方式更直接可控。

第一步:修改Web项目的.csproj

在Web项目的.csproj文件里添加一个Target,编译时自动生成包含所有项目引用名称的文件:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <!-- 保留你原有的PropertyGroup、ItemGroup内容 -->

  <!-- 新增:编译时收集所有ProjectReference的名称,写入文件 -->
  <Target Name="CollectProjectReferences" BeforeTargets="Build">
    <ItemGroup>
      <ProjectReferenceAssemblyNames Include="%(ProjectReference.Name)" />
    </ItemGroup>
    <WriteLinesToFile 
      File="$(OutDir)\ProjectReferences.txt" 
      Lines="@(ProjectReferenceAssemblyNames)" 
      Overwrite="true" 
      Encoding="UTF-8" />
  </Target>
</Project>

第二步:在ConfigureServices中读取并加载程序集

public static void ConfigureServices(this IServiceCollection services)
{
    // 读取编译时生成的项目引用名称文件
    var referencesFilePath = Path.Combine(AppContext.BaseDirectory, "ProjectReferences.txt");
    if (!File.Exists(referencesFilePath))
    {
        throw new FileNotFoundException("未找到项目引用列表文件,请检查MSBuild配置是否正确", referencesFilePath);
    }

    var projectAssemblyNames = File.ReadAllLines(referencesFilePath)
        .Where(name => !string.IsNullOrWhiteSpace(name))
        .ToArray();

    // 加载所有项目类库程序集,加上Web程序集和Common程序集
    var referencedAssemblies = projectAssemblyNames
        .Select(Assembly.Load)
        .Concat(new[] { Assembly.GetExecutingAssembly(), typeof(IService).Assembly })
        .Distinct()
        .ToArray();

    // 后续的服务注册逻辑和方案一完全一致
    var serviceTypes = referencedAssemblies
        .SelectMany(asm => asm.GetTypes())
        .Where(t => typeof(IService).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)
        .ToArray();

    foreach (var serviceType in serviceTypes)
    {
        var interfaceType = serviceType.GetInterfaces()
            .FirstOrDefault(i => typeof(IService).IsAssignableFrom(i) && i != typeof(IService));

        if (interfaceType != null)
        {
            services.AddScoped(interfaceType, serviceType);
        }
    }
}

方案优势

  • 筛选逻辑100%精准,完全基于编译时的项目引用列表
  • 不需要处理第三方包程序集的加载异常,性能更稳定

额外小提示

如果你的项目程序集有统一的命名规则(比如都以YourCompany.开头),还可以简化方案一中的筛选逻辑,直接根据程序集名称前缀判断:

// 替换方案一中的筛选逻辑
var referencedAssemblies = webAssembly.GetReferencedAssemblies()
    .Select(asmName => 
    {
        try
        {
            return Assembly.Load(asmName);
        }
        catch
        {
            return null;
        }
    })
    .Where(asm => asm != null && asm.Name.StartsWith("YourCompany."))
    .Select(asm => asm!)
    .Concat(new[] { webAssembly, commonAssembly })
    .Distinct()
    .ToArray();

备注:内容来源于stack exchange,提问作者bcExpt1123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:19:36