c# .NET 加载/卸载程序集,同时保持相同的会话

Posted

技术标签:

【中文标题】c# .NET 加载/卸载程序集,同时保持相同的会话【英文标题】:c# .NET Loading/Unloading assembly while keeping the same session 【发布时间】:2011-09-08 20:35:47 【问题描述】:

我对 c# 和 .NET 比较陌生,并试图创建一个动态加载程序集的 asp.net Web 应用程序。

最初,我使用Activator.CreateInstance 动态加载程序集,但它似乎锁定了程序集 DLL 文件。因为我经常对组件进行更改,所以这变得相当痛苦。我还需要与其他应用程序共享程序集,所以以后可能会成为问题。

似乎大多数人建议创建一个单独的 AppDomain 并将程序集加载到其中,然后在我完成后卸载 appdomain。但是,我的应用程序和程序集也取决于会话上下文,一旦我将其发送到应用程序域,所有会话都会丢失;程序集崩溃,因为它找不到会话上下文。

有什么方法可以将我的会话上下文传递给 AppDomain?或者有什么方法可以让我在不锁定 DLL 文件的情况下加载程序集?我已经尝试按照一些建议流式传输文件,但它仍然锁定 DLL。

编辑:我已按照 Davide 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);
        

    

【问题讨论】:

查看我的编辑,更多代码即将推出 :) 【参考方案1】:

要在同一个 AppDomain 中加载程序集,但加载后不锁定文件,只需按这种方式使用 LoadFrom 方法:

Assembly asm = Assembly.LoadFrom( “mydll.dll” );

这样你就完成了,会话将可用。

调试器会出现问题,因为符号 (*.pdb) 不会被加载,因此没有断点也没有可用的调试,为了能够调试,您也应该真正将 .pdb 文件加载到内存中,例如使用 FileStream。

编辑: 加载符号而不锁定文件的方法是使用 Assembly.Load 的适当重载,一个为程序集获取两个字节 [] 的方法,以及其他为程序集的符号文件(.pdb 文件):

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

事实上,您应该首先使用流加载字节,然后调用 Assembly.Load 并传递 byte[]

编辑 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;
   

【讨论】:

但正在卸载?我的意思是这就是我感兴趣的......怎么样,我们检查组件是否已经加载,如果没有,则加载它。并且无论何时,我们都可以轻松卸载。 Afaik 至少在 .net 2 之前,一旦添加到应用程序域,就无法卸载程序集。所以它只会在你卸载域时被卸载。 loadFile方法可以用File.ReadAllBytes()代替

以上是关于c# .NET 加载/卸载程序集,同时保持相同的会话的主要内容,如果未能解决你的问题,请参考以下文章

C#.Net 如何动态加载与卸载程序集(.dll或者.exe)

C# 动态加载/卸载程序集

将 c# 程序集动态加载和卸载到 appdomain

C# 通过 AppDomain 应用程序域实现程序集动态卸载或加载

C# 通过 AppDomain 应用程序域实现程序集动态卸载或加载

在C# .net中,多个客户同时写入数据会不会导致数据混乱?