如何加载位于.net核心控制台应用程序中的文件夹中的程序集

Vah*_*iri 35 .net c# .net-core .net-core-rc2

我正在.Net Core平台上制作一个控制台应用程序,并且想知道,如何使用C#动态功能加载程序集(.dll文件)和实例化类?它似乎与.Net 4.X有很大不同,并没有真正记录......

例如,假设我有一个类库(.Net Core),它只有一个类:

namespace MyClassLib.SampleClasses
{
    public class Sample
    {
        public string SayHello(string name)
        {
            return $"Hello {name}";
        }

        public DateTime SayDateTime()
        {
            return DateTime.Now;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,dll文件的名称将MyClassLib.dll位于其中/dlls/MyClassLib.dll.

现在我想在一个简单的控制台应用程序(.Net Core)中加载它并实例化Sample该类并使用C#的动态功能在以下控制台应用程序中调用方法:

namespace AssemblyLoadingDynamic
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // load the assembly and use the classes
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意: .Net Core我指的是RC2版本.

Rob*_*Rob 37

目前针对netcoreapp1.0您的运行实际上并不需要实现您自己的程度AssemblyLoader.有一个Default存在,工作得很好.(因此@ VSG24提到它Load什么都不做).

using System;
using System.Runtime.Loader;

namespace AssemblyLoadingDynamic
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var myAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"C:\MyDirectory\bin\Custom.Thing.dll");
            var myType = myAssembly.GetType("Custom.Thing.SampleClass");
            var myInstance = Activator.CreateInstance(myType);
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

project.json看起来像:

{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": true
  },

  "dependencies": {
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.1"
    },
    "System.Runtime.Loader": "4.0.0"
  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 不加载.NET Core程序集,它令人惊讶地只加载正常的.NET Framework程序集! (2认同)

Vah*_*iri 19

不确定这是否是最佳方式,但这是我想出的:

(仅在.Net Core RC2上测试 - Windows)

using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.Extensions.DependencyModel;

namespace AssemblyLoadingDynamic
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var asl = new AssemblyLoader();
            var asm = asl.LoadFromAssemblyPath(@"C:\Location\Of\" + "SampleClassLib.dll");

            var type = asm.GetType("MyClassLib.SampleClasses.Sample");
            dynamic obj = Activator.CreateInstance(type);
            Console.WriteLine(obj.SayHello("John Doe"));
        }

        public class AssemblyLoader : AssemblyLoadContext
        {
            // Not exactly sure about this
            protected override Assembly Load(AssemblyName assemblyName)
            {
                var deps = DependencyContext.Default;
                var res = deps.CompileLibraries.Where(d => d.Name.Contains(assemblyName.Name)).ToList();
                var assembly = Assembly.Load(new AssemblyName(res.First().Name));
                return assembly;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

MyClassLib.SampleClasses是名称空间,Sample是类名称类名.

执行时,它会尝试SampleClassLib.dll在内存中加载已编译的类库并让我的控制台应用程序访问MyClassLib.SampleClasses.Sample(看看问题)然后我的应用程序调用该方法SayHello()并将"John Doe"作为名称传递给它,因此程序打印:

"Hello John Doe"

快速说明: 该方法的覆盖Load并不重要,因此您可能只需更换其内容,throw new NotImplementedException()它不应影响我们关心的任何内容.


小智 10

谢谢你的分享.它也在使用Net Core 1.0.如果程序集在同一路径上需要另一个程序集,则可以使用下面的代码示例.

using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.Extensions.DependencyModel;
public class AssemblyLoader : AssemblyLoadContext
{
    private string folderPath;

    public AssemblyLoader(string folderPath)
    {
        this.folderPath = folderPath;
    }

    protected override Assembly Load(AssemblyName assemblyName)
    {
        var deps = DependencyContext.Default;
        var res = deps.CompileLibraries.Where(d => d.Name.Contains(assemblyName.Name)).ToList();
        if (res.Count > 0)
        {
            return Assembly.Load(new AssemblyName(res.First().Name));
        }
        else
        {
            var apiApplicationFileInfo = new FileInfo($"{folderPath}{Path.DirectorySeparatorChar}{assemblyName.Name}.dll");
            if (File.Exists(apiApplicationFileInfo.FullName))
            {
                var asl = new AssemblyLoader(apiApplicationFileInfo.DirectoryName);
                return asl.LoadFromAssemblyPath(apiApplicationFileInfo.FullName);
            }
        }
        return Assembly.Load(assemblyName);
    }
}
Run Code Online (Sandbox Code Playgroud)

请记住将以下依赖项添加到您的project.json文件中:

 "System.Runtime.Loader"
 "Microsoft.Extensions.DependencyModel"
Run Code Online (Sandbox Code Playgroud)


小智 6

使用.net core 1.1 / standard 1.6,我发现AssemblyLoader不可用,并且

AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath)
给我一个“无法加载文件或程序集xxx”错误。

终于,下面的解决方案对我有用-纯粹通过添加一个步骤来获取AssemblyName对象。希望它能帮助任何陷入困境的人:

var assemblyName = AssemblyLoadContext.GetAssemblyName(assemblyPath);
var assembly = Assembly.Load(assemblyName);