如何加载位于.net核心控制台应用程序中的文件夹中的程序集
我正在.Net Core平台上制作一个控制台应用程序,并且想知道,如何使用C#动态function加载程序集(.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; } } }
所以dll文件的名称是MyClassLib.dll
,它位于/dlls/MyClassLib.dll
。
现在我想在一个简单的控制台应用程序(.Net Core)中加载它并实例化Sample
类并使用C#的动态function在以下控制台应用程序中调用方法:
namespace AssemblyLoadingDynamic { public class Program { public static void Main(string[] args) { // load the assembly and use the classes } } }
注意: .Net Core我指的是RC2版本。
目前针对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); } } }
与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" } } }
不确定这是否是最佳方式,但这就是我想出的:
( 仅在.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; } } } }
MyClassLib.SampleClasses
是名称空间, Sample
是类型名称。
执行时,它会尝试在内存中加载SampleClassLib.dll
编译的类库,并让我的控制台应用程序访问MyClassLib.SampleClasses.Sample
(看看问题),然后我的应用程序调用方法SayHello()
并传递“ John Doe“作为它的名字,因此程序打印:
"Hello John Doe"
快速注意:方法Load
的覆盖并不重要,所以你也可以用throw new NotImplementedException()
替换它的内容,它不应该影响我们关心的任何事情。
谢谢你的分享。 它也与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); } }
请记住将以下依赖项添加到project.json
文件中:
"System.Runtime.Loader" "Microsoft.Extensions.DependencyModel"
使用.net核心1.1 /标准1.6,我发现AssemblyLoader不可用,并且
AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath)
给了我一个“无法加载文件或程序集xxx”错误。
最后,下面的解决方案对我有用 – 纯粹是通过添加一个步骤来获取AssemblyName对象。 希望它可以帮助任何陷入困境的人:
var assemblyName = AssemblyLoadContext.GetAssemblyName(assemblyPath); var assembly = Assembly.Load(assemblyName);
@Rob,我可以让你的例子构建的唯一方法是将你的“myInstance”类型更改为动态 。
将类型保留为var确实允许代码构建,但是一旦我尝试使用运行时加载的程序集中的方法 ,我就会遇到编译器错误,例如myInstance不包含方法X. 我是新手,但将这种类型标记为动态,看起来似乎有道理。 如果在运行时加载类型,那么编译器如何validationmyInstance将包含方法X还是prop Y? 通过输入myInstance作为动态我相信你正在删除编译器检查,因此我可以得到构建和运行的例子。 不确定这是100%正确的方法(我不太了解你可能会建议使用动态有问题吗?)但这是我让它工作的唯一方法,而不必去创建我自己的麻烦AssemblyLoader(正确指出)。
所以…
using System; using System.Runtime.Loader; namespace TestApp { class Program { static void Main(string[] args) { var myAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"C:\Documents\Visual Studio 2017\Projects\Foo\Foo\bin\Debug\netcoreapp2.0\Foo.dll"); var myType = myAssembly.GetType("Foo.FooClass"); dynamic myInstance = Activator.CreateInstance(myType); myInstance.UpperName("test"); } } }
希望这可以帮助某人成为新手,我花了很多时间来确定为什么myInstance作为var没有方法X等Doh!