问题
Possible Duplicate:
how to delete the pluginassembly after AppDomain.Unload(domain)
I am struggling with an issue while loading an assembly up in a temporary AppDomain to read its GetUsedReferences property. Once I do that, I call AppDomain.Unload(tempDomain) and then I try to clean up my mess by deleting the files. That fails because the file is locked. I Unloaded the temporary domain though! Any thoughts or suggestions would be greately appreciated. Here is some of my code:
//I already have btyes for the .dll and the .pdb from the actual files
AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ApplicationBase = Environment.CurrentDirectory;
domainSetup.ShadowCopyFiles = "true";
domainSetup.CachePath = Environment.CurrentDirectory;
AppDomain tempAppDomain = AppDomain.CreateDomain("TempAppDomain", AppDomain.CurrentDomain.Evidence, domainSetup);
//Load up the temp assembly and do stuff
Assembly projectAssembly = tempAppDomain.Load(assemblyFileBuffer, symbolsFileBuffer);
//Then I'm trying to clean up
AppDomain.Unload(tempAppDomain);
tempAppDomain = null;
File.Delete(tempAssemblyFile); //I even try to force GC
File.Delete(tempSymbolsFile);
Anyway, the Deletes fail because the files are locked still. Shouldn't they be released because I Unloaded the temporary AppDomain?
回答1:
I know this is an old question, but there still is no accepted answer. I stumbled upon this question looking for the answer, hence I think that it might be useful to post the solution I found here.
Problem
tempAppDomain.Load(assemblyFileBuffer, symbolsFileBuffer); will load the assembly into tempAppDomain, but also into the app domain executing the code. You would have to unload that app domain as well to be able to delete the file. You probably do not want to do that though.
Solution
You will have to execute the code that loads the assembly from the app domain tempAppDomain. You could use the DoCallBack function on tempAppDomain to execute code in tempAppDomain. If you load the assembly there, then you should be able to delete the file after calling tempAppDomain.Unload().
Example
class Program
{
private static string assemblyPath = @"C:\Users\wesselm\Documents\Visual Studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\ClassLibrary1.dll";
static void Main(string[] args)
{
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
var appDomain = AppDomain.CreateDomain("myAppDomain", null, setup);
// Loads assembly in both application domains.
appDomain.Load(AssemblyName.GetAssemblyName(assemblyPath));
// Only loads assembly in one application domain.
appDomain.DoCallBack(() => AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(assemblyPath)));
AppDomain.Unload(appDomain);
File.Delete(assemblyPath);
}
}
Sources
http://msdn.microsoft.com/en-us/library/system.appdomain.docallback.aspx
http://msdn.microsoft.com/en-us/library/36az8x58.aspx
https://stackoverflow.com/a/2475177/210336
回答2:
See these pages:
http://connect.microsoft.com/VisualStudio/feedback/details/536783/vsip-assembly-file-handles-not-being-released-after-appdomain-unload
http://msdn.microsoft.com/it-it/library/43wc4hhs.aspx
Set a new AppDomain AppDomainSetup with LoaderOptimization.MultiDomainHost
E.g.
domainnew = AppDomain.CreateDomain(
newdomain_name,
null,
new AppDomainSetup
{
ApplicationName = newdomain_name,
ApplicationBase = assembly_directory,
ConfigurationFile = ConfigurationManager.OpenExeConfiguration(assemblylocation).FilePath,
LoaderOptimization = LoaderOptimization.MultiDomainHost,
//http://msdn.microsoft.com/it-it/library/43wc4hhs.aspx
ShadowCopyFiles = shadowcopy ? "true" : "false",
});
best regards
回答3:
If you are reading your file like this:
FileStream assemblyFileStream = new FileStream(tempAssemblyFile, FileMode.Open);
byte[] assemblyFileBuffer = new byte[assemblyFileStream.Length];
assemblyFileStream.Read(assemblyFileBuffer, 0, (int)assemblyFileStream.Length);
your problem should be fixed if you do this:
byte[] newAssemblyBuffer = new byte[assemblyFileBuffer.Length];
assemblyFileBuffer.CopyTo(newAssemblyBuffer, 0);
and change this:
Assembly projectAssembly = tempAppDomain.Load(newAssemblyFileBuffer, symbolsFileBuffer);
Alternatively this should work as well and allow you to skip the filestream:
byte[] assemblyFileBUffer = File.ReadAllBytes(tempAssemblyFile);
回答4:
You have to use a Wrapper to be able to unload successfully your AppDomain. Here you can find a good example of it - http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm
来源:https://stackoverflow.com/questions/1468151/appdomain-unload-doesnt-release-the-assembly-i-loaded-up-with-reflection