AppDomain.Unload doesn't release the assembly I loaded up with Reflection [duplicate]

狂风中的少年 提交于 2019-12-03 11:04:22

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!