我在一个最小的,可复制的示例中遇到了两个问题,该示例具有三个针对.NET Core 3.1的项目。
该示例适用于需要在运行时加载程序集并使用提供的程序集的应用程序。
已加载的程序集引用了另一个项目,该项目又使用了NuGet包。
class Program
{
static void Main(string[] args)
{
var featurePath = System.IO.Path.GetFullPath(@"..\..\..\..\Feature\bin\Debug\netcoreapp3.1\Feature.dll");
var featureAssembly = System.Reflection.Assembly.LoadFile(featurePath);
var featureType = featureAssembly.GetType("SomeFeature");
var featureInstance = System.Activator.CreateInstance(featureType);
featureType.InvokeMember("PrintText",
System.Reflection.BindingFlags.InvokeMethod, null, featureInstance, new object[0]);
}
}
..\Subfeature\Subfeature.csproj
的ProjectReference并包含文件SomeFeature.cs:public class SomeFeature
{
public void PrintText()
{
System.Console.WriteLine(new SomeSubfeature().GetText());
}
}
Newtonsoft.Json
的PackageReference并包含文件SomeSubfeature.cs的类库:public class SomeSubfeature
{
public string GetText()
{
return Newtonsoft.Json.JsonConvert.SerializeObject("Some Text");
}
}
第一个解决的问题是因为使用的程序集引用了另一个项目和/或使用了程序包。 Assembly.LoadFrom
仅加载请求的程序集。引用的项目的程序集和程序包未加载。这导致FileNotFoundException,因为找不到子功能。我可以通过(1)将Assembly.LoadFile(featurePath)
替换为Assembly.LoadFrom(featurePath)
来解决此问题,以便也可以加载同一目录中的其他所需DLL。并且(2)通过将仅在发布过程中复制到同一目录的软件包DLL也添加到Feature.csproj <PropertyGroup><CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies></PropertyGroup>
中,从而在构建过程中也将其复制。
第二个解决的问题是,应用程序在加载DLL时将其锁定。这样可以防止我在应用程序仍在运行时部署DLL的较新版本。这就使得发布较新的版本变得很麻烦,例如,该应用程序是IIS托管应用程序的一部分。 .NET Core不再支持加载DLL的卷影副本。我可以通过(1)将Assembly.LoadFile(featurePath)
替换为Assembly.Load(System.IO.File.ReadAllBytes(featurePath))
来解决此问题,以便从加载之前读取的字节中加载所需的DLL。并且(2)如果DLL文件在其目录中发生问题,请使用FileWatcher重新加载应用程序。
第一个问题的解决方案与第二个问题的解决方案不兼容。 Assembly.LoadFrom
解决了我的第一个问题。 Assembly.Load
解决了我的第二个问题。但是我还没有找到Assembly.LoadFile
的替代品同时解决两个问题。
我在一个最小的,可复制的示例中遇到了两个问题,该示例具有三个针对.NET Core 3.1的项目。该示例适用于需要在运行时加载程序集并使用...
这是我的解决方法。代替使用Activator
创建新实例,请尝试使用AppDomain.CurrentDomain
的CreateInstanceAndUnwrap
方法。并像读取所有字节一样添加AssemblyResolve
事件句柄和句柄程序集加载。
const string location = @"..\..\..\..\Dependency\bin\Debug\netcoreapp3.1\";
static void Main(string[] args)
{
var domain = AppDomain.CurrentDomain;
domain.AssemblyResolve += Domain_AssemblyResolve;
object obj = domain.CreateInstanceAndUnwrap(
"Dependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"Dependency.DependentClass");
Console.WriteLine(obj.ToString());
}
private static Assembly Domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var dll = $"{args.Name.Split(",")[0]}.dll";
var path = Path.Combine(location, dll);
var asm = Assembly.Load(File.ReadAllBytes(path));
return asm;
}