这个示例是一个需要在运行时加载程序集并使用提供的程序集的应用程序。
所加载的程序集引用了另一个项目,而该项目反过来使用了NuGet软件包。
代码
- 项目Host是控制台应用程序,没有项目引用和软件包引用。它包含文件Program.cs:
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
的项目引用,并包含文件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,因为无法找到Subfeature。
我通过以下方式解决此问题:(1)将Assembly.LoadFile(featurePath)
替换为Assembly.LoadFrom(featurePath)
,以便在同一目录中也可以加载其他所需的DLL。 (2)通过添加到Feature.csproj中的代码<PropertyGroup><CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies></PropertyGroup>
,使只在发布期间复制到相同目录的软件包DLL也在生成期间复制。第二个已解决的问题是当应用程序加载DLL时会锁定它们。这会阻止我在应用程序仍在运行时部署更新版本的DLL。当应用程序是IIS托管应用程序的一部分时,发布新版本变得棘手。.NET Core不再支持加载DLL的影子副本。
我通过以下方式解决此问题:(1)将Assembly.LoadFile(featurePath)
替换为Assembly.Load(System.IO.File.ReadAllBytes(featurePath))
,以便在加载之前从读取的字节中加载所需的DLL。 (2)使用文件监视器在发生目录中DLL文件更改时重新加载应用程序。
最终问题
第一个问题的解决方案与第二个问题的解决方案不兼容。 Assembly.LoadFrom
修复了我的第一个问题。 Assembly.Load
修复我的第二个问题。但我还没有找到一个Assembly.LoadFile
的替代方案,可以同时解决这两个问题。