b2aat6n
b2aat6n
b2aat6n
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
thode mehrere Parameter von einfachen<br />
Typen erwarten, müsste jemand, der den<br />
Code liest, daraus gedanklich die Dienstbeschreibung<br />
erst wieder zusammensetzen.<br />
Das Datenmodell für die Dienstbeschreibung<br />
sieht aus wie in Listing 5.<br />
Die Kontrakte für die Funktionseinheiten<br />
sind in EBC-Manier erstellt. Das bedeutet,<br />
dass sie über sogenannte Inputund<br />
Outputpins verfügen. Inputpins werden<br />
in Form von Methoden modelliert,<br />
Outputpins sind Events. Zu weiteren Details<br />
über EBCs lesen Sie am besten die<br />
Artikelserie von Ralf Westphal, zu finden<br />
unter [1] [2] [3]. Der Kontrakt für das Auswerten<br />
der Argumente sieht aus wie in Listing<br />
6. Auf dem Inputpin In_Process der<br />
Funktionseinheit werden die Kommando-<br />
Listing 4<br />
Eine statische Methode<br />
„Run” verwenden.<br />
EasyService.Run(<br />
args,<br />
"myService",<br />
"Mein Service",<br />
"Ein Service, der nichts tut.",<br />
() => Trace.WriteLine<br />
("OnStart aufgerufen"),<br />
() => Trace.WriteLine<br />
("OnStop aufgerufen")<br />
);<br />
Listing 5<br />
Datenmodell für die Dienstbeschreibung.<br />
public class ServiceBeschreibung<br />
{<br />
public string Name { get; set; }<br />
public string DisplayName { get; set; }<br />
public string Description { get; set; }<br />
}<br />
Listing 6<br />
Argumente auswerten.<br />
public interface IArgumenteAuswerten<br />
{<br />
void In_Process(params string[] args);<br />
event Action Out_Install;<br />
event Action Out_Uninstall;<br />
event Action Out_RunAsService;<br />
}<br />
[Abb. 2] Verfeinerung<br />
des Entwurfs.<br />
zeilenparameter in Form eines string-Arrays<br />
übergeben. Je nachdem, welcher Parameter<br />
übergeben wurde, wird daraufhin<br />
der korrespondierende Outputpin ausgelöst.<br />
Die beiden Kontrakte für die Installation<br />
und Deinstallation sind noch einfacher, da<br />
sie nicht über Outputpins verfügen, siehe<br />
Listing 7.<br />
Und zu guter Letzt ist da noch der Kontrakt<br />
für die Ausführung des Service, siehe<br />
Listing 8.<br />
Damit haben Sie nun alle Kontrakte zusammen<br />
und können mit der Implementierung<br />
beginnen. Wie schon angedeutet,<br />
sind automatisierte Tests an den Stellen<br />
schwierig, an denen die Windows-Infrastruktur<br />
relevant ist. Dies betrifft das Installieren<br />
und Deinstallieren des Dienstes. Ferner<br />
sollte der Kontrakt IServiceAusführen<br />
mit der abstrakten Klasse ServiceBase aus<br />
dem .NET Framework kombiniert werden.<br />
Diese stellt die erforderliche Infrastruktur<br />
für die Dienstausführung zur Verfügung.<br />
Damit die Dienste nicht von ServiceBase<br />
ableiten müssen und tatsächlich keine Abhängigkeiten<br />
zur Windows-Infrastruktur<br />
haben, verwende ich einen Dienstproxy.<br />
Diese Klasse leitet von ServiceBase ab und<br />
bietet zwei Events, die beim Starten bzw.<br />
Stoppen des Dienstes ausgeführt werden.<br />
Dadurch kann ein Lambda-Ausdruck verwendet<br />
werden, und der Dienst ist infra-<br />
Listing 7<br />
Installation und Deinstallation.<br />
public interface IServiceInstallieren<br />
{<br />
void In_Installieren(ServiceBeschreibung beschreibung);<br />
}<br />
public interface IServiceDeinstallieren<br />
{<br />
void In_Deinstallieren(ServiceBeschreibung beschreibung);<br />
}<br />
LÖSUNG<br />
strukturunabhängig. Der Dienstproxy sieht<br />
aus, wie in Listing 9 gezeigt wird.<br />
Diese Klasse ist so simpel, dass ich auf<br />
Tests verzichtet habe. Sie zu ergänzen würde<br />
im Übrigen auch erfordern, die protected<br />
Methoden OnStart und OnStop im<br />
Test aufzurufen. Aufgrund der Vererbung<br />
kann die Sichtbarkeit nicht zu internal geändert<br />
werden. Aufwand und Nutzen stünden<br />
daher in einem sehr ungünstigen Verhältnis.<br />
Da das gesamte Projekt ohnehin<br />
einen Integrationstest erfordert, wird der<br />
ServiceProxy dort mitgetestet.<br />
Sehr gut automatisiert zu testen ist die<br />
Implementierung der Argumentauswertung.<br />
Ich habe die Klasse ArgumenteAuswerten<br />
testgetrieben entwickelt. Listing 10<br />
zeigt zwei der Tests als Beispiele.<br />
Der erste Test prüft, ob beim Aufruf ohne<br />
Parameter der Outputpin Out_RunAs-<br />
Service ausgelöst wird. Dies ist wichtig, da<br />
Windows den Dienst so startet. Der zweite<br />
Test prüft, ob bei Aufruf mit /install der<br />
Event Out_Install ausgelöst wird.<br />
Die zugehörige Implementierung ist einfach<br />
gehalten. Zunächst wird geprüft, ob<br />
kein Argument übergeben wurde. In dem<br />
Fall wird der Event Out_RunAsService ausgeführt.<br />
Andernfalls wird über ein switch-<br />
Statement in die jeweiligen Events verzweigt.<br />
Diese Form der Argumentauswertung<br />
ist zwar zu einfach, um damit etwa zusätzliche<br />
Parameter zu den Optionen parsen<br />
www.dotnetpro.de dotnetpro.dojos.2011 47