.NET Komponenten in COM+ Clients einsetzen
Geschrieben von: Christoph Wille Mit dem .NET Framework sind Funktionen in die Griffweite eines jeden Programmierers gerückt, von denen man noch vor nicht allzu langer Zeit nur träumen durfte. Trotz all dieser neuen Features kann man meist seine alten Applikationen nicht einfach wegwerfen und in .NET neu schreiben, sondern man muß sie weiterwarten. Dieser Artikel zeigt, wie man seine existierende Applikation mit in .NET geschriebenen Komponenten verbinden kann. Viele existierende VB6 oder ASP Applikationen werden uns noch Jahre begleiten, doch sind in diesen Programmiersprachen bestimmte Dinge nur schwer oder gar nicht realisierbar. Diese gleichen Aufgaben sind jedoch in .NET in wenigen Zeilen erledigt; wie kann man also neuen .NET Code in seine existierende Anwendung bringen? Die Antwort sind COM Callable Wrapper, kurz CCW. COM Callable WrapperDer Name ist Programm: der COM Callable Wrapper ist nichts anderes als ein Wrapper rund um unsere .NET Komponente, damit sie von VB6 und anderen COM Clients aus angesprochen werden. Ein CCW ist das Gegenstück zum Runtime Callable Wrapper (RCW), den wir bereits im Artikel Verwenden von COM Komponenten in ASP.NET näher betrachtet haben. Was alles muß man für CCW's beachten? Nun, es gibt einige wichtige Punkte:
Weiters sollte die Assembly, in der die .NET Komponente lebt mit einem Strong Name versehen sein, und der Einfachheit halber im Global Assembly Cache (GAC) abgelegt sein. BeispielAls Beispiel verwenden wir die ImageInfo Klasse aus dem Artikel Bildinformationen selbst ermitteln, die wir um einige Best Practices für CCW's erweitern werden. Beginnen wir mit dem erwähnten Strong Name. Dieser legt die Identität der Assembly kryptographisch fest, und für diese Prozedur benötigen wir ein Schlüsselpaar, das man mit dem sn Utility erzeugen kann: F:\Inetpub\wwwroot\AspHeute\dotnetccw>sn -k ImageInfo.key Microsoft (R) .NET Framework Strong Name Utility Version 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. All rights reserved. Key pair written to ImageInfo.key Der weitere Teil der Prozedur ist einfach, weil den Großteil der Compiler erledigt - man muß dem Compiler nur mitteilen, daß er das Schlüsselpaar zur Erzeugung des Strong Names verwenden soll. Dies geschieht am besten in einer separaten Datei (der Übersichtlichkeit halber), die man AssemblyInfo.cs nennen sollte: using System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("ImageInfo")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("AlphaSierraPapa")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("(c) 2002 Christoph Wille")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyDelaySign(false)] [assembly: AssemblyKeyFile("ImageInfo.key")] Die letzte Zeile sorgt dafür, daß der Compiler automatisch den Strong Name anlegt. Damit, und mit einer korrekten Versionsnummer, ist man dann später in der Lage, die Assembly in den GAC (Global Assembly Cache) zu installieren. So weit sind wir aber noch nicht, wir müssen die Komponente noch ein wenig anpassen. Die im Artikel Bildinformationen selbst ermitteln vorgestellte ImageInfo Komponente entspricht noch nicht ganz unseren Vorgaben. Wir sollten für eine schnelle Zerstörung der "teuren" Bitmapresource sorgen (mittels Dispose Pattern), einen Konstruktor anlegen, und auch die Methoden explizit für COM markieren. Beginnen wir bei den leichten Dingen, dem Konstruktor (ImageInfo.cs): // Ein öffentlicher Konstruktor muß vorhanden sein public ImageInfo() { m_bmpRepresentation = null; } Nun markieren wir alle Methoden mit dem ComVisible Attribut. Da wir keine Methode verstecken wollen, könnte man argumentieren, daß dieser Schritt unnotwendig ist. Er hat aber einen guten Grund: jeder, der den Code später liest weiß, daß diese Komponente für die Verwendung in COM Applikationen vorgesehen ist, und er keine Änderungen machen sollte, die diese Verwendung verhindert. Außerdem kann man mit externen Tools die Attribute auslesen, was zB für die Dokumentation wichtig sein kann. Für die beiden Eigenschaften sieht unser Code dann so aus: [ComVisible(true)] public int Height { get { return m_bmpRepresentation.Height; } } [ComVisible(true)] public int Width { get { return m_bmpRepresentation.Height; } } Es ist kein großer Aufwand, dokumentiert aber die Absicht des Programmierers. Klarerweise kann man mit false als Argument zum Attribut eine Methode verstecken (zB falls diese für COM Applikationen keinen Sinn machen würde). Kommen wir zum letzten Punkt, dem Dispose Pattern. Ein Bitmap Objekt ist teuer, weil es viele Resourcen verbraucht. Daher sollte man es nach Verwendung wieder freigeben, und hier setzt der Dispose Pattern an - er definiert, was man in seine Klasse einbauen muß, damit jeder das Objekt deterministisch zerstören kann (der Dispose Pattern wird auch gerne als DF, Deterministic Finalization, bezeichnet). Ich habe die einfachste Variante gewählt, indem ich von der Component Klasse abgeleitet habe, und deren Dispose Methode überlade: using System.ComponentModel; // für Component Basisklasse public class ImageInfo : Component { protected override void Dispose(bool disposing) { if (disposing) { // explizit aufgerufen, wir können das Bitmap weggeben if (null != m_bmpRepresentation) m_bmpRepresentation.Dispose(); // Dispose könnte mehr als einmal aufgerufen werden, daher setzen // wir die zerstörte Referenz auf null m_bmpRepresentation = null; } base.Dispose(disposing); } [ComVisible(true)] public void Close() { Dispose(); // Close ruft nur Dispose auf } Für einige Programmierer ist es ein "Problem", ein Objekt "wegzuwerfen". Für viele ist es natürlicher, ein Objekt zu schließen, was speziell für Dateien oder Datenbankverbindungen zutrifft. Deshalb kann man - man muß nicht - zusätzlich zu Dispose weitere synonyme Methoden anbieten (hier Close). Damit sind die Änderungen beendet, wir müssen die Komponente nun kompilieren: csc /out:ImageInfo.dll /target:library ImageInfo.cs AssemblyInfo.cs /r:System.Drawing.dll /r:System.dll Dadurch erhalten wir die Assembly mit einem Strong Name, die wir nun für COM registrieren können. CCW erstellen und registrierenDie Schritte zum CCW sind bestechend einfach - prinzipiell ist es nur der Aufruf des regasm Tools: F:\Inetpub\wwwroot\AspHeute\dotnetccw>regasm ImageInfo.dll /tlb:ImageInfo.tlb Microsoft (R) .NET Framework Assembly Registration Utility 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. All rights reserved. Types registered successfully Assembly exported to 'F:\Inetpub\wwwroot\AspHeute\dotnetccw\ImageInfo.tlb', and the type library was registered successfully Allerdings kann man leicht in Probleme laufen, wenn man die Assembly dann nicht in den GAC installiert (Pfade). Deshalb sollte man noch F:\Inetpub\wwwroot\AspHeute\dotnetccw>gacutil /i ImageInfo.dll Microsoft (R) .NET Global Assembly Cache Utility. Version 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. All rights reserved. Assembly successfully added to the cache ausführen. Damit ist die Assembly von allen Applikationen aus verwendbar, und ein potentielles Problem ausgeräumt, das einem stundenlange Fehlersuche bereiten kann. .NET Komponente verwendenAls Beispiel habe ich die .NET Komponente im Windows Scripting Host verwendet (es soll ja so einfach wie möglich sein). Die ProgId einer .NET Komponente ist Namespacename.Classname, also in unserem Falle AspHeute.ImageInfo. Damit sieht der Sourcecode in demo.vbs so aus: strImageFile = "myImage.jpg" bLoadedOK = True Set imgInfo = WScript.CreateObject("AspHeute.ImageInfo") On Error Resume Next imgInfo.Load strImageFile If Err.Number <> 0 Then Wscript.Echo Err.Description bLoadedOK = False End If If (bLoadedOK) Then Wscript.Echo "Breite: " & imgInfo.Width & ", Höhe: " & imgInfo.Height & ", Bildformat: " & imgInfo.Format End If imgInfo.Close Set imgInfo = Nothing Dieser Code kann auch in VB6 oder Office Applikationen eingesetzt werden. Und schon hat man Funktionalität in seiner alten Applikation, von der man ohne externe Komponente nur träumen konnte. SchlußbemerkungDieser Artikel soll als Kochrezept und Ermunterung dazu dienen, existierende Anwendungen mit in .NET geschriebenen Komponenten zu erweitern und zu verbessern. Der Nutzen steht einem sehr geringem Aufwand gegenüber. Download des CodesKlicken Sie hier, um den Download zu starten. Verwandte Artikel
Bildinformationen selbst ermitteln Wenn Sie jetzt Fragen haben...Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten. Eine weitere sehr hilfreiche Resource ist das deutsche ASP.NET Wiki, das als zentrale Anlaufstelle für Tips, Tricks, Know How und alles Nützliche was man in seinem Alltag als (ASP).NET-Entwickler so braucht und entdeckt gedacht ist. Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.
Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.
©2000-2006 AspHeute.com |