Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs
ASP German Homepage Homepage
 

Liste

.NET 2.0 (1)
.NET Allgemein (16)
.NET Fu (5)
ADO.NET (11)
Aprilscherz (3)
ASP Grundlagen (44)
ASP Tricks (83)
ASP.NET (44)
ASPIntranet.de (5)
C# (28)
Datenbank (44)
Dokumentation (4)
IIS 6.0 (1)
Komponenten (29)
Optimierung (10)
Server (21)
Sicherheit (34)
Tee Off (6)
VB.NET (6)
WAP (8)
Web Services (11)
XML (9)

RSS 2.0 - Die neuesten fünf Artikel auf AspHeute.com


 

Suchen





 

English Articles
Chinese Articles
Unsere Autoren
 
Link zu AspHeute
Impressum
Werben
Anfragen

.NET Komponenten in COM+ Clients einsetzen

Geschrieben von: Christoph Wille
Kategorie: .NET Allgemein

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 Wrapper

Der 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:

  • Die Klasse muß einen öffentlichen (public) Konstruktor haben.
  • Nur öffentliche Instanzmethoden können von außen angesprochen werden.
  • Statische Methoden oder Eigenschaften sind prinzipiell nicht ansprechbar.

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.

Beispiel

Als 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 registrieren

Die 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 verwenden

Als 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ßbemerkung

Dieser 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 Codes

Klicken Sie hier, um den Download zu starten.

Verwandte Artikel

Bildinformationen selbst ermitteln
Eine kleine Bilddatenbank, Teil 1
On-the-fly Generierung von Graphiken
Scrapen von Webseiten
Thumbnailgenerierung in .NET
Verwenden von COM Komponenten in ASP.NET
WHOIS Abfragen a la .NET

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.

Bewerten Sie diesen Artikel
 Sehr gut   Nicht genügend  
   1  2  3  4  5  
 

  
   Für Ausdruck optimierte Seite

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.