天天看點

C#.Net 如何動态加載與解除安裝程式集(.dll或者.exe)2----通過應用程式域AppDomain加載和解除安裝程式集之後,如何再傳回原來的主程式域

實作目的:動态加載dll,執行完畢之後可以随時解除安裝掉,并可以替換這些dll,以在運作中更新dll中的類。

其實就是通過應用程式域AppDomain加載和解除安裝程式集。

在這方面微軟有篇文章​​​http://www.microsoft.com/china/msdn/archives/library/dncscol/html/csharp05162002.asp​​​介紹的比較詳細;

具體實作起來倒也不難,我的問題是:可以加載了,可以解除安裝了,但是不同域的執行個體是通過代理來實作調用的(這是可以動态加載/解除安裝的基礎),從主域調用子域中的沒問題,反之如何讓子域中的類來通路主域中的執行個體呢?

先說動态加載和解除安裝,前面兩篇文章已經有很精彩的論述了,隻說幾個要點

1:主域中建立子域,加載的dll來自别的檔案夾

   AppDomain svcDomain = null;
    try
    {
     AppDomainSetup setup = new AppDomainSetup();
     setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
     setup.PrivateBinPath = setup.ApplicationBase;
      setup.ApplicationName = asmName.FullName;
      setup.ShadowCopyDirectories = ​​​setup.ApplicationBase+@"dlls​​";    //dll不是來自bin目錄下(很奇怪,為什麼有很多人認為dll必須就在bin目錄下)      setup.ShadowCopyFiles = "true";
      svcDomain = AppDomain.CreateDomain(asmName.FullName, null, setup);
    }
    catch (Exception ex)
    {
         Log.Write("test","can not CreateDomain")
           return;
    }    // Get remote service handler
    ServiceProxy svc = null;
    try
    { //關鍵點
       svc = (ServiceProxy)   svcDomain.CreateInstanceFromAndUnwrap(
      svcDomain.BaseDirectory + "\\Services.dll",    "MaServices.ServiceProxy");
    }
    catch (Exception ex)
    {
      AppDomain.Unload(svcDomain);
     Log.Write("test", "can not create proxy")
          return;
    }

2:proxy的定義,一定要繼承自MarshalByRefObject,傳遞的資料對象一定要可以序列化
    public class ServiceProxy: MarshalByRefObject,IDisposable

3:proxy中加載dll

public bool LoadService(string assemblyName)
  {
   Assembly assembly = null;
   try
   {     assembly = Assembly.LoadFrom(assemblyName);
         IService sev = (IService)assembly.CreateInstance(typename, true);

         this.services[assemblyName]=sev ;
   }
 4:proxy中調用具體的類:注意,具體調用一定不能再主域中
public IContext RunService(string serviceName,IContext ctx)
  {
       object o = this.service[serviceName];
        ((IService)o).RunService(ctx);
        return ctx;
   }


     最後,主域中直接調用既可

   proxy.RunService(xx,xx)      

就這些。這樣程式就可以随時加載一個dll(位置任意),反射得到類,運作,這個dll随時可以被替換

幾個關鍵點:

代理不要傳回被反射的執行個體,傳遞的資料要可以序列化,注意設定ShadowCopyDirectories。

現在言歸正傳,說說問題

假設主域M,子域C1,C2。通過代理之後,M可以調用C1和C2中的執行個體,反過來,如何讓C1調用M中的執行個體呢?或者C1調用C2中的執行個體?

tcp通訊是一種方法,但是系統消耗太大,頻繁使用那就糟透了。

誰有高招?

還有一個問題:看上述文章時發現,他們的prxoy在傳回時都是傳回的要代理的類的執行個體,對于這一點我比較懷疑。如果dll不在一個目錄下,那麼本地将無法接受這個執行個體。是以要求本地必須有這麼一個dll存在,才能接受這個傳回結果,然後根據本地的dll中定義的類的結構來反序列化。這樣一來,不論如何使用proxy,其實在DefaultAppDomain裡面都引用了具體的類和dll,是以導緻dll是被目前程式占用的,無論如何都不能被替換。