Jam*_*ock 4 .net c# reflection initialization core
我目前正在尝试开发一种在外部项目中使用反射以编程方式运行测试类的方法。这是应该显示我的问题的简化代码块。
string pathToDLL = @"C:\Path\To\Test\Project\UnitTests.dll";
IEnumerable<Type> testClasses = assembly.GetExportedTypes();
Type testClass = testClasses.First();
object testClassInstance = assembly.CreateInstance(testClass.FullName);
Run Code Online (Sandbox Code Playgroud)
此代码引发以下异常:
'assembly.CreateInstance(testClass.FullName)' threw an exception of type 'System.Reflection.TargetInvocationException'
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146232828
HelpLink: null
InnerException: {System.IO.FileNotFoundException: Could not load file or assembly 'Project.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'Project.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
at Project.UnitTests.TestClass..ctor()}
Message: "Exception has been thrown by the target of an invocation."
Source: "System.Private.CoreLib"
StackTrace: " at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)\r\n at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)\r\n at System.Activator.CreateInstance(Type type, Boolean nonPublic)\r\n at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)\r\n at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)\r\n at System.Reflection.Assembly.CreateInstance(String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)\r\n at System.Reflection.Assembly.CreateInstance(String typeName)"
Run Code Online (Sandbox Code Playgroud)
在堆栈跟踪中指出“无法加载文件或程序集'Project.Core ...'”。
该项目是目标DLL直接引用的项目(它已测试的项目)。有谁知道为什么这将无法自动提取这些DLL?
我研究了解决此问题的方法:
1)这可能是dll的编译方式-可以更改此方式,因为我控制此方式-当前是dotnet build */*/project.json
在解决方案级别运行。这样可以成功编译所有内容,并且所有相关的DLL似乎都已填充到bin文件夹中。我还调查了是否更改为dotnet publish
或dotnet build */*/project.json --configuration Release
似乎都没有帮助。
2)我也研究过使用不同的编译方法,就像Activator.CreateInstance
没有骰子一样。
3)我似乎看不到将多个DLL加载到同一个Assembly类中以便可以控制引用的方法。由于AppDomains已从.Net Core中删除,因此这看起来不太可能,尽管我可能会弄错/在错误的地方查看。
如果我正在做的事情似乎不可能实现,那么有人知道这种功能是否可以使用其他方法来实现吗?即罗斯林?
我只是以为我将使用设法找到的解决方案来更新此问题,以防其他人遇到与我相同的问题。尽管我要感谢@EmrahSüngü为我指出正确的方向。
Emrah提请我注意以下事实:我需要导入要加载的DLL的依赖项,以调用存储在其中的类。一种方法是扩展app.config以便导入那些依赖项-但是我想在运行时执行此操作(对于在启动程序之前我不知道要运行的项目),因此我需要寻找另一种解决方案。
如果您不使用.NET Core,这将相对简单,因为AppDomains可用于加载所有依赖项并执行代码。但是,由于已将其从.NET Core中删除,因此我需要找到另一种兼容的解决方案。
我开玩笑的想法是运行一个单独的进程(或Powershell),并更改工作目录,以便该进程在存储所需的所有依赖项的目录中运行。但是,我找不到一种可以使我对运行方法的结果做出反应的方法。
后来我研究了如何操作AssemblyLoadContext类,但是(在撰写本文时)几乎没有关于此类的文档。我确实找到了这个答案,可以极大地帮助您…… /sf/answers/2652731371/
为了使其正常工作,我确实必须进行一些更改,而不是每次都创建一个新的AssemblyLoader(这将导致在尝试调用Assembly中的方法时引发异常),而是每次都重用AssemblyLoader(已删除)这个问题)。
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))
{
return this.LoadFromAssemblyPath(apiApplicationFileInfo.FullName);
}
}
return Assembly.Load(assemblyName);
}
}
Run Code Online (Sandbox Code Playgroud)
可以用来加载这样的程序集:
string directory = @"C:\Path\To\Project\bin\Debug\netcoreapp1.0\publish\";
string pathToDLL = @"C:\Path\To\Project\bin\Debug\netcoreapp1.0\publish\project.dll";
AssemblyLoader al = new AssemblyLoader(directory);
Assembly assembly = al.LoadFromAssemblyPath(pathToDLL);
Run Code Online (Sandbox Code Playgroud)