Laden...

Dynamisch geladene Assemblies und Patchen dieser

Erstellt von Carryman vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.092 Views
C
Carryman Themenstarter:in
19 Beiträge seit 2007
vor 12 Jahren
Dynamisch geladene Assemblies und Patchen dieser

Hallo Community,

ich bräuchte wieder mal nen Schubs in die richtige Richtung.

Ich hab einige Dll's aus einer laufenden Entwicklung und mir ein Tool gebastelt was mir Konfigurationen aus diesen Dll's ausliest (per Reflection).

Soweit so gut. Nun möchte ich aber im Tool einen Patch-Mechanismus für neue Versionen einfügen.
Ich hab für jedes Assembly eine eigene AppDomain dynamisch erzeugt und über diese lade ich mir die Assemblies.
Dann möchte ich patchen -> Access denied.
Auch das manuelle Patchen (copy&paste) geht nicht, solange das Tool läuft.


private Dictionary<string, AppDomain> Custom_Assemblies = new Dictionary<string, AppDomain>();

///...
public bool LoadAssemblies()
{
//...
                    foreach (KeyValuePair<string, AppDomain> tmp in Custom_Assemblies)
                    {
                        if (tmp.Value == null)
                        {
                            Custom_Assemblies[tmp.Key] = AppDomain.CreateDomain(tmp.Key);
                            Custom_Assemblies[tmp.Key].Load (System.IO.File.ReadAllBytes(tmp.Key));
                        }
                    }
//...
}

///...
public bool UnLoadAssemblies()
{
//...
                foreach (KeyValuePair<string, AppDomain> tmp in Custom_Assemblies)
                {
                    if (tmp.Value != null)
                    {
                        AppDomain.Unload(tmp.Value);
                        Custom_Assemblies[tmp.Key] = null;
                    }
                }
//...
}


Berechtigungen werden/sind korrekt gesetzt und über ne MiniApp kann ich die Libraries auch "ersetzen". Nur nicht wenn ich diese vorher einmal dynamisch geladen und ausgelesen hab.

Irgendwelche Ideen?

Vielen Dank für Eure Hilfe.

Grüße

Carry

P.S.:
Die Ausgabe "tasklist /m" sagt mir auch, dass ich kein geladenes Modul(Lib) am Prozess anhängen habe, die ich zu dem "Access denied" Zeitpunkt patchen möchte.

1.361 Beiträge seit 2007
vor 12 Jahren

Hallo Carryman,

Ich würde dafür eher Mono.Cecil verwenden.
Damit solltest du keinerlei Probleme haben.

Kannst man überhaupt mit Reflection eine Assembly persistent manipulieren? (Also ne komplett neue geht über reflection.emit... Aber ne bestehende...)

Beste grüße
Zommi

C
Carryman Themenstarter:in
19 Beiträge seit 2007
vor 12 Jahren
Danke

...editieren will ich se ja gar nicht. Ich will se einhängen, auslesen, aushängen, damit ich die Files mit ner neueren Version patchen kann, bei Bedarf. 😉
Ich guck mir Mono-Cecil mal an. Danke schon mal.

Grüße

Hoffi

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo Carryman,

wenn es um normale Konfiguration geht, also darum, der Anwendung Konfigurationsdaten zur Verfügung zu stellen, ist das vermutlich eher ein Fall für [Tutorial] Konfigurationsmodell im .NET Framework.

herbivore

656 Beiträge seit 2008
vor 12 Jahren

Klingt eher nach [FAQ] Eigene Anwendung pluginfähig machen - zumindest verstehe ich "patchen" hier in dem Kontext als "aktuelle DLL entladen, neue einspielen, neue DLL laden".

C
Carryman Themenstarter:in
19 Beiträge seit 2007
vor 12 Jahren

Hallo herbivore und Bhaal,

um einfache Konfigurationen geht es leider nicht. Ich muss aus Assemblies benutzerdefinierte Attribute (welche an den Methoden hängen), Enums und Structs auslesen. Diese geben z.B. Reihenfolgen wieder, in der diese gestartet werden und gewisse Gegebenheiten die erfüllt sein müssen.
Mein Tooling prüft die Gegenheiten und stellt diese automatisiert auf dem System ein, bevor die Assemblies ausgeführt werden.

Das Laden an und für sich ist auch nicht das Problem, das geht. Aber das "Plugin"-fähig machen ist Tricky.

Danke Bhaal, die Tutorials zieh ich mir mal rein.

Grüße

Carry

C
Carryman Themenstarter:in
19 Beiträge seit 2007
vor 12 Jahren
Leider keine passende Logik dabei

Hallo zusammen nochmal,

ich hab mir die Lösungsansätze von Bhaal im Detail angeguckt. Es scheitert leider bei fast allen an einer Kleinigkeit.
Um das System mit den Microsoft-Mitteln "Plugin"-fähig zu machen, gibt es bestimmte Vorraussetzungen an den geladenen Bibliotheken (Attribute an Methoden, etc.).
Ich habe leider null Einfluss auf die Entwicklung der geladenen Bibliotheken. Diese werden ganz woanders hergestellt und ich bekomme nur die fertigen Assemblies, welche ich auch nicht bearbeiten darf.

Die einzige Möglichkeit, die mir noch einfällt: Den Patch-Vorgang über ne Zwischenanwendung durchführen:

  1. Anwendung startet "Patch"-Anwendung und schließt sich selbst (Referenzen frei)
  2. "Patch"-Anwendung startet Anwendung und schließt sich selbst (Referenzen werden wieder geladen
    Was aber unheimlich unschön ist und dem Projektleiter zu wieder läuft.

Bibliotheken von Drittanbietern ("SharpDevelop Core", etc.) wären zwar prinzipiell möglich, ziehen aber einen Rattenschwanz an Genehmigungen mit sich...

Seht ihr noch ne andere Lösung das Problem selber zu lösen? (Beispiel: Die Referenzen nach dem Unload der AppDomain manuell aus dem Speicher löschen oder sowas... ^^)

Sonnige Grüße
Carry

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo Carryman,

nach meinen Verständnis sollte das Unload der AppDomain die Dll automatisch wieder freigeben, so dass sie überschrieben werden kann.

herbivore

C
Carryman Themenstarter:in
19 Beiträge seit 2007
vor 12 Jahren

Hi herbivore,

das war auch mein Verständnis. Ich bin mittlerweile auch nen Schritt weiter:

Wenn das geladene Assembly kein weiteres Assembly referenziert, welches gepatcht werden soll, dann geht's. Sprich ich kann nach dem Unload der AppDomain auf das File zugreifen.
Wenn das geladene Assembly weitere Assemblies referenziert, dann sind die referenzierten Dll's gelockt. Trotz das ich vorher die Custom-AppDomain UnLoad aufgerufen hatte. 🙁

So ist beispielsweise eine Standard-Bibliothek die alle referenzieren immer gelockt.

Ich probiers weiter.

Grüße

Carry

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo Carryman,

Wenn das geladene Assembly weitere Assemblies referenziert, dann sind die referenzierten Dll's gelockt.

aber doch vermutlich nur solange diese weiteren Assemblies noch nicht entladen sind.

herbivore

C
Carryman Themenstarter:in
19 Beiträge seit 2007
vor 12 Jahren

Hi herbivore,

und da kommt die Krux. Entladen kann ich nur die AppDomain. Aber die Assemblies leider nicht.
Einen Hinweis habe ich gefunden im letzten Statement hier: My app domain won't unload:

I have found that if you ever directly access types in an assembly it gets loaded into your own domain.

Was da nun dran ist, weiß ich nicht aber ich habe festgestellt, dass die Assemblies auch nach dem Entladen der AppDomain noch vorhanden sind.
Deswegen glaube ich, dass da was dran ist.
Hilft mir nur in meiner Lösung nicht weiter. 😦

Grüße
Carry

S
248 Beiträge seit 2008
vor 12 Jahren

Hallo Carryman,

du musst so vorgehen:*Neue AppDomain erzeugen *In dieser neuen AppDomain die gewünschte Assmbly laden *Mit AppDomain.CreateInstanceAndUnwrap einen Proxy erzeugen und verwenden

Damit es bei mir funktioniert hat, musste ich bei der Klasse von MarshalByRefObject erben.

Dann sollte Entladen und Löschen der Assembly bzw AppDomain funktionieren.

grüße spooky

D
500 Beiträge seit 2007
vor 12 Jahren

Hallo Carrymann!

Es kommt bei der Kommunikation zwischen den AppDomains auch stark darauf an, welche Informationen Du zwischen den AppDomains (Haupt AppDomain und die temporaere AppDomain) austauscht bzw. was Dir die aufgerufene Methode an Rueckgabewerten zurueckliefert. Handelt es sich um einen Typen, der aus der nachgeladenen Assembly stammt, und wird dieser aus der temporaeren Domain in die Hauptdomain uebermittelt, dann wird die Assembly auch in die Hauptdomain geladen. Das Verhalten kannst Du wunderbar ueberpruefen, indem Du auf der entsprechenden AppDomain dir mittels der Methode GetAssemblies() die momentan geladenen Assemblies anschaust. So ein impliziter Typenaustausch zwischen den AppDomains kann eventuell fuer Probleme sorgen.

Ist vielleicht noch ShadowCopying ein Stichwort?

@Spook: Auch die von Dir beschriebene Loesung, kann zu dem von mir beschriebenen Problem fuehren, dass eine Assembly implizit in die Hauptdomain geladen wird und somit der Zugriff auf die eigentliche Datei (dll) verweigert wird.

Gruss,
DaMoe