Dotnet Core获取已加载程序集列表以进行依赖注入

11

我正在使用 AutoFac 根据它们的接口实现自动注册依赖项,方法如下:

builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).AsImplementedInterfaces();

这对于入口程序集非常有效,但是其他相关的程序集怎么办?

我想做这样的事情:

IList<Assembly> assemblies = GetLoadedAssemblies();
foreach(var assembly in assemblies)
{
  builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
}

我搜索过并看到很多关于.netcore 1.0的内容,包括AssemblyLoadContext等,但在1.1中似乎不再存在。基本上,当你搜索时,你会得到许多关于已经不起作用的过时参考。

肯定有一种方式可以获取当前加载的程序集。

我该怎么做?


你真的对已加载的程序集感兴趣,还是对应用程序依赖图中的程序集感兴趣?如果你的程序集没有直接引用其中一个程序集,即使在csproj中指定了它作为依赖项,它也可能没有被加载。 - Martin Ullrich
在这个特定的应用程序中,已加载的程序集就可以了。但在其他应用程序中,我想要加载相关的程序集并进行映射,因为你说得对,它们可能还没有被加载。 - Robert
3个回答

19

.NET Core 2.0 中带来了许多从 .NET Framework 移植的API,其中之一是 AppDomain.CurrentDomain.GetAssemblies(),它允许你获取已加载到应用程序域执行上下文中的程序集。当然,这个概念并没有完全从 .NET Framework 移植到 .NET Core,所以不能创建自己的应用程序域并将其作为单个进程内的隔离单元处理(因此,您只有一个应用程序域)。但对于您想要实现的目标来说,这已足够。


2
您可以使用与 .netstandard 1.6 兼容的 Scrutor,或查看此处了解其实现方式。
    public IImplementationTypeSelector FromAssemblyDependencies(Assembly assembly)
    {
        Preconditions.NotNull(assembly, nameof(assembly));

        var assemblies = new List<Assembly> { assembly };

        try
        {
            var dependencyNames = assembly.GetReferencedAssemblies();

            foreach (var dependencyName in dependencyNames)
            {
                try
                {
                    // Try to load the referenced assembly...
                    assemblies.Add(Assembly.Load(dependencyName));
                }
                catch
                {
                    // Failed to load assembly. Skip it.
                }
            }

            return InternalFromAssemblies(assemblies);
        }
        catch
        {
            return InternalFromAssemblies(assemblies);
        }
   }

0

这是一个老问题,但是没有一个答案适用于我。
我在使用autofac与asp.net core webapi项目(.net 6)。

这就是我需要获取程序集的地方:

host
// autofac
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
// autofac container
.ConfigureContainer<ContainerBuilder>(builder => {
       // get assemblies for register
       var assemblies = ???
       builder.RegisterAssemblyTypes(assemblies).AsImplementedInterfaces()...
});

该项目由DDD设计,依赖关系如下:

webapi -> domain,infra
infra -> domain

针对我的情况:
AppDomain.CurrentDomain.GetAssemblies() 只能获取 webapi 程序集。
顺便说一下:Assembly.GetEntryAssembly() 也可以获取 webapi 程序集。 webapiAssembly.GetReferencedAssemblies() 只能获取域项目的程序集。找不到基础架构程序集。

为什么 GetReferencedAssemblies() 没有按预期获取所有引用的程序集?

这是因为在我的项目中,webapi 使用了一个存储库接口,该接口在域中定义,但在基础架构中实现。Webapi 项目没有直接依赖基础架构层(使用基础架构中定义的类/接口)。因此,基础架构程序集未被包含。

如果 webapi 直接依赖于基础架构,则使用 GetReferencedAssemblies() 就可以了。

这里有另一个适合我的解决方案:
使用 Microsoft.Extensions.DependencyModel(nuget 包)中包含的 DependencyContext 获取我想要的所有程序集(webapi、域、基础架构)。

public static class AssemblyHelper
{
    // get all assemblies that I wanted
    // you may want to filter assemblies with a namespace start name
    public static Assembly[] GetAllAssemblies(string namespaceStartName = "")
    {
        var ctx = DependencyContext.Default;
        var names = ctx.RuntimeLibraries.SelectMany(rl =>  rl.GetDefaultAssemblyNames(ctx));

        if (!string.IsNullOrWhiteSpace(namespaceStartName))
        {
            if (namespaceStartName.Substring(namespaceStartName.Length - 1, 1) != ".")
                namespaceStartName += ".";

            names = names.Where(x => x.FullName != null && x.FullName.StartsWith(namespaceStartName)).ToArray();
        }

        var assemblies = new List<Assembly>();
        foreach (var name in names)
        {
            try
            {
                assemblies.Add(Assembly.Load(name));
            }
            catch { } // skip
        }

        return assemblies.ToArray();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接