如何在 .NET 中获取解决方案中的所有程序集?

How to get all assemblies in solution in .NET?

我有一个典型的 3 层 .NET 应用程序。

领域层不引用其他项目。

数据访问层引用域层并实现一些存储库。

Web 视图层使用领域层的服务并控制 Autofac(IOC 容器)。

域层和数据访问层实现 Autofac 模块。这意味着我可以从 Web 视图层扫描所有程序集并将它们注册到 Autofac 以提供依赖项注入。

我不想让我的 Web 视图层知道或关心使用了哪个数据访问层,所以我不想包含对它的引用。但是,如果我不引用数据访问层,查找程序集的扫描将不会拾取它。

WebView层调用的启动方法如下:

private static void RegisterAutofacAssemblyModules(ContainerBuilder builder)
    {
        IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(x => x.FullName.Contains("Boutique"));

        if (HostingEnvironment.InClientBuildManager)
        {
            assemblies = assemblies.Union(BuildManager.GetReferencedAssemblies().Cast<Assembly>()).Distinct();
        }

        builder.RegisterAssemblyModules(assemblies.ToArray());
    }

我添加了 .Where() 以希望提高性能,因为必须扫描的程序集更少。 (不确定这是不是真的)。​​

如果我引用数据访问层(在 Web 视图层中),这段代码工作得很好。但我不希望 Web 视图层引用数据访问层。那么如何扫描程序集以确保包含数据访问层呢?如果可能的话,我只想获得解决方案中的所有程序集。

在我看来,您可能缺少一个横切层来处理您的 IoC 容器注册。

创建一个名为CrossCutting.IoC的新class项目并将所有Autofac注册移至其中,Web视图层注册除外,这些将由Web层本身处理。

因此 Web 层将引用 IoC 层,不再需要引用数据层。 IoC 层将引用每个其他项目。

我使用 SimpleInjector,所以我从未在 Autofac 中实现过它,但快速搜索后看起来您需要使用 Modules as explained in this answer. If you follow that answer's advice and create one module for each layer, then you can use RegisterAssemblyModules 并一次注册所有模块。

编辑

我刚刚在一个 WebAPI 项目中对此进行了测试,该项目具有与您相同的层加上 CrossCutting.IoC 并且它有效。根据 the docs,您甚至不必使用 AppDomain,只需使用 BuildManager:

protected void Application_Start()
{
    var builder = new ContainerBuilder();

    var config = GlobalConfiguration.Configuration;

    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
    builder.RegisterWebApiFilterProvider(config);
    builder.RegisterWebApiModelBinderProvider();

    // Automatically scan and register all modules found in referenced assemblies
    var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
    builder.RegisterAssemblyModules(assemblies);

    var container = builder.Build();
    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}

虽然我不会将它配置为运行时扫描,但我认为这是一种风险,我更愿意明确说明它,所以如果你愿意,只需将自动扫描部分替换为 RegisterModule 调用每个模块:

builder.RegisterModule<CrossCuttingModule>();
builder.RegisterModule<DomainModule>();
// etc...