Update einer WPF Anwendung zur Laufzeit

Von Thomas Schissler

Aktuell sind wir es gewohnt, dass zum Update einer Anwendung meist ein Neustart notwendig ist. Nachfolgend möchte ich einen Weg aufzeigen, wie man mit Hilfe von MEF auch Komponenten einer Anwendung zur Laufzeit aktualisieren kann.

Wir haben dazu kurzerhand ein kleines Demo mit Fischertechnik gebaut: Ein Programm steuert eine Maschine, deren Betrieb durch das Update nicht unterbrochen werden darf. Übrigens: Der Code zu unserer kleinen Applikation ist hier auf GitHub zu finden.

zur Demo

Das Prinzip

Das Grundprinzip ist recht simpel. Man nehme eine Assembly mit einer der upgedateten Komponente und kopiert sie ins Anwendungsverzeichnis der aktuell laufenden Anwendung. Dies bekommt die Anwendung mit und aktualisiert den IoC Container, was wiederum dazu führt dass von nun an die neue Komponenten genutzt wird.

Die Umsetzung

Für die Umsetzung sind drei Dinge notwendig:

  1. Zu erst einmal brauchen wir einen Trigger, welcher der Anwendung mitteilt dass diese sich aktualisieren soll. Der Einfachheit halber haben wir uns für einen FileSystemWatcher entschieden, welcher uns meldet wenn sich etwas im Ausführungsverzeichnis geändert hat.
  2. Wurde der Update einmal getriggert muss die neue Assembly geladen werden. Hierfür nutzen wir MEF und die DirectoryCatalog-Klasse. Ändert sich etwas in einem bereits registrierten Directory nutzen wir die Refresh() Methode, um den Catalog zu aktualisieren. Kam ein neues Verzeichnis hinzu, so wird für dies ein neuer DirectoryCatalog erstellt. Übrigens: Bei unseren ersten Versuchen kam es hierbei zu Fehlern. MEF erkannte zwar, das es zwei Assemblies laden muss, allerdings hatten wir im Container zwei mal dieselbe Assembly geladen. Die Lösung war die Assemblies zu signieren, hierbei kann der gleiche Key für beide Assemblies verwendet werden. Außerdem muss noch die Assembly-Version in der Update-Assembly hochgesetzt werden.
  3. Wir haben nun das Erkennen eines Updates und das Laden der Assemblies in der Anwendung abgehandelt. Das bedeutet, dass wir nun zwei unterschiedliche Versionen einer Komponente zur Verfügung haben. Jetzt gilt es noch zu bestimmen welche wir den nun anzeigen sollen.
    Um zu erkennen, welches die neuere Version ist nutzen wir das ExportMetadata-Attribut von MEF. Neben der Versionierung der Assembly ist es also noch notwendig, dass die Komponente weiß, welche Version sie hat. Um dann letztendlich auch in der Anwendung die neue Komponente zu nutzen, werden beim Import die Metadaten ausgewertet und nur die Komponente mit der höchsten Version genutzt.

Das war es dann auch schon. Mehr gibt es im Grund nicht zu tun. War doch gar nicht so schlimm, oder?