Deployment-Probleme
Beim Design jeder ernst zu nehmenden Anwendung, die sich am Markt schon etabliert hat oder sich bald durchsetzen soll, muss unter anderem immer auch ein geeignetes Deployment-Konzept erdacht werden. Einige Studien aus den letzten Jahren haben gezeigt, dass ein größerer Anteil der Kosten erst dann entsteht, wenn die Entwicklung längst abgeschlossen worden ist.In der Lebenszeit jeder Anwendung gibt es viele fachliche und technische Prozesse, die im Hintergrund laufen und die Anwendung am Leben halten. Technisch gesehen ist keine Anwendung fehlerfrei. Es gibt immer Fehler, die zu beheben sind oder zumindest gibt es neue Features, die die Anwendung verbessern und erweitern. Vor einigen Jahren hat man die Updates einer Anwendung noch auf einer Diskette geliefert. Kurz danach war es möglich, das gleiche auf einer CD zu liefern. Da es in den meisten Fällen genug Platz gab, hat man neben der Anwendung häufig noch Internet Explorer, MDAC und diverse andere Patches mitgeliefert. Technisch hat sich bis heute nur die Vorgehensweise geändert, aus fachlicher Sicht ist jedoch alles unverändert geblieben. Ob das Medium eine Diskette oder eine CD ist - die Lieferung dieses Mediums zu den Kunden ist in der Regel teuer.
Wahrscheinlich werden viele der Leser an dieser Stelle einwenden, dass eine solche Art der Auslieferung in die Jurazeit der Softwareindustrie gehört. Dazu muss man sagen, dass es noch viele Kunden gibt, die den Begriff Goldene CD unheimlich schätzen. Eine kleine Revolution im Gegensatz zu der herkömmlichen Vorgehensweise besteht sicherlich in der Verwendung des Internets. Ein neues Update wird einfach ins Internet zum Download gestellt. Die Kunden laden die neue Version bei Bedarf herunter und die Lieferungskosten sind so niedrig wie noch nie zuvor.
Nun, der Stand der Technik bietet seit der Einführung von Windows XP schon viel mehr. Wir alle kennen schon den Windows Update-Mechanismus unter XP. Sie müssen sich nur einloggen und schon laufen einige Updates im Hintergrund. Das mag in einigen Situationen lästig oder sogar falsch sein. In der Tat ist das aber eine tolle Funktionalität, die sich in der Zukunft unvermeidbar durchsetzen wird.
Dieser Artikel soll zeigen, wie ein solches Update in Windows konzipiert ist und wie man die bestehenden Funktionalitäten im .NET ausnutzen kann.
Update Support in Windows
Seit der ersten Auslieferung von Windows XP wird Version 1.0 der Background Intelligence Transfer Services mitgeliefert. Dieses System, bekannter als BITS, ist grundsätzlich für den Transfer der Dateien über HTTP zuständig. Das System ist in der Lage, die Übertragung im Hintergrund oder Vordergrund durchzuführen - auch dann, wenn die betroffene Anwendung nicht läuft. BITS implementiert grundsätzlich eine Art von Queuing-Mechanismus. Für jeden Download wird zuerst ein Download Job erzeugt, durch den der Transfer der Dateien verwaltet wird. Jeder Job kann eine von vier Prioritäten einnehmen:- Wenn ein Job Foreground-Priorität hat, verwendet er die gesamte Netzwerkbandbreite für den Transfer. In diesem Fall werden möglicherweise alle anderen Prozesse beeinträchtigt. Aus diesem Grund sollte diese Priorität sehr vorsichtig verwendet werden.
- Ein Job der Priorität High startet den Transfer beim Netzwerk-Idle. Das bedeutet, dass die Übertragung erst dann gestartet wird, wenn das Netzwerk auf der Seite des Clients frei zur Verfügung steht. Dies ist der so genannte Background Job von der höchsten Priorität.
- Priorität Normal ist die Default Job Priorität, die automatisch bei der Erzeugung eines Jobs gesetzt wird. Sie bezeichnet einen Background-Job mit der mittleren Priorität. Wenn bei der Erzeugung eines Jobs die Priorität nicht explizit angegeben wird, wird die Priorität Normal automatisch gesetzt.
- Jobs mit Low-Priorität werden nicht gestartet, solange nicht alle Jobs mit der höheren Priorität beendet sind. Die Jobs mit der gleichen Priorität teilen unter sich die Transferzeit und die Bandbreite.
Konsistenz der Übertragung
Der BITS-Service basiert auf einem proprietären Protokoll, das auf Basis von HTTP 1.1 entworfen ist. Aus diesem Grund können die unterstützten Upload- und Download-Funktionalitäten nur mit einem HTTP Webserver abgewickelt werden, der HTTP Version 1.1 oder höher unterstützt.Es ist allgemein bekannt, dass Windows XP in der Lage ist, die neuesten Patches automatisch zu beziehen. Leider ist es weniger bekannt, dass Windows XP mit dem selben Dienst in der Lage ist, mit Unterstützung von BITS, auch Dateien von Ihrem Rechner zu einem Zielserver zu übertragen. Laut Microsoft ist diese Funktionalität für den Austausch diverser Media-Dateien in der Zukunft gedacht. Für die Verwendung der BITS-Upload-Funktionalität muss die BITS Server Extension für den IIS installiert werden. Um potenzielle kriminelle Energie nicht anzustacheln, wird die Upload-Funktionalität in diesem Artikel nicht weiter betrachtet. Mehr Informationen dazu können Sie in der Plattform SDK-Dokumentation finden.
Das Herunterladen einer Datei scheint auf den ersten Blick keine besonders schwierige Aufgabe zu sein. Tatsächlich gibt es sehr viele Probleme, die in der Praxis auftreten können. Zum Beispiel: Wie verhält sich BITS, wenn während des Transfers eine Datei auf dem Server gerade aktualisiert wurde? Oder wie verhält sich eine Anwendung, wenn nur einige der vielen Dateien aktualisiert wurden? Diese Dateien besitzen wiederum Abhängigkeiten zu anderen Dateien. Was soll z.B. eine Anwendung tun, wenn diese Dateien nicht auf dem neuesten Stand sind? Diese offenen Fragen waren wahrscheinlich auch der Grund, warum ein automatisches Update nicht Bestandteil des .NET Frameworks 1.1 ist. Die gerade beschriebene Problematik wird als File Transfer Consistency bezeichnet. Eine Lösung für die Konsistenz der Daten ist jedoch schon, wenn auch unterhalb des Application-Levels, vorhanden.
Beim Herunterladen einer Datei überprüft BITS, ob sich die Größe der Datei oder ihr Timestamp verändert haben. Wenn dies der Fall ist, startet BITS die Übertragung der Datei neu. Wenn aber mehrere Dateien übertragen werden sollen und auf dem Server alle Dateien erneut aktualisiert wurden, startet BITS die Übertragung nur der letzten nicht übertragenen Datei neu. Die Dateien, die bereits übertragen wurden, werden nicht erneut übertragen. Bitte achten Sie darauf, dass dieses Verhalten einer Spezifikation entspricht und auf keinen Fall falsch ist. Ob bei solchem Verhalten Probleme auf einem höheren Application-Level auftreten, ist von den Dependencies der übertragenen Dateien abhängig.
Dies bedeutet, dass BITS in der gegenwärtigen Version die Konsistenz basierend auf der Größe der Dateien und ihrem Timestamp garantiert. Bitte denken Sie daran, dass daher der Inhalt der Datei gegen eine Man-in-the-Middle-Attack gegenwärtig noch nicht gewährleistet ist.
No-Touch Deployment in .NET
Bevor wir ein konkretes Beispiel auf Grundlage des BITS erstellen, wollen wir in diesem Abschnitt sehen, was in .NET in Sachen automatischer Updates - unter Microsoft-Architekten besser bekannt als No-Touch Deployment - schon vorhanden ist. Seit der ersten Version des Frameworks ist es möglich, die Installation einer Windows Forms-Anwendung vollständig automatisch durchzuführen. Bei diesem Update handelt es sich nicht um einen BITS Service, sondern um eine Funktionalität des Frameworks.Um dies zu zeigen, erstellen wir eine einfache HelloForms-Anwendung (siehe Abb. 1). Diese Anwendung soll ein Formular mit dem Text Version 1 anzeigen. Erstellen Sie dann eine HTML Datei mit dem Link zu der ausführbaren Datei HelloForms.Exe:
<html><head><title>BITS Artikel</title></head><body><a href="HelloForms.Exe">Click here to start application</a></body></html>
BITS in .NET
Um ganz ehrlich zu sein: Im .NET Framework ist BITS noch nicht integriert. Da erst die kommende Version 2.0 die BITS Funktionalitäten in vollem Umfang enthalten soll, werden wir in diesem Abschnitt die Verwendung von BITS in .NET untersuchen. BITS kann grundsätzlich in zwei Teile aufgeteilt werden. Der erste Teil ist der Prozess wuauclt.exe (Windows Update Automatic Update Client). Dieser Prozess ist dafür zuständig, das Update ohne User-Interaktion durchzuführen.
Damit er diese Aufgabe erfüllen kann, muss es einen Mechanismus geben, um die Update-Jobs zu generieren. Für diese Aufgabe ist die BITS-COM-Schnittstelle zuständig, die in der Datei qmgrprxy.dll implementiert ist. Diese zwei Dateien decken fast alles ab, was Sie vom BITS brauchen. Da Sie mit dem Prozess wuauclt.exe keine direkte Kommunikation haben, ist er komplett selbständig. Wenn das System hochgefahren wird, wird wuauclt.exe vom Prozess svchost.exe als Child-Prozess gestartet.
Eine der wichtigsten BITS Schnittstellen ist der Copy Manager, der über Interop wie folgt deklariert werden kann:
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)][GuidAttribute("5CE34C0D-0DC9-4C1F-897C-DAA1B78CEE7C")][ComImportAttribute()]interface IBackgroundCopyManager {void CreateJob([MarshalAs(UnmanagedType.LPWStr)] string DisplayName, BG_JOB_TYPE Type, out Guid pJobId, [MarshalAs(UnmanagedType.Interface)] out IBackgroundCopyJob ppJob);void GetJob(ref Guid jobID, [MarshalAs(UnmanagedType.Interface)] out IBackgroundCopyJob ppJob);void EnumJobs(uint dwFlags, [MarshalAs(UnmanagedType.Interface)] out IEnumBackgroundCopyJobs ppenum);void GetErrorDescription([MarshalAs(UnmanagedType.Error)] int hResult, uint LanguageId, [MarshalAs(UnmanagedType.LPWStr)] out string pErrorDescription);}
Listing 1
IBackgroundCopyManager bcm = null;IBackgroundCopyJob myJob = null;// Erzeuge BITS Manager. Deklariert im InteropBits.Csbcm = (IBackgroundCopyManager)new BackgroundCopyManager();// Erzeuge einen Job namens ThinkBeyond und gebe die JobId und das Job-Object zurück.bcm.CreateJob("ThinkBeyondJob", BG_JOB_TYPE.BG_JOB_TYPE_DOWNLOAD, out jobId, out myJob);BitsNotifier myNotifier = new BitsNotifier();myJob.SetNotifyInterface(myNotifier);myJob.SetNotifyFlags(3);// Eine Datei hinzufügen, die heruntergeladen werden soll. Bei diesem// Aufruf wird spezifiziert von wo die Datei heruntergeladen werden soll// und wo sie hinkopiert werden soll. Nach diesem Aufruf befindet sich der// Job im Suspended-StatemyJob.AddFile("http://localhost/bitsupdate/update.zip", AppDomain.CurrentDomain.BaseDirectory + "\\myDownload.zip");// Nach diesem Aufruf wird der Job in den Queued-State versetzt, damit// Download beginnen kann.myJob.Resume();
// Am Ende sollten Sie nicht vergessen, einen Clean-Up durchzuführen.if(myJob != null)Marshal.ReleaseComObject(myJob);if(bcm != null)Marshal.ReleaseComObject(bcm);
Wird dieses Programm gestartet, wird ein Job erzeugt und der Download kann im Hintergrund starten, wenn das Netz im Idle-Zustand ist. Die Datei wird zuerst in eine temporäre Datei heruntergeladen, die sich im Destination-Verzeichnis befindet. Der Name dieser Datei wird vom BITS vergeben. In diesem Fall heißt die Datei BIT2FEA.tmp. Wenn der Download gestartet wird (Resume()-Aufruf ) ändert der Job seinen Zustand. Abpictureung 6 zeigt die gängigen Zustände in der Lebensdauer eines Jobs.
Listing 2
BG_JOB_STATE jobState;String dn;IBackgroundCopyError myErr = null;myJob.GetDisplayName(out dn); // Display Name abfragenmyJob.GetState(out jobState); // Job-Zustand abfragen<b></b>// Überprüfen, ob sich der Job im Fehlerzustand befindetif(jobState == BG_JOB_STATE.BG_JOB_STATE_ERROR){// Fehlerobjekt abfragenmyJob.GetError(out myErr);// Die Beschreibung des Fehlers abfragenmyErr.GetErrorDescription((uint)Thread.CurrentThread.CurrentCulture.LCID, outerrDesc);}
Callbacks
Solange es sich um eine Testanwendung handelt, können Sie die Zustände eines Jobs ständig abfragen. Leider ist diese Vorgehensweise keine besonders gute Lösung, wenn Sie zum Beispiel mehrere Jobs verwalten. Sie müssten in diesem Fall für mehrere Jobs die Zustände abfragen, um den gewünschten Zustand zu ermitteln. Zum Beispiel: Sie möchten erfahren, ob ein Job sich im Fehlerzustand befindet, oder ob ein Job erfolgreich die Übertragung beendet hat. Eine bessere Programmiertechnik stellt das BITS-Callback-Verfahren dar.BITS bietet unter anderem die Schnittstelle IBackgroundCopyCalback, die Sie implementieren müssen, wenn Sie automatisch (ohne kontinuierliche Abfragen) benachrichtigt werden möchten, wenn sich der Job in wichtigen Zuständen befindet. Diese Schnittstelle bietet die Benachrichtigung (Callback-Methoden) für folgende Fälle: 1. JobTransferred - wenn die Datei heruntergeladen worden ist (Zustand: Transferred). In dieser Callback-Methode sollten Sie die für die Anwendung spezifische Logik implementieren. Sie rufen die Complete()-Methode auf und anschließen bearbeiten Sie die heruntergeladene Datei. Das Bearbeiten dieser Datei wird in diesem Kontext wahrscheinlich ein Update Ihrer Anwendung bedeuten. Und gerade dies ist keine einfache Angelegenheit. BITS leistet in der bestehenden Form eine Menge Arbeit auf einem tieferen Level. Die Dateien werden ohne viel Aufwand in das gewünschte Verzeichnis kopiert, ohne dass das System überlastet wird.
Gerade diese Leistung ist eine echte Erleichterung. Leider löst sie nur einen Teil Ihres Problems. Wenn eine Datei übertragen worden ist, müsste man auch alle anderen abhängigen Dateien herunterladen. Erst wenn alle Dateien (Dependencies) lokal vorhanden sind, kann man anfangen, die alten Dateien auszutauschen. Wenn aber in diesem Moment die Anwendung läuft, sind meistens alle der Dateien exklusiv gelockt.
Die einzige Lösung wäre, einen kontrollierten Start der Anwendung zu implementieren. Zum Beispiel soll die Anwendung bei jedem Start überprüfen, ob eine neue Version der Anwendung zur Ausführung bereit steht. Eine solche Implementierung kann man auf www.windowsforms.com finden. Das Microsoft Team hat hier eine Zwischenlösung offengelegt, Windows Updater getauft, die aber nicht auf Basis des BITS realisiert ist. Eine überarbeitete Version soll erst in der Version 2.0 des Frameworks vorhanden sein (inoffizielle Aussage des Windows Forms-Product Managers).
2. JobError - wenn bei der Übertragung einer oder mehrerer Dateien ein Fehler aufgetreten ist. Hier ist es wichtig, zwei Typen von Fehlern zu unterscheiden. Fehler, die auftreten, wenn die Übertragung nicht fortgesetzt werden kann (Zustand: Error) und die Fehler, die vom BITS selbst behoben werden können (Zustand: Transient Error).
Folgendes Beispiel illustriert dieses Verhalten, wenn man versucht, die Datei von einem nicht existierenden Server herunterzuladen: Zuerst versucht BITS eine Verbindung mit dem Server aufzubauen. Nach einigen Versuchen wird BITS in den Zustand Transient Error versetzt. Bitte achten Sie darauf, dass in diesem Moment der JobError-Callback nicht aufgerufen wird. In Abhängigkeit von den Werten MinimumRetryDelay und NoProgressTimeOut wird der Zeitpunkt festgelegt, wann die Callback-Methode aufgerufen wird (Achtung: Die Zeitwerte sind in Microsoft-Sekunden einzugeben). Um dies zu testen, setzen Sie am besten diese Werte auf eine Ms-Sekunde. Dann können Sie sehen, wie das System aus Connecting und Transient Error in den Zustand Error übergeht. Die Callback-Methode wird nur ein Mal aufgerufen, wenn der Job den Error-Zustand annehmen soll.
3. JobModification - wenn der gewünschte Job modifiziert worden ist.
Job Enumeration
Bisher haben wir gesehen, wie man einen Job erzeugt und wie man die Zustände eines Jobs abfragen kann. In allen Beispielen haben wir vorausgesetzt, dass wir die Instanz eines Jobs haben. Dies war auch möglich, weil wir die Instanz selbst erzeugt haben. Es gibt aber Fälle, wo wir die Jobs nicht selbst erzeugt haben oder die Anwendung neu starten musste. Folgendes Beispiel zeigt wie man alle Jobs in der BITS-Queue auflisten kann. Beachten Sie, dass der erste Parameter der Methode EnumJobs spezifiziert, ob wir nur Jobs, die wir selbst generiert haben (0), oder die Jobs aller Benutzer (1) auflisten wollen. Um die Jobs aller Benutzer aufzulisten, müssen Sie selbstverständlich ein Administrator sein.bcm = (IBackgroundCopyManager)new BackgroundCopyManager();// Objekt für die JoblisteIEnumBackgroundCopyJobs pJobList;// Jobs aller Benutzer enumerieren und in die Liste eintragenbcm.EnumJobs(1, out pJobList);// Die Anzahl von Jobs ermittelnuint pJobCounter;pJobList.GetCount(out pJobCounter);for(int n = 0; n < pJobCounter; n++){. . .}
Security
Die bisherigen Beispiele zeigen, wie man die Dateien ohne Authentifizierung herunterladen kann. Wenn Sie Ihr so genanntes Intellectual Property verschenken möchten, können Sie diesen Abschnitt überspringen. In den IIS-Einstellungen hat man einen Anonymous Login vorausgesetzt. In den meisten Fällen wird dies leider nicht ausreichen.BITS unterstützt Basic Authentication, Passport und selbstverständlich Challenge/Response. Um zu sehen, was passiert, wenn BITS versucht, eine Datei aus dem gesicherten Bereich herunterzuladen, setzen Sie die Security-Einstellungen im IIS auf Basic-Cleartext. Abpictureung 7 zeigt den Fehler, der bei der Übertragung entstanden ist.
<a>HTTP://username:password@server/path/file</a>
string fName;IEnumBackgroundCopyFiles myFiles = null;IBackgroundCopyFile myFile = null;myJob.EnumFiles(out myFiles);myFiles.Next(1, out myFile, out fetched);myFileArr.GetRemoteName(out fName);
Ausblick
In diesem Artikel haben wir die ersten Einsätze des No-Touch Deployment-Konzepts mit .NET erläutert. Dieses Konzept reicht leider nicht aus, um automatische Updates vollständig konfigurierbar und ohne viel Aufwand durchführen zu können. Zusätzlich ist der Anwender beim Herunterladen einer neueren Version größerer Anwendungen gezwungen, so lange zu warten, bis alle notwendigen Dateien heruntergeladen worden sind. Darüber hinaus kann dieses Konzept nur für Windows Forms-Anwendungen eingesetzt werden.Auf der anderen Seite bietet BITS die Möglichkeit, das Update einer Anwendung auf eine technisch sehr geschickte Weise im Hintergrund durchführen zu können. Diese Funktionalität findet gegenwärtig leider keine Anwendung in .NET. Hier haben wir aufgezeigt, wie man BITS in eigene .NET-Anwendungen integrieren kann, um ein automatisches Update auf Basis des BITS dennoch durchführen zu können.




