我正在开发一种解决方案,其中服务在后台持续运行,并且可以在运行时添加/删除插件DLL。该服务将在需要时加载必要的插件,运行它们并卸载它们。这是卸载部分是目前给我带来的麻烦:一旦某个类第一次成功加载(变量tc),它就永远不会重新加载,即使DLL文件已更新。我认为我没有正确地卸载课程/程序集/ appdomain,所以我很欣赏一些最后一英里的建议。
编辑:我更新了帖子以反映最近的代码更改并解释了何时卸载无效:问题没有出现在Linux Ubuntu上(通过Mono),但它出现在Windows 2008 Server上,当我我试图用更新的文件版本替换某个插件DLL。似乎.NET框架已缓存到程序集的某个地方,并且在不重新加载的情况下很高兴。 DLL文件名不会改变,但文件版本属性不同,所以我希望运行时将先前加载的DLL版本与正在加载的版本进行比较,如果版本号不同,则使用较新版本。如果我稍微更改代码以从具有不同名称的DLL文件加载程序集,则重新加载按预期进行。
using System;
using System.Reflection;
namespace TestMonoConsole
{
public interface ITestClass
{
void Talk();
}
class MainClass
{
public static void Main (string[] args)
{
string pluginPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string classAssembly = "TestClass";
string className = "TestMonoConsole.TestClass";
string command = "";
do
{
try
{
System.AppDomain domain = System.AppDomain.CreateDomain(classAssembly);
string pluginAssemblyFile = pluginPath + "/" + classAssembly + ".dll";
System.IO.StreamReader reader = new System.IO.StreamReader(pluginAssemblyFile, System.Text.Encoding.GetEncoding(1252), false);
byte[] b = new byte[reader.BaseStream.Length];
reader.BaseStream.Read(b, 0, System.Convert.ToInt32(reader.BaseStream.Length));
domain.Load(b);
reader.Close();
ITestClass tc = (ITestClass) Activator.CreateInstance(domain, classAssembly, className).Unwrap();
tc.Talk();
System.AppDomain.Unload(domain);
}
catch (System.IO.FileNotFoundException e)
{
Console.WriteLine (String.Format("Error loading plugin: assembly {0} not found", classAssembly));
}
command = Console.ReadLine();
} while (command == "");
}
}
}
答案 0 :(得分:2)
您正在直接在主机域中创建类型。每个http://msdn.microsoft.com/en-us/library/ms224132(v=vs.90).aspx
使用Activator.CreateInstance时需要指定域答案 1 :(得分:0)
此外,您可以使用托管加载项框架(MAF,System.AddIn)为您执行此操作,而不是重新发明此机制。查看here快速入门。
答案 2 :(得分:0)
无法从AppDomain卸载类型和程序集。 因此,您需要创建新的AppDomain,加载类型,执行所有操作,然后卸载该域。
答案 3 :(得分:0)
您正在自己的AppDomain中实例化插件类型。在多次实现插件框架之后,我强烈建议使用MEF(托管扩展性框架)作为解决方案,因为它处理代码隔离的这些常见问题。如果你不想要MEF,一种方法是实现一个“远程控制”类,它将充当app域之间的通信器。您可以在远程类上调用一个方法,该方法将在辅助应用程序域中实例化并运行代码。
答案 4 :(得分:0)
根据this MSDN article,CLR默认不使用卷影复制。您可以尝试按照以下步骤启用它:
它适用于Mono但不适用于CLR(Windows)这一事实可能意味着CLI未指定是否应默认启用卷影复制。