2011-09-08 47 views
4

我對c#和.NET頗爲陌生,並試圖創建一個動態加載程序集的asp.net web應用程序。c#.NET加載/卸載程序集,同時保持相同的會話

最初,我用Activator.CreateInstance動態加載程序集,但它似乎鎖定程序集DLL文件。因爲我經常改變大會,所以變得非常痛苦。我還需要與其他應用程序共享程序集,因此稍後可能會成爲問題。

看來,大多數人建議創建一個單獨的AppDomain並將程序集加載到它中,然後在完成後卸載AppDomain。但是,我的應用程序和程序集也依賴於會話上下文,一旦將它發送到應用程序域,所有會話都會丟失;程序集崩潰,因爲它找不到會話上下文。

有沒有辦法將我的會話上下文傳遞給AppDomain?或者有沒有什麼辦法可以加載程序集而不鎖定DLL文件?我嘗試按照某些建議的流式傳輸文件,但它仍然鎖定DLL。

編輯:我試過下面的代碼爲達維德Piras酒店建議,但DLL文件仍然鎖定

private static T CreateInstance<T>(string fileName, string typeName) 
    { 
     if (!File.Exists(fileName)) throw new FileNotFoundException(string.Format("Cannot find assembly '{0}'.", fileName)); 

     try 
     { 
      Assembly assembly = Assembly.LoadFrom(fileName); 
      if (assembly != null) 
      { 
       List<Type> assemblyTypes = assembly.GetTypes().ToList(); 

       Type assemblyType = 
        assemblyTypes.FirstOrDefault(asmType => typeof(T).IsAssignableFrom(asmType)); 
       T instance = (T) Activator.CreateInstance(assemblyType); 

       if (instance != null) return instance; 

      } 
      // Trouble if the above doesn't work! 
      throw new NullReferenceException(string.Format("Could not create type '{0}'.", typeName)); 
     } 
     catch (Exception exp1) 
     { 
      throw new Exception("Cannot create instance from " + fileName + ", with type " + typeName + ": " + exp1.Message + exp1.Source, exp1.InnerException); 
     } 

    } 
+0

看到我的編輯和更多的代碼就快到了:) –

回答

4

加載組件在同一個AppDomain中,但不鎖定文件後,負載只使用LoadFrom方法是這樣的:

Assembly asm = Assembly.LoadFrom(「mydll.dll」); 

這樣你完成和會話將可用。

調試器會出現問題,因爲符號(* .pdb)不會被加載,所以沒有斷點也沒有可用的調試,爲了能夠調試你應該真的在內存中加載.pdb文件,使用FileStream的例子。

編輯:你也可以用來加載符號而不鎖定文件的方式是使用Assembly.Load的正確重載,一個用於裝配,另一個用於裝配'符號文件(.pdb文件):

public static Assembly Load(
    byte[] rawAssembly, 
    byte[] rawSymbolStore 
) 

實際上應先與流加載字節然後調用Assembly.Load並傳遞字節[]

編輯2:

這裏是一個完整的示例,用於加載當前域中的程序集,包括符號文件並且不具有文件鎖定。

是在網上找到了一個比較完整的例子,它反映了你需要包括AppDomain.AssemblyResolve的處理一切......

public static void Main() { 
     AppDomain currentDomain = AppDomain.CurrentDomain; 

     currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolver); 
    } 

    static void InstantiateMyType(AppDomain domain) { 
     try { 
    // You must supply a valid fully qualified assembly name here. 
     domain.CreateInstance("Assembly text name, Version, Culture, PublicKeyToken", "MyType"); 
     } catch (Exception e) { 
     Console.WriteLine(e.Message); 
     } 
    } 

    // Loads the content of a file to a byte array. 
    static byte[] loadFile(string filename) { 
     FileStream fs = new FileStream(filename, FileMode.Open); 
     byte[] buffer = new byte[(int) fs.Length]; 
     fs.Read(buffer, 0, buffer.Length); 
     fs.Close(); 

     return buffer; 
    } 

    static Assembly MyResolver(object sender, ResolveEventArgs args) { 
     AppDomain domain = (AppDomain) sender; 

     // Once the files are generated, this call is 
     // actually no longer necessary. 
     EmitAssembly(domain); 

     byte[] rawAssembly = loadFile("temp.dll"); 
     byte[] rawSymbolStore = loadFile("temp.pdb"); 
     Assembly assembly = domain.Load(rawAssembly, rawSymbolStore); 

     return assembly; 
    } 
+0

但卸載?我的意思是說,我對此感興趣....這個怎麼樣,我們檢查assmebly是否已經加載,如果沒有,然後加載它。只要我們想要,我們可以輕鬆卸載。 – KMX

+0

Afaik至少在.net 2之前,沒有辦法一旦添加到應用程序域就卸載程序集。所以它只會在你卸載域時卸載。 –

+1

loadFile方法可以被File.ReadAllBytes()替換 – staafl