Anwendungsdomänen und Community

Veröffentlicht: 13. Mai 2002 | Aktualisiert: 20. Jun 2004

Von Eric Gunnerson

Die Kolumne für diesen Monat enthält wenig Code, dafür umso mehr Informationen. Dies liegt zum Teil daran, dass ich Ihnen einige wichtige Dinge mitzuteilen habe; der Hauptgrund ist jedoch, dass ich einfach zu viel zu tun hatte.

Auf dieser Seite

Community Community
Anwendungsdomänen Anwendungsdomänen
Nächster Monat Nächster Monat

Community

Ich rief den C#-Produktzyklus als Testleiter für den C#-Compiler ins Leben, mit der Konsequenz, dass ich dem Designteam für die C#-Programmiersprache beitrat, daraufhin ein Buch über C# schrieb und diverse Präsentationen dazu zusammenstellte. Schließlich wurde ich Projektmanager eines neu gegründeten C#-Teams, der für die Community des gesamten C#-Teams verantwortlich ist.

Die Definition einer Community ist einfach - sie umfasst alle Interaktionen zwischen Personen, die dieselben Interessen haben. In meiner Freizeit beschäftige ich mich mit Raketen. Details dazu finden Sie auf meiner Website, auf die ich in diesem Artikel noch näher eingehen werde. Ein solches Vorhaben erfordert natürlich ein solides Grundwissen und eine gewisse Erfahrung. Zum Glück bin ich auf einer Mailingliste zu diesem Thema, so dass ich auf alle meine Fragen eine Antwort bekam. Das ist eine großartige Community; eine ebensolche möchte ich für den C#-Bereich ins Leben rufen.

Womit wir beim Thema wären. Wir haben viele Ideen, wie wir unseren Job einfacher gestalten können, aber wir brauchen Ihre Hilfe, um sicherzugehen, dass wir auch das Richtige tun. Mein Ziel ist es, Ihnen nützliche Informationen zur Verfügung zu stellen und dabei Spaß zu haben.

Unser größtes Vorhaben ist das Einrichten einer neuen Website für die C#-Community auf GotDotNet unter https://www.gotdotnet.com/team/csharp (in Englisch). Zur Zeit finden Sie dort noch nicht viele Informationen, aber die wenigen Informationen, die bereits verfügbar sind, sind sehr nützlich; u.a. auch eine FAQ-Liste zur C#-Sprache.

Ich muss zugeben, ich bin sehr stolz auf Aussehen und Layout der Site. Naja, ehrlich gesagt habe ich die Site selbst innerhalb kürzester Zeit entworfen und meine Fähigkeiten beschränken sich dann doch eher auf funktionelle Dinge. Es wird besser (es muss), aber ich gehöre einfach zu den Leuten, die sich eher auf den Content als auf das Äußere konzentrieren. Seien Sie also bitte nachsichtig mit mir.

Um beim Thema Einrichten einer Website zu bleiben; ich habe eine C#-Implementierung von Spacewar, dem allerersten Videospiel, auf der Site bereitgestellt. Laden Sie sich doch einfach den Code sowie die ausführbaren Dateien herunter und spendieren Sie Ihren Kollegen und Freunden einen Flug ins All. Darüber hinaus finden Sie dort auch eine Benutzerstudie, an der wir Sie bitten möchten teilzunehmen.

Neben der auf GotDotNet gehosteten Site gibt es auch eine neue, unabhängige C#-Site unter http://www.csharp.org (in Englisch). Ich habe mir diese Site noch nicht so genau angesehen, aber was ich gesehen habe, schien sehr nützlich zu sein.

Neben der GotDotNet-Website finden Sie die Mitglieder der Visual-C#-Community in den Newsgroups von Microsoft und in den entsprechenden Foren.

Anwendungsdomänen

Ich habe kürzlich Code zur Handhabung von Anwendungsdomänen geschrieben. Mit Anwendungsdomänen können Sie einen Teil einer Anwendung von anderen Teilen isolieren. Kurz gesagt, Sie können in zwei separaten Umgebungen arbeiten. In einigen Fällen sind diese sogar auf unterschiedlichen Computern, wobei die Kommunikation zwischen den Anwendungsdomänen dann über Remoteverarbeitung erfol> in anderen Fällen befinden sie sich in ein und demselben Prozess.

Neben der Isolierung bieten Anwendungsdomänen noch eine weitere wichtige Funktion. Ist eine Anwendungsdomäne entladen, sind auch deren Assemblys entladen. Dadurch kann ein dynamisches, aktualisierbares System implementiert werden. So kann beispielsweise ein Serverprozess aktualisierte Assemblys aufspüren, die alten deaktivieren und die Arbeit mit den neuen fortsetzen.

Die Arbeit mit Anwendungsdomänen erscheint zu Anfang etwas schwierig und ungewohnt. Da eine separate Anwendungsdomäne von der aktuellen isoliert ist, können zwischen diesen keine Objekte übergeben werden. Sie müssen gemarshalled (übertragen) werden. Dazu müssen Sie die neue Anwendungsdomäne anweisen, ein neues Objekt zu erzeugen, und diesem einen Proxy zurückgeben. Der Aufruf selbst erfolgt dann anschließend über diesen Proxy.

Das Proxyobjekt muss sich von MarshalByRefObject ableiten, da nur auf diese Weise Proxys implementiert werden können. Im Folgenden finden Sie das Proxyobjekt, mit dem wir eine Assembly laden, um mit dieser einige Aktionen durchzuführen:

namespace AppDomainAssemblyLoader
 {
   public class AssemblyProcessor : MarshalByRefObject
   {
      Assembly assembly;
      public AssemblyProcessor()
      {
      }
      public void Load(string assemblyName)
      {
         assembly = Assembly.Load(assemblyName);
      }
      public void Process()
      {
      }
   }
}

Diese Klasse stellt im Wesentlichen eine Methode zur Verfügung, mit der eine Assembly mit Hilfe von Assembly.Load() geladen wird, sowie eine Methode zur Durchführung einiger Prozesse. Die Klasse muss in eine separte Assembly kompiliert werden. Die Gründe hierzu erfahren Sie im weiteren Verlauf des Dokuments.

Das Wichtigste an diesem Code finden Sie in der Klasse, die die neue Anwendungsdomäne erstellt:

public class AssemblyLoader: IDisposable 
{
   AppDomain appDomain;

   public AssemblyLoader()
   {
   }

   void Dispose(bool disposing)
   {
      if (appDomain ! = null) 
      {
         AppDomain.Unload(appDomain);
         appDomain = null;
      }
   }

   ~AssemblyLoader()
   {
      Dispose(false);
   }

   public void Dispose()
   {
      Dispose(true);
   }

   public void ProcessAssembly(string filename)
   {
      FileInfo fileInfo = new FileInfo(filename);

      AppDomainSetup setup = new AppDomainSetup();
      setup.ApplicationBase = fileInfo.DirectoryName;
      setup.PrivateBinPath = 
         AppDomain.CurrentDomain.BaseDirectory;
      setup.ApplicationName = "Loader";
      setup.ShadowCopyFiles = "true";

      try
      {
         appDomain = AppDomain.CreateDomain(
            "Loading Domain", null, setup);

        AssemblyProcessor processor = (AssemblyProcessor)
            appDomain.CreateInstanceFromAndUnwrap(
            "AppDomainAssemblyLoader.dll", 
            "AppDomainAssemblyLoader.AssemblyProcessor");

         string name =
            fileInfo.Name.Replace(fileInfo.Extension, "");   
         Console.WriteLine(name);
         processor.Load(name);
         processor.Process();
      }
      Finally
      {
         if (appDomain != null)
         {
            AppDomain.Unload(appDomain);
            appDomain = null;
         }
      }
   }
}

Das Setup der Anwendungsdomäne ist das schwierigste. Die AssemblyProcessor-Klasse verwendet Assembly.Load() zum Aufspüren einer Assembly, die nach Assemblys in der Anwendungsbasis der Anwendungsdomäne sucht. Deshalb muss die Anwendungsbasis dem Verzeichnis zugewiesen werden, das die Assembly enthält. Dies geschieht mit folgender Codezeile:

setup.ApplicationBase = fileInfo.DirectoryName;

Anmerkung Die Anwendungsdomäne kann eigene Regeln für das Laden implementieren, indem eine Verbindung mit dem AssemblyResolve-Ereignis hergestellt wird.

Dieser Code reicht nicht zum Laden der AssemblyProcessor-Klasse aus; er befindet sich jedoch in demselben Verzeichnis wie die aktuelle Anwendungsdomäne. Deshalb setzen wir den PrivateBinPath der neuen Anwendungsdomäne auf das Verzeichnis der aktuellen Anwendungsdomäne.

setup.PrivateBinPath =
AppDomain.CurrentDomain.BaseDirectory;

Jetzt müssen Sie nur noch eine Konfiguration vornehmen. Die Benutzer sollen in der Lage sein, die vorhandenen Assemblys zu überschreiben. Das Problem ist nur, dass alle Assemblydateien nach dem Laden gesperrt sind. Um dies zu umgehen, erstellen Sie eine Kopie der Assemblys in einem anderen Verzeichnis, so dass die Originaldateien nicht gesperrt sind. Die Anwendungsdomäne kann dies automatisch durchführen.

setup.ShadowCopyFiles = "true";

Nach der Definition des Setups der Anwendungsdomäne fahren Sie mit deren Erstellung fort und generieren anschließend eine AssemblyProcessor-Instanz in dieser neuen Domäne:

AssemblyProcessor processor = (AssemblyProcessor)
      appDomain.CreateInstanceFromAndUnwrap(
         "AppDomainAssemblyLoader.dll", 
         "AppDomainAssemblyLoader.AssemblyProcessor");

Rufen Sie CreateInstanceFromAndUnwrap() auf und übergeben Sie den Dateinamen der zu verwendenden Assembly sowie den vollständig qualifizierten Namen des zu erstellenden Typs.

Daraufhin erhalten Sie einen AssemblyProcessor-Proxy für das tatsächliche AssemblyProcessor-Objekt in der neu erstellten Anwendungsdomäne. Dieses Objekt kann genauso wie ein lokales Objekt verwendet werden:

string name = fileInfo.Name.Replace(fileInfo.Extension, "");
Console.WriteLine(name);
processor.Load(name);
processor.Process();

Da Assembly.Load() Assemblynamen erfordert und Dateinamen nicht unterstützt, müssen wir die Erweiterung abschneiden.

Am Ende der Verarbeitung ist die Anwendungsdomäne entladen, was einige Dinge erleichtert. Ich habe zusätzlich noch einen Destruktor und eine IDisposable-Schnittstelle implementiert, obwohl sie für dieses Beispiel nicht notwendig wären.

Nächster Monat

Im nächsten Monat lernen Sie die Beispielanwendung kennen, die mit diesem Code arbeitet. Bitte besuchen Sie unsere neue Community-Site (in Englisch), und nehmen Sie an der C#-Benutzerstudie teil.