简体   繁体   中英

c# .NET Loading/Unloading assembly while keeping the same session

I am rather new to c# and .NET, and trying to create an asp.net web application that dynamically loads assembly.

Initially, I've used Activator.CreateInstance to dynamically load assemblies, but it seems to lock the assembly DLL file. Because I am making frequent changes to the assembly it's become quite a pain. I also need to share the assembly with other apps, so it may become a problem later.

It appears that most people recommend creating a separate AppDomain and loading the assembly into it, then unload the appdomain after I'm done. However, my app and the assembly also depends on session context and all the session is lost once I send it over to the app domain; the assembly crashes because it cannot find session context.

Is there any way to pass on my session context to the AppDomain? Or is there any way for me to load the assembly without locking the DLL file? I've tried streaming the file as some suggested, but it still locks the DLL.

Edit: I've tried the following code as Davide Piras suggested, but the DLL file is still locked

    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);
        }

    }

to load the assemblies in the same AppDomain but not lock the files after load just use the LoadFrom method in this way:

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

in this way you are done and Session will be available.

there will be an issue with the debugger because symbols (*.pdb) will not get loaded so no breakpoint and no debugging available, to be able to debug you should really load the .pdb files in memory as well, for example using FileStream.

Edit: The way you can do to also load symbols and not lock the files is to use proper overload of Assembly.Load, the one that gets two byte[] one for the assembly and the other for the assembly' symbols file (.pdb file):

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

in fact you should first load the bytes with a stream then call Assembly.Load and pass the byte[]

EDIT 2:

here a full example to load the assemblies in your current domain, including the symbol file and not having the files locks.

it's a full example found online, it reflect everything you need including the handling of 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;
   }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM