7 Stimmen

AppDomain.Unload gibt die Assembly, die ich mit Reflection geladen habe, nicht frei

Mögliches Duplikat:
Wie wird die Plugin-Assembly nach AppDomain.Unload(domain) gelöscht?

Ich kämpfe mit einem Problem beim Laden einer Assembly in einer temporären AppDomain, um deren GetUsedReferences-Eigenschaft zu lesen. Sobald ich das getan habe, rufe ich AppDomain.Unload(tempDomain) auf und versuche dann, mein Chaos zu beseitigen, indem ich die Dateien lösche. Das schlägt fehl, weil die Datei gesperrt ist. Ich habe die temporäre Domäne jedoch entladen! Ich bin für jede Idee oder jeden Vorschlag dankbar. Hier ist ein Teil meines Codes:

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

Die Löschvorgänge schlagen jedoch fehl, da die Dateien noch gesperrt sind. Sollten sie nicht freigegeben werden, weil ich die temporäre AppDomain entladen habe?

13voto

Matthijs Wessels Punkte 6351

Ich weiß, dass dies eine alte Frage ist, aber es gibt immer noch keine akzeptierte Antwort. Ich bin auf diese Frage gestoßen, als ich nach der Antwort suchte. Daher denke ich, dass es nützlich sein könnte, die Lösung, die ich gefunden habe, hier zu posten.

Problem

tempAppDomain.Load(assemblyFileBuffer, symbolsFileBuffer); lädt die Baugruppe in tempAppDomain sondern auch in die Anwendungsdomäne, die den Code ausführt. Um die Datei löschen zu können, müssten Sie auch diese Anwendungsdomäne entladen. Das wollen Sie aber wahrscheinlich nicht tun.

Solución

Sie müssen den Code ausführen, der die Baugruppe aus der Anwendungsdomäne lädt tempAppDomain . Sie können die DoCallBack Funktion bei tempAppDomain zur Ausführung von Code in tempAppDomain . Wenn Sie die Baugruppe dort laden, sollten Sie die Datei nach dem Aufruf von tempAppDomain.Unload() .

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

Quellen

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

7voto

kiii Punkte 431

Siehe diese Seiten:

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

Setzen einer neuen AppDomain AppDomainSetup mit LoaderOptimization.MultiDomainHost

z.B.

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

mit freundlichen Grüßen

4voto

David Silva Smith Punkte 10859

Wenn Sie Ihre Datei auf diese Weise lesen:

FileStream assemblyFileStream = new FileStream(tempAssemblyFile, FileMode.Open);

byte[] assemblyFileBuffer = new byte[assemblyFileStream.Length];
assemblyFileStream.Read(assemblyFileBuffer, 0, (int)assemblyFileStream.Length);

Wenn Sie dies tun, sollte Ihr Problem behoben sein:

byte[] newAssemblyBuffer = new byte[assemblyFileBuffer.Length];
assemblyFileBuffer.CopyTo(newAssemblyBuffer, 0);

und ändern Sie dies:

Assembly projectAssembly = tempAppDomain.Load(newAssemblyFileBuffer, symbolsFileBuffer);

Alternativ sollte dies auch funktionieren und Ihnen ermöglichen, den Dateistrom zu überspringen:

byte[] assemblyFileBUffer = File.ReadAllBytes(tempAssemblyFile);

3voto

GenZiy Punkte 1387

Sie müssen einen Wrapper verwenden, um Ihre AppDomain erfolgreich entladen zu können. Hier können Sie ein gutes Beispiel dafür finden - http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X