2009-08-09 10 views
1

Ich habe eine App, die eine Reihe von DLLs auf dem Dateisystem und in der GAC öffnet, und die eine Sperre für diese Dateien hält. Wie kann ich diese Punkte explizit freigeben, damit ich sie in Visual Studio neu erstellen kann, ohne meine App zu schließen?C#: Warum schließt meine App nicht die Dateigriffe?

-Code folgt:

private void BuildTabPage_AssemblyTree(string filename, string foldername) 
{ 
    Assembly assembly; 
    try 
    { 
    assembly = Assembly.LoadFrom(filename); 
    } 
    catch (Exception ex) 
    { 
    MessageBox.Show("Error loading assembly " + filename + "\n" + ex.Message); 
    return; 
    } 
    TreeNode tRoot = BuildNode(assembly, foldername); 
    tvAssemblies.Nodes.Add(tRoot); 
    tvAssemblies.ExpandAll(); 

    txtResults.Text = 
    RefsFound.ToString() + " References Located in Filesystem\r\n" + 
    RefsInFramework.ToString() + " References Located in Framework\r\n" + 
    RefsInGac.ToString() + " References Located in GAC\r\n" + 
    RefsNotFound.ToString() + " References Not Found: \r\n\r\n"; 
    foreach (string s in MissingFiles) 
    txtResults.Text += s + "\r\n"; 
} 

private TreeNode BuildNode(Assembly assembly, string foldername) 
{ 
    TreeNode tn = new TreeNode(assembly.GetName().Name); 
    tn.ToolTipText = assembly.FullName + "\n" + assembly.CodeBase; 
    AssemblyName[] assemblies = assembly.GetReferencedAssemblies(); 

    foreach (AssemblyName a in assemblies) 
    { 
    string filename2 = foldername + a.Name + ".dll"; 
    TreeNode tn2; 
    if (System.IO.File.Exists(filename2)) 
    { // File found in folder 
     RefsFound++; 
     Assembly assy = Assembly.LoadFile(filename2); 
     tn2 = BuildNode(assy, foldername); 
    } 
    else if (a.Name.StartsWith("System")) 
    { // Framework assemblies not included 
     RefsInFramework++; 
     tn2 = new TreeNode(); 
     tn2.Text = a.Name; 
     tn2.ForeColor = System.Drawing.Color.Green; 
     tn2.ToolTipText += "\n.NET Framework File"; 
    } 
    else 
    { 
     try 
     { // Find file in GAC 
     Assembly assy = Assembly.Load(a); 
     tn2 = new TreeNode(a.Name); 
     tn.ToolTipText = assembly.FullName + "\n" + assembly.CodeBase + "\nFile detected in GAC"; 
     tn2.Text = "(" + filename2.Substring(filename2.LastIndexOf("\\") + 1) + ")"; 
     tn2.ForeColor = System.Drawing.Color.Green; 
     RefsInGac++; 
     } 
     catch (System.IO.FileNotFoundException) 
     { // File not Found 
     RefsNotFound++; 
     if (!MissingFiles.Contains(a.Name)) 
      MissingFiles.Add(a.Name); 
     tn2 = new TreeNode(); 
     tn2.Text = "(" + filename2.Substring(filename2.LastIndexOf("\\") + 1) + ")"; 
     tn2.ToolTipText = "File Not Found"; 
     tn2.ForeColor = System.Drawing.Color.Red; 
     } 
    } 
    tn.Nodes.Add(tn2); 
    } 

    return tn; 
} 
+2

dieser Code "riecht" .... BuildNode() hat mehrere Verantwortlichkeiten, die nichts mit dem Aufbau eines Knotens zu tun haben ... –

Antwort

6

Leider werden Assemblys, die in eine Standard-Anwendungsdomäne geladen wurden, erst dann entladen, wenn die Anwendung beendet wird. Sie können jedoch eine Anwendungsdomäne erstellen und Baugruppen in einer erstellten Anwendungsdomäne laden. Wenn die erstellte Anwendungsdomäne entfernt wird, werden in der erstellten Anwendungsdomäne geladene Assemblys zusammen entladen.

+0

Ich sehe keinen Weg zu AppDomain.Load() einer Assembly nach Pfad und Dateiname. Die meisten Baugruppen, auf die ich ausgerichtet bin, sind nicht im GAC enthalten. Wie kann ich eine DLL nach Datei in eine neue AppDomain laden? – tsilb

+0

Ich würde lieber eine AppDomain mit der Assembly erstellen, die BuildTabPage_AssemblyTree() enthält und die Methode in der erstellten AppDomain ausführen. Sobald Sie fertig sind, können Sie die erstellte AppDomain entfernen. Alle in der AppDomain geladenen Assemblys sollten zusammen entladen werden. Ich hoffe, dass dies Ihr Problem lösen kann. –

+0

AppDomain.Unload scheint keine Auswirkungen zu haben. Der Debugger zeigt die geladenen Assemblys an, zeigt jedoch nicht, dass sie beim Entladen der AppDomain entladen werden. Die Dateigriffe bleiben geöffnet. – Triynko

0

Ich denke, wenn Sie Setup Ihre AppDomain Shadow verwenden sollte es funktionieren:

http://blogs.msdn.com/junfeng/archive/2004/02/09/69919.aspx

Dieser Link befasst sich mit Ihrer Frage im Detail (wenn ich Ich verstehe Sie richtig): http://blogs.msdn.com/jasonz/archive/2004/05/31/145105.aspx

+0

Das erklärt die Dateisperre; aber warum wird die Datei nicht entladen, wenn die Variable den Gültigkeitsbereich verlässt? – tsilb

+0

Nun, "aus dem Rahmen zu gehen" hat eine ganz andere Bedeutung in C#. Sehen Sie sich das Dispose-Muster an, um die Ressourcenverwaltung zu verstehen. Sicher C# ist Müll gesammelt aber das geht nur so weit. Sie müssen immer noch verstehen, wie Ressourcen zu verwalten sind. Ein weiterer Grund dafür, dass die Assembly nicht entladen wird, besteht darin, dass Assemblys nicht per Entwurf aus einer App-Domäne entladen werden können. –

+0

Ich glaube nicht, dass die Verwendung der ShadowCopy eine gute Idee ist. Nach dem Code zu urteilen, würde diese App am Ende eine sehr große Anzahl von Assemblys kopieren, einschließlich vieler der Standard-System-Assemblies. Außerdem hätte das Programm keine Möglichkeit, die Eigenschaften der Assemblys zu aktualisieren, da nachfolgende Aufrufe zum Laden der Assembly die bereits geladene Assembly zurückgeben und nicht die, die vermutlich gerade neu erstellt wurde. –

1

Sobald Sie eine Baugruppe in Ihren Prozess laden, können Sie sie nicht entladen. Stattdessen können Sie für jede Assembly, die Sie laden möchten, eine Anwendungsdomäne erstellen, die Eigenschaften der Assemblys abrufen und die Anwendungsdomäne schließen.

Verwandte Themen