實作目的:動态加載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是被目前程式占用的,無論如何都不能被替換。