AppDomain加載與釋放dll

原文:AppDomain加載與釋放dll

我與很多人都在找這問題的答案。還好,我很幸運,沒有進入很多人都進入的死衚衕而漫長的討論中。因爲我找到了這篇文章

黃天不負有心人,終於全身而退,哈哈

文章說得很明白,我去掉其他設置,只使用以下代碼時
AppDomain.CurrentDomain.SetShadowCopyFiles();

在文章發佈的幾天後,我在微軟的MSDN上發現了這文章。似乎闡述得更爲系統
http://www.microsoft.com/china/msdn/library/langtool/vcsharp/csharp05162002.mspx

在加載dll時有一個奇怪現象,以下代碼會報錯

object objBuild = pJobDomain.CreateInstanceAndUnwrap(strDllFilePath,strClassName);
說沒找到dll或依賴的項,看報錯提示的路徑卻是實實在在有這個dll的。

於是使用以下代碼
System.Reflection.Assembly asm = pJobDomain.Load(str[1]);
                
object objBuild = asm.CreateInstance(str[0]);
                
                
if(objBuild==null)
                    Mag.Windows.Interface.Log.AddErr(
"buildWorker","創建對象失敗");
                
else
                    iDo 
= (Mag.Windows.Interface.IDo)objBuild;
Unload後是可以重新編譯dll的。

上面的代碼還有一個問題,就是我UnLoad程序域後,重新編譯dll,也看到dll成功更新了。應用程序域檢測到配置被修改後,重新使用上面的代碼載入dll,但程序結果並不是我期待的!!程序行爲還是上面版本dll的。估計是使用了緩存的dll。嘗試換用以下代碼

System.Runtime.Remoting.ObjectHandle objHandle = pJobDomain.CreateInstanceFrom(strDllFilePath,strClassName);
object objBuild = objHandle.Unwrap();
問題解決。汗,我以爲上面的代碼可以用CreateInstanceAndUnwrap來代替。

設置SetShadowCopyFiles後,程序運行期間,程序文件是可以隨意更新的,不過不會應用這些變化,除非重新啓動程序。不過在我的項目中這個不是問題。因爲主程序是極小去更新的,但相關的dll就需要不斷的修正,並重新加載到程序域中。所以上文的提示已很足夠了。以下是我的代碼
//創建 AppDomainSetup 對象
            AppDomainSetup setup = new AppDomainSetup();            
            setup.ApplicationBase 
= AppDomain.CurrentDomain.BaseDirectory;
            setup.ShadowCopyDirectories 
= "true";
            
//主程序很少更新,可以不設置,但考慮還要有可能,
            
//設置後,更新完文件直接通知網管重啓就可以了。不需要先關再上傳文件,再通知開啓這麼麻煩
            AppDomain.CurrentDomain.SetShadowCopyFiles();
            
            
//新域的 config 和本域公用一個。不使用默認的配置文件。
        
//    setup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
            
//安全級別相同
            System.Security.Policy.Evidence adevidence = AppDomain.CurrentDomain.Evidence;
            
//創建新的輔程序域
            this.domainJob = AppDomain.CreateDomain("Mag.Web.MainSrv.Jobs",adevidence,setup);
            
//輔程序域,dll都加載在這,更新頻繁,這是一定要設置的。
            this.domainJob.SetShadowCopyFiles();

加載dll
private Mag.Windows.Interface.IDo buildWorker(System.AppDomain pJobDomain,string config)
        
{
            
string [] str = config.Split(',');
            
string strDllFilePath = string.Format("{0}{1}.dll",AppDomain.CurrentDomain.BaseDirectory,str[1]);
            
string strClassName = str[0];

            
if(!System.IO.File.Exists(strDllFilePath))
            
{
                
//throw new Exception("指定的文件不存在");
                Mag.Windows.Interface.Log.AddErr("buildWorker","指定的文件不存在" + strDllFilePath);
                
return null;
            }


            Mag.Windows.Interface.IDo iDo
=null;
            
try
            
{            
                
//使用當前程序域加載
//                System.Runtime.Remoting.ObjectHandle objHandle = Activator.CreateComInstanceFrom(strDllFilePath,strClassName);
//                object objBuild = objHandle.Unwrap();//建立對像

                System.Runtime.Remoting.ObjectHandle objHandle 
= pJobDomain.CreateInstanceFrom(strDllFilePath,strClassName);
                
object objBuild = objHandle.Unwrap();

                
//會引起找到不dll或依賴的項的錯誤。
//                object objBuild = pJobDomain.CreateInstanceAndUnwrap(strDllFilePath,strClassName);

                
//會首先使用緩存中的dll
//                System.Reflection.Assembly asm = pJobDomain.Load(str[1]);
//                object objBuild = asm.CreateInstance(str[0]);
                
                
if(objBuild==null)
                    Mag.Windows.Interface.Log.AddErr(
"buildWorker","創建對象失敗");
                
else
                    iDo 
= (Mag.Windows.Interface.IDo)objBuild;                    
            }

            
catch(Exception ee)
            
{
            
//    throw ee;
                Mag.Windows.Interface.Log.AddErr("buildWorker",ee);
            }


            
return iDo;
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章