在ASP.NET 5中动态加载程序集

时间:2015-04-02 19:34:06

标签: c# asp.net-core c#-6.0

我曾经有一些代码扫描了我的应用程序的bin目录,但尚未加载到AppDomain中的程序集并加载它们。它基本上看起来像:

foreach (var assemblyPath in Directory.GetFiles("path\to\bin", "*.dll"))
{
    var inspected = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
    Assembly.Load(inspected.GetName());
}

为简洁起见,我跳过了try / catch子句等。

这允许我在运行时删除bin文件夹中的程序集并实现某些接口,并让IoC容器自动接收它们。现在有了新的Roslyn魔法,在调试时就没有物理DLL了。有没有办法动态检索程序集名称,项目名称或依赖项名称(在project.json中)。

我想我必须实现像this example in the Entropy repo之类的东西,但我不知道如何为我的场景实现它。

5 个答案:

答案 0 :(得分:6)

您可以使用IAssemblyLoadContextAccessor接口动态加载ASP.NET 5类库(.xproj)项目。以下示例代码适用于Beta 4:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        var assemblyLoadContextAccessor = app.ApplicationServices.GetService<IAssemblyLoadContextAccessor>();
        var loadContext = assemblyLoadContextAccessor.Default;
        var loadedAssembly = loadContext.Load("NameOfYourLibrary");
    }
}

答案 1 :(得分:2)

您正在寻找的是ILibraryManager实现,它提供了对应用程序的完整依赖关系图的访问。这已经流过ASP.NET 5 DI系统了。所以,你可以从那里接触它。

Sample usage可以在RoslynCompilationService内找到。

答案 2 :(得分:1)

我使用@tugberk建议的ILibraryManager部分解决了这个问题。我稍微改变了方法,因此无需为新程序集扫描bin文件夹。我只想要当前AppDomain中所有已加载的程序集。

我在类型查找器类中注入了ILibraryManager接口的实例,并使用GetReferencingLibraries()方法和核心程序集的名称,该程序集由应用程序中的所有其他程序集引用。 / p>

可以找到示例实现here,其中这是重要的部分:

public IEnumerable<Assembly> GetLoadedAssemblies()
{
    return _libraryManager.GetReferencingLibraries(_coreAssemblyName.Name)
                          .SelectMany(info => info.Assemblies)
                          .Select(info => Assembly.Load(new AssemblyName(info.Name)));
}

答案 3 :(得分:0)

对于.net核心用户,这是我从特定路径加载程序集的代码。我不得不使用指令,因为它与.Net Framework和.Net Core略有不同。

在您的班级标题中,您需要声明使用类似于:

的内容
#if NET46
#else
    using System.Runtime.Loader;
#endif

在你的函数中,类似于以下内容:

string assemblyPath = "c:\temp\assmebly.dll";

#if NET46
                Assembly assembly = Assembly.LoadFrom(assemblyPath);
#else
                AssemblyLoadContext context = AssemblyLoadContext.Default;
                Assembly assembly = context.LoadFromAssemblyPath(assemblyPath);
#endif

答案 4 :(得分:0)

它不是ASP.NET,但可以轻松转换为asp.net。 在用于加载程序集的if函数下方,并在该程序集的类内调用方法。

        private static FormCustomized loadLayout(global::System.String layoutFilename, global::System.String layoutNameSpace)
    {
        FormCustomized mainForm = default;
        Type typeMainLayout = default;
        FileInfo layoutFile;
        layoutFile = new FileInfo(layoutFilename);
        layoutFile.Refresh();
        if (!layoutFile.Exists)
        {
            MessageBox.Show("Layout file not found. You need to reinstall the program");
            return default;
        }

        try
        {
            Assembly assemblyRaw = Assembly.LoadFrom(layoutFilename);
            AssemblyLoadContext context = AssemblyLoadContext.Default;
            Assembly assembly = context.LoadFromAssemblyPath(layoutFilename);


            Type typeMainLayoutIni = assembly.GetType(layoutNameSpace + ".initializeLayoutClass");
            Object iniClass = Activator.CreateInstance(typeMainLayoutIni, true);
            MethodInfo methodInfo = typeMainLayoutIni.GetMethod("AssembliesToLoadAtStart");
            enVars.assemblies = (Dictionary<string, Environment.environmentAssembliesClass>)methodInfo.Invoke(iniClass, default);
            typeMainLayout = assembly.GetType(layoutNameSpace + ".mainAppLayoutForm");
            mainForm = Activator.CreateInstance(typeMainLayout, enVars) as FormCustomized;
        }
        catch (Exception ex)
        {
            return default;
        }

        return default;
    }