如何在dotnet核心中动态加载程序集

Com*_*nDk 9 c# .net-core asp.net-core

我正在构建一个Web应用程序,我想要单独关注,即在不同的项目中进行抽象和实现.

为了实现这一点,我尝试实现一个组合根概念,其中所有实现必须具有ICompositionRootComposer注册服务,类型等的实例.

public interface ICompositionRootComposer
{
    void Compose(ICompositionConfigurator configurator);
}
Run Code Online (Sandbox Code Playgroud)

在构建层次结构中直接引用的项目中,将ICompositionRootComposer调用实现,并在基础IoC容器中正确注册服务.

当我尝试在项目中注册服务时出现问题,我在其中设置了一个后期构建任务,将构建的dll复制到Web项目的调试文件夹:

cp -R $(TargetDir)"assembly and symbol name"* $(SolutionDir)src/"webproject path"/bin/Debug/netcoreapp1.1
Run Code Online (Sandbox Code Playgroud)

我正在加载程序集:(灵感:如何加载位于.net核心控制台应用程序中的文件夹中的程序集)

internal class AssemblyLoader : AssemblyLoadContext
{
    private string folderPath;

    internal AssemblyLoader(string folderPath)
    {
        this.folderPath = Path.GetDirectoryName(folderPath);
    }

    internal Assembly Load(string filePath)
    {
        FileInfo fileInfo = new FileInfo(filePath);
        AssemblyName assemblyName = new AssemblyName(fileInfo.Name.Replace(fileInfo.Extension, string.Empty));

        return this.Load(assemblyName);
    }

    protected override Assembly Load(AssemblyName assemblyName)
    {
        var dependencyContext = DependencyContext.Default;
        var ressource = dependencyContext.CompileLibraries.FirstOrDefault(r => r.Name.Contains(assemblyName.Name));

        if(ressource != null)
        {
            return Assembly.Load(new AssemblyName(ressource.Name));
        }

        var fileInfo = this.LoadFileInfo(assemblyName.Name);
        if(File.Exists(fileInfo.FullName))
        {
            Assembly assembly = null;
            if(this.TryGetAssemblyFromAssemblyName(assemblyName, out assembly))
            {
                return assembly;
            }
            return this.LoadFromAssemblyPath(fileInfo.FullName);
        }

        return Assembly.Load(assemblyName);
    }

    private FileInfo LoadFileInfo(string assemblyName)
    {
        string fullPath = Path.Combine(this.folderPath, $"{assemblyName}.dll");

        return new FileInfo(fullPath);
    }

    private bool TryGetAssemblyFromAssemblyName(AssemblyName assemblyName, out Assembly assembly)
    {
        try
        {
            assembly = Default.LoadFromAssemblyName(assemblyName);
            return true;
        }
        catch
        {
            assembly = null;
            return false;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有了这个,我就可以加载程序集并调用项目ICompositionRootComposer实现.

但问题是它似乎没有认出我的任何类型.

用调用我的配置器时

configurator.RegisterTransiantService<IFoo, Foo>();
Run Code Online (Sandbox Code Playgroud)

它应该在IoC中注册IFoo和Foo.
但是在调试时我无法获取类型的信息,即通过Visual Studio Code中调试控制台中的typeof(Foo).

Ste*_*ger 9

Necromancing.

您可以为旧的Assembly.LoadFile创建一个包装类来执行此操作.
这样做的另一个好处是,您可以通过在旧代码库中应用搜索和替换更改来保持向后兼容dotnet-none-core.
您需要System.Runtime.Loader通过nuget 添加.

namespace System.Reflection
{

    public class Assembly2
    {


        public static System.Reflection.Assembly LoadFile(string path)
        {
            System.Reflection.Assembly ass = null;

#if NET_CORE
            // Requires nuget - System.Runtime.Loader
            ass = System.Runtime.Loader.AssemblyLoadContext.Default
                   .LoadFromAssemblyPath(path);
#else
            ass = System.Reflection. Assembly.LoadFile(path);
#endif 
            // System.Type myType = ass.GetType("Custom.Thing.SampleClass");
            // object myInstance = Activator.CreateInstance(myType);
            return ass;
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,我最终连接到了“AssemblyLoadContext.Resolving”事件来帮助加载上下文加载它自身无法加载的程序集。 (3认同)

Com*_*nDk 5

我找到了解决问题的方法。

事实证明,我将该属性PreserveCompilationContext设置为 true,这就是调试器不会注册我手动复制的程序集的原因。当我从 Web 项目 csproj 文件中删除该属性时,一切正常。