Serverarchitektur bei ASP.NET Hosting

Vielleicht einfach ein paar kurze Gedanken zu den letzten Arbeiten an VCR.NET 3.9, etwas abstrahiert. Im Endeffekt geht es darum, eine Serverfunktionalität mit präziser Lebenszeitkontrolle mit einer Web Oberfläche anzubieten. Die Kontrolle der Lebenszeit läßt sich ideal durch das Hosten des Servers in einem Windows Dienst erreichen, für die Web Oberfläche wäre natürlich der Microsoft Internet Information Server die bevorzugte Lösung. Mit dem ASP.NET Hosting läßt sich beides weitgehend kombinieren (es ist allerdings kaum möglich, alle Autorisierungsoptionen des IIS nachzubilden, aber das braucht man auch nicht immer).

Zu beachten ist allerdings, dass ein virtuelles Verzeichnis immer in einer eigenen .NET AppDomain läuft. Unser Ansatz besteht daher immer aus mindestens zwei AppDomains, was einige besondere Aspekte mit sich bringt. Ich stelle hier in Stichworten einmal die beim VCR.NET implementierte Lösung vor.

1. Der .NET Dienst wird natürlich in einer ersten AppDomain gestartet. Hier soll auch der Server leben.
2. Der Server wird als .NET Instanz einer MarshalByRefObject Klasse (Server) erzeugt.
3. Für das ASP.NET Hosting wird eine weitere MarshalByRefObject Klasse (Host) benötigt, die in dem virtuellen Verzeichnis erstellt wird.
4. Nach dem Starten des virtuellen Verzeichnisses erhält Host die Server Referenz aus der ersten AppDomain.
5. Alle Zugriffe aus dem virtuellen Verzeichnis erfolgen über dese Referenz und werden in der ersten AppDomain ausgeführt.
6. Damit die beiden (Server und Host) Inter-AppDomain Referenzen nicht durch die Remoting Lebenszeitkontrolle spontan gelöst werden, melden deren InitializeLifetimeService Methoden null.
7. Alle Klassen, die zwischen den AppDomains ausgetauscht werden sollen, müssen MarshalByRefObject oder [Serializable] sein. VCR.NET setzt auf serialisierbare Klassen, so dass zwar für die Serialisierung und Deserialisierung bezahlt werden muss, die Objekte dann aber ohne Kommunikationsverluste weiter verwendet werden können. Man beachte, dass hier die binäre Serialisierung zum Einsatz kommt – man siehe dazu einen früheren Eintrag in diesem BLog.

Zur Verwaltung der Konfiguration wird ein einziges Konfigurationsobjekt eingesetzt, über das alle Zugriff (auch schreibend) erfolgen. Dieses wird in der ersten AppDomain angelegt. Damit es nicht in alle Klassen durchgereicht werden muss (hier gibt es etwa Methoden wie Log(string message)), erhählt die Konfigurationsklasse (Config) ein statisches Feld Current, dass bei der Intialisierung des Windows Dienstes auf der ersten AppDomain belegt wird (Config.Current = new Config()). Zusätzlich bietet die Server Klasse eine Eigenschaft zum Zugriff auf Config.Current an. In Schritt 4. oben wird in der AppDomain des virtuellen Verzeichnisses eine Referenz des eindeutigen Konfigurationsobjektes in das statische Feld als Referenz übernommen (Config.Current = Server.CurrentConfiguration) – ein anderes statisches Feld, da statische Felder nur pro AppDomain eindeutig sind. So arbeiten beide AppDomains immer mit der selben Konfiguration – Config ist natürlich ein MarshalByRefObject, dessen InitializeLifetimeService null liefert.

Nun, für einige ist das vermutlich trivial, aber vielleicht hilft die Information hier dem einen oder anderen, einige Fallstricke zu vermeiden und etwas Zeit zu sparen.

Viel Glück

Jochen

Bookmark the permalink.

Schreibe einen Kommentar