找不到从我的Windows服务中删除/重新启动内存中的DLL状态的方法

时间:2011-11-21 21:50:14

标签: c# dll .net-4.0

我正在使用第三方DLL,它在首次使用时从文件中读取,但从不检查它是否有变化。我的想法是在我第一次调用后将DLL加载到AppDomain中并卸载DLL - 所以我每次调用(或多或少)都会消除DLL的状态。

AssemblyName name = AssemblyName.GetAssemblyName(@"C:\fake.dll");
AppDomain newDomain = AppDomain.CreateDomain("DomainName");
Assembly lib = newDomain.Load(name);

...
//Use the Assembly

AppDomain.Unload(newDomain);

这段代码可以每秒运行多次 - 效率低下,但是我现在只能使用这个DLL ...

问题是DLL的内存似乎甚至存在于我创建的其他AppDomain中 - 它仍然使用它在第一次读取文件时找到的相同值(并且它从不再次检查)。我可以让DLL再次读取文件的唯一方法是重启服务。

我不了解AppDomain还是应该从不同的角度对此进行攻击?

编辑:将DLL加载到我自己的域中的问题一直是使用MarshalByRefObject类的地址(谢谢!),但我不希望它是跨域的。我希望这个DLL在这个AppDomain中生存和死亡 - Unload方法是否足以压制这个DLL状态出现在另一个AppDomain中的任何希望?

3 个答案:

答案 0 :(得分:3)

如果您在“//使用程序集”代码中直接使用dll中的对象,那么您已将dll拉入当前AppDomain以及新AppDomain。这意味着你还没有真正实现目标。

您需要使用反射来使用加载到新AppDomain中的类和方法,而不必将dll拉入原始AppDomain。

答案 1 :(得分:3)

这一行:

Assembly lib = newDomain.Load(name);

导致程序集also be loaded in the current AppDomain,因为Assembly类标记为[Serializable],而不是MarshalByRefObject,因此它在AppDomain边界上被序列化:

您可以创建自己的MarshalByRefObject对象,以将调用代理到另一个程序集中。有关详细信息,请参阅MSDN中的示例。但基本的想法是这样的:

public class Worker : MarshalByRefObject, IWorker
{
    public void DoWork() 
    { 
        // Load the assembly here. This code will run in the AppDomain
    }
}

public interface IWorker
{
    void DoWork();
}


public class Program
{
    public static void Main()
    {
        AppDomain ad = AppDomain.CreateDomain("New domain");

        // This line creates a proxy to your worker.
        IWorker remoteWorker = (IWorker) ad.CreateInstanceAndUnwrap(
            Assembly.GetExecutingAssembly().FullName,
            "Worker");

        remoteWorker.DoWork();

        ad.Unload();
    }
}

您甚至可以更进一步,让您的Worker类实现一个接口并将其放在一个共享程序集中。

答案 2 :(得分:1)

不确定此处的//Use the Assembly部分发生了什么,但我怀疑您正在做的是无意中将程序集加载到调用 AppDomain中,例如你的主要应用程序的appDomain。

你想要做的是将所有使用该DLL的代码全部放入一个程序集中,理想情况下,在继承自MarshalByRefObject的类上使用一个非常简单的方法来启动它,如下所示:

public class StartErUp : MarshalByRefObject {
    public void RunThatOtherDll() { ... }
}

然后使用AppDomain.CreateInstanceAndUnwrap()加载该类。重要的是,您的类继承自MarshalByRefObject,因为它告诉CLR为它创建跨应用程序域代理,而不是尝试在AppDomains中序列化(复制)它。