views:

1751

answers:

7

hello,

i have a weird problem. i would like to delete an assembly(plugin.dll on harddisk) which is already loaded, but the assembly is locked by the operating system (vista), even if i have unloaded it.

f.e.

AppDomainSetup setup = new AppDomainSetup();
setup.ShadowCopyFiles = "true";
AppDomain appDomain = AppDomain.CreateDomain(assemblyName + "_AppDomain", AppDomain.CurrentDomain.Evidence, setup);
IPlugin plugin = (IPlugin)appDomain.CreateInstanceFromAndUnwrap(assemblyName,                        "Plugin.MyPlugins");

I also need the assemblyinfos, because I don't know which classes in the pluginassembly implements the IPlugin Interface. It should be possible to have more than one Plugin in one Pluginassembly.

Assembly assembly = appDomain.Load(assemblyName);
if (assembly != null) {
   Type[] assemblyTypes = assembly.GetTypes();
   foreach (Type assemblyTyp in assemblyTypes) {
      if (typeof(IPlugin).IsAssignableFrom(assemblyTyp)) {
         IPlugin plugin = (IPlugin)Activator.CreateInstance(assemblyTyp);
         plugin.AssemblyName = assemblyNameWithEx;
         plugin.Host = this;
      }
   }
}
AppDomain.Unload(appDomain);

How is it possible to get the assemblyinfos from the appDomain without locking the assembly?

best regards

+2  A: 

What we do, is to have one folder that is watched for assemblies. When an assembly is added, the application copies it to a temp directory gives it a unique file name and loads it from there.

When the application is first loaded, it tries to clear out the temp directory.

I don't think that directly answers your question, but it probably solves your problem.

Stever B
+1 for shadow copies
Nader Shirazie
A: 

hello Steve B,

yes i think it should work in this case too but i can't belive that that is the right way. it looks like a workaround.

the object AppDomainSetup has the property ShadowCopyFiles. this should be the solution, but it doesn't work in this case.

Tch
+2  A: 

If you load the assembly as a stream, it should work.

byte[] fileContent;
string path = "../../../test/bin/Debug/test.dll"; //Path to plugin assembly
using (FileStream dll = File.OpenRead(path))
{
   fileContent = new byte[dll.Length];
   dll.Read(fileContent, 0, (int)dll.Length);
}
Assembly assembly = appDomain.Load(fileContent);
File.Delete(path);
Øyvind Skaar
it should, but it doesnt. :(UnauthorizedAccessException at File.Delete(path);
Ase
Can you delete the file if you don't load the assembly first?
Øyvind Skaar
+8  A: 

Hello,

I think i've the answer! the answer from Øyvind Skaar will not work, if you would like to delete the loaded assembly.

instead of

using (FileStream dll = File.OpenRead(path))
{
   fileContent = new byte[dll.Length];
   dll.Read(fileContent, 0, (int)dll.Length);
}
Assembly assembly = appDomain.Load(fileContent);

you have to use

byte[] b = File.ReadAllBytes(assemblyName);
assembly = Assembly.Load(b);

best regards

Tch
It worked fine when I tried it, but yours is shorter anyway;)
Øyvind Skaar
A: 

Unfortunately the "solution" seems to be incompatible when adding symbols/debugging. The following code demonstrates the problem:

byte[] bytesDLL = File.ReadAllBytes(pathDLL);
byte[] bytesPDB = File.ReadAllBytes(pathPDB);
Assembly assembly = tempDomain.Load(bytesDLL, bytesPDB);
AppDomain.Unload(tempDomain);
File.Delete(pathDLL); // <-- UnauthorizedAccessException here

File.Delete works just before the tempDomain.Load call, but not after. Strangely, Vista still lets me manually rename/delete the DLL at any point by hand, so the file lock if that's what's going on is behaving quite strangely and File.Delete behaves different than manual delete. I'm at a loss here, and all my experimentation has yielded a wide variety of incomplete solutions... it seems to be "Pick any 2: dynamically load symbols with assembly, have an unloadable domain, avoid file locks." I even tried making temp files for the DLL and PDB we read in, but it chooses to lock the original DLL despite our precautions.

A: 

Further, if one loads this way to the Current domain, then a file lock is not created. Why would a file lock be created for one domain but not the other? I've tried using ShadowCopyFiles etc to no avail.

byte[] bytesDLL = File.ReadAllBytes(pathDLL);
byte[] bytesPDB = File.ReadAllBytes(pathPDB);
Assembly assembly = AppDomain.CurrentDomain.Load(bytesDLL, bytesPDB);
// Don't even have to try to unload the domain
File.Delete(pathDLL); // <-- No exceptions this time

Too bad the whole point of these attempts is to update a debuggable DLL with a new one without restarting the whole service... Thus they need to be unloadable (in another domain).

A: 

I know this thread is quite dead, but I am currently working on this and I just got the answer (at 1h30 AM...)

AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
AppDomain app = AppDomain.CreateDomain("YaCsi", null, setup);
app.DoCallBack(LoaderCallback);
AppDomain.Unload(app);
File.Delete("__YaCsi_Test01.dll");

static void LoaderCallback()
{
    byte[] raw = File.ReadAllBytes("__YaCsi_Test01.dll");
    Assembly yacsi = Assembly.Load(raw);
    ((IScript)yacsi.CreateInstance("Script")).Go();
}

And it actually don't throw any exceptions!!! Hope someone will read this and that it will answer there question!

KKitsune