Artikel

November 2002 | Artikel

Polymorpher Platzhirsch

(Link zum Artikel: http://www.it-republik.de/dotnet/artikel/0257)

Ein Blick auf die Programmierschnittstellen von Crystal Reports 9

Text: von Andreas Kosch
  • Teilen
  • kommentieren
  • empfehlen
  • Bookmark and Share
Crystal Reports war bereits in Visual Basic 1 integriert und ist seitdem in einer jeweils abge-speckten Fassung ein fester Bestandteil von Microsoft Visual Studio. Selbstverständlich hat sich daran auch in Visual Studio .NET nichts geändert, wobei dies nicht bedeutet, dass andere Entwicklungs-umgebungen außen vor sind. Crystal Reports demonstriert anschaulich die Evolution in der Software-Branche, wie der folgende Blick auf die unterschiedlichen Programmierschnittstellen zeigt.

Als Entwickler mit Delphi-Background habe ich die ganzen Jahre schon im Punkt Report-Generatoren etwas neidisch auf die Konkurrenz geschaut. Crystal Reports ist mit über vier Millionen verkauften Lizenzen das Report-Tool schlechthin, wobei man hier bei exakter Betrachtung zwischen den Einsatzfällen Endanwendung und Entwickler unterscheiden müsste. Bereits beim Setup - vorausgesetzt, Sie wählen die Custom Installation-Option - wird deutlich, dass Crystal Reports nicht nur auf die Microsoft-Entwicklungsumgebungen fixiert ist. Immer dann, wenn zum Beispiel auch Borland Delphi in Version 2 bis 7 vorgefunden wird, bietet das Setup von Crystal Reports 9 Advanced Edition die Installation der entsprechenden Programmierschnittstellen an. Zwar unterstützt Crystal Reports 9 offiziell nur die Delphi-Versionen 2 bis 6, aber die im Sourcecode vorliegenden VCL-Komponenten lassen sich nach einer kleinen Anpassung (siehe Kommentarzeilen im Beispielprojekt D7CRPEDemo.dpr auf der CD) auch in Delphi 7 installieren.

Wie Abpictureung 1 ebenfalls zeigt, aktualisiert das Setup auch die bereits in Microsoft Visual Studio .NET integrierte Version 8.0. Das ist sowohl eine gute als auch eine schlechte Nachricht, wie ein Blick in die recht umfangreichen Release Notes zeigt. Sie sollten der Versuchung widerstehen, die ersten 35 Seiten dieser Hinweise nicht durchzuarbeiten. Außerdem setzt Crystal Reports 9 voraus, dass eine gewisse Reihenfolge bei der Installation eingehalten wird:
  • Microsoft Visual Studio .NET
  • Crystal Reports 9
  • Crystal Enterprise Report Application Server (oder mindestens das RAS-SDK)
Die Anbindung von Crystal Reports innerhalb von Visual Studio .NET funktioniert nur dann vollständig, wenn zuletzt das Report Application Server-SDK ebenfalls auf diesem Rechner installiert wird. Am einfachsten erfüllen Sie diese Forderung, indem Sie gleich den vollständigen Report Application Server 9 (RAS) über die zweite CD-ROM installieren. Als Ergebnis dieser Mühen erhalten Sie eine Entwicklungsumgebung, deren Reporting-Fähigkeiten deutlich über der alten, bereits in VS .NET integrierten Fassung liegt. Da die alten Entwicklungsumgebungen wie Visual Studio 6 oder Borland Delphi -um nur zwei beim Namen zu nennen - auch weiterhin vollständig unterstützt werden, hat man in der heutigen Umbruch-Phase zu .NET ein Werkzeug zur Hand, das diesen Migrations-Prozess begleiten kann.
Ich hatte schon darauf hingewiesen, dass Crystal Reports sehr gut die Evolution in unserer Branche demonstriert. Diese betrifft zwei unterschiedliche Bereiche: Zum einen die Anwendungs-Architektur selbst, da die verschiedenen Modelle 1-Tier (alles in einer Anwendung), 2-Tier (alias Client/Server) und 3-Tier (alias Three-Tier) gleichermaßen unterstützt werden. Selbstverständlich darf auch das Thema Web Service nicht fehlen - der nun unterstütze Report Web Service dient als Reportquelle sowohl für Windows- als auch für Webanwendungen. Aber auch in Bezug auf die Programmierschnittstellen ist die Evolution deutlich erkennbar, nachdem man sich erst einmal einen Überblick verschafft hat. Abpictureung 2 zeigt, welche Optionen zur Wahl stehen. Dieses komplexe Gepicturee kann man in drei Teile untergliedern: COM, Java und .NET.
Eine Webanwendung greift entweder über COM (zum Beispiel aus einer Active Server Page heraus) oder über Java (zum Beispiel über Apache Tomcat 4) auf das Objektmodell von Crystal Reports 9 zu. Bei einer Windows-Anwendung muss man sich für eine der drei Alternativen entscheiden. Der älteste Teil ist die API-Schnittstelle der Crystal Reports Print Engine (CRPE). Da heute niemand mehr direkt mit den API-Funktionen hantieren möchte, stellt Crystal Reports auch sprachspezifische Komponenten für Borland Delphi zur Verfügung, die diese API-Schnittstelle objektorientiert kapseln. Der nächste Entwicklungsschritt erlaubt den sprachunabhängiger Zugriffsweg über binäre COM-Objekte, indem das Objektmodell von Report Designer Component (RDC) die Funktionalität unterstützt. Und am Ende des Entwicklungsprozesses steht der sprachunabhängige Zugriffsweg über .NET-Klassen (Komponenten), wobei sogar Strongly Typed Report-Klassen unterstützt werden.
Damit das für Sie nicht nur leere Worthülsen bleiben, demonstriert jeweils ein kleines Beispiel die ver-schiedenen Zugriffswege. Dabei greife ich für CRPE und RDC auf Borland Delphi 7 zurück und für die .NET-Fassung auf Microsoft Visual Studio .NET. Bei dieser Gelegenheit gehe ich auch auf die erstaunliche Flexibilität von Crystal Reports 9 in Bezug auf die Datenquelle ein.
VCL-Komponente für die CRPE
Wenn das vom Crystal Reports 9-Setup abgelegte Package in Delphi installiert wird, steht die VCL-Komponente TCrpe zur Verfügung. Das folgende Beispiel demonstriert, dass eine Handvoll Programmzeilen ausreichen, um die Report-Vorschau im eigenen Programmfenster anzuzeigen. Nachdem eine TPanel-Instanz als Eltern-Fenster sowie die Report-Datei zugewiesen wurden, legt die DatabaseName-Eigenschaft die auszulesende Datenbankdatei fest. Wird dann die Methode Execute aufgerufen, kann der angezeigte Report entweder aus-gedruckt oder in den Formaten PDF, DOC, XLS, HTML oder XML (um nur einige zu nennen) exportiert werden:
  1. Crpe1.WindowStyle.BorderStyle := bsNone;
  2. Crpe1.WindowParent := Panel1;
  3. Crpe1.ReportName := sAppPath + 'OSD7CR9.rpt';
  4. Crpe1.Connect.DatabaseName := sAppPath + 'OSCR9DEMO.mdb';
  5. Crpe1.Execute;
Für einen Entwickler, der mit Borland Delphi arbeitet, ist das sehr bequem - die ganze Arbeit hat die Firma Crystal Decisions als Hersteller am Hals. Aus der Sicht des Herstellers ist daher der sprachunabhängige Zugriffs-weg über COM-Objekte und ActiveX-Controls der effektivere Weg - denn hier sind keine Anpassungen an ein spezielles Produkt notwendig. Es ist also verständlich, wenn im Entwickler-Handbuch von Crystal Reports 9 der direkte Zugriff auf die CRPE als veraltet bezeichnet wird.
RDC und ActiveX-Viewer
Der neue Zugriffsweg führt Sie direkt in das Objektmodell von RDC, sodass der erste Schritt darin besteht, die Typbibliothek von Report Designer Component 9 (RDC) zu importieren. Da nun die Report-Vorschau über ein separates ActiveX-Control läuft, muss als zweiter Schritt auch das Crystal Reports Viewer Control 9 (Version 9.2) installiert werden. Über die dabei von Delphi angelegten Unit-Dateien CRVIEWER9Lib_TLB.pas und CRAXDDRT_TLB.pas greift das nächste Beispiel direkt auf die COM-Objekte zu (siehe Listing 1). Nachdem eine Instanz des Application-Objekts von RDC angefordert wurde, öffnet die OpenReport-Methode die Report-Datei. Allerdings greift mein zweites Beispiel nicht direkt auf die Datenbank zu, sondern nutzt ein bereits gefülltes Recordset-Objekt von ADO als Datenquelle. Da man ein Recordset völlig unabhängig von einer Datenbank direkt im Programm neu definieren und mit Daten füllen kann, steht so ein verblüffend einfacher Weg zur Verfügung, um beliebige Daten an den Report zu übergeben. Außerdem hat der Zugriff über das Recordset den Vorteil, dass man völlig unabhängig von den Datenbank-Treibern von Crystal Reports ist und an dieser Stelle nichts dazulernen muss:

Listing 1
  1. var
  2. aCRApp : IApplication;
  3. aCRRpt : IReport;
  4. aCRDB : IDatabase;
  5. begin
  6. aCRApp := CoApplication.Create;
  7. aCRRpt := aCRApp.OpenReport(sPath, 0);
  8. aCRDB := aCRRpt.Database;
  9. // bereits gefülltes Recordset-Objekt als Datenquelle nutzen
  10. aCRDB.SetDataSource(FRecordSet, 3, 1);
  11. CRViewer91.ReportSource := aCRRpt;
  12. CRViewer91.ViewReport;
  13. end;
Der in Listing 1 dargestellte Zugriffsweg gilt universell für alle Sprachen. Es macht also an dieser Stelle abgesehen von der Syntax keinen Unterschied, ob Sie mit C++ oder Delphi arbeiten. Sobald allerdings .NET ins Spiel kommt, ändert sich die Situation, denn hier steht ein Managed Wrapper für die CRPE zur Verfügung, sodass aus dem COM-Objektmodell für RDC neue .NET-Klassen werden.
Crystal Reports 9 und .NET
Ein kurzer Blick auf Abpictureung 4 macht deutlich, wie Crystal Reports die Integration in .NET intern umsetzt. Für die Vorschau greifen sowohl die Web Forms (ASP.NET) als auch die Windows Forms auf die selbe Quelle zu. Die Trennung zwischen der Report-Quelle und dem Managed Wrapper der Engine macht Sinn, da sich zwischen diesen beiden Schichten auch eine Rechnergrenze befinden darf - wobei in diesem Fall die Daten über HTTP transportiert werden. Der Wrapper selbst stellt in der .NET-Welt das Objektmodell für die Crystal Reports Print Engine (CRPE) zur Verfügung, die auch in .NET der Hauptbestandteil des Ganzen bleibt.
Bevor Sie nun mit der Bemerkung Also prinzipiell nichts Neues abwinken, schicke ich voraus, dass sich für uns durchaus die Vorgehensweise gravierend ändert, wenn wir auch die neuen Möglichkeiten ausnutzen. Wenn Sie die alternativen Wege selbst ausprobieren möchten, sind die folgenden Vorbereitungen notwendig (eine ausführlichere Beschreibung finden Sie jeweils in der Datei Liesmich.txt in den Unterverzeichnissen der 7 Beispielprojekte für VS.NET):
  • Neues Projekt einer Windows Application
  • Neuen Crystal Reports hinzufügen (Solution Explorer | Add New Item)
  • Standard Report Creation Wizard konfigurieren
  • CrystalReportViewer-Komponente von der Toolbox auf dem Formular ablegen
Um nun den Report in der eigenen Anwendung zu aktivieren, gibt es verschiedene Optionen. Die am Anfang scheinbar einfachste Option besteht darin, im Properties-Fenster die CrystalReportViewer-Eigenschaft ReportSource auf den Pfadnamen der RPT-Datei zu setzen. Das funktioniert zwar, hat aber den Nachteil, dass diese Datei zur Laufzeit an exakt dieser Stelle vorgefunden werden muss. Es ist also gleich besser, die ReportSource-Eigenschaft auf (none) zu belassen und stattdessen direkt die Strongly Typed Report-Klasse zu nutzen. Im Hintergrund hat Visual Studio .NET analog zur Vorgehensweise von ADO.NET im Fall des DataSets für den Report eine eigene Hilfsklasse generiert, die spätestens dann sichtbar wird, wenn Sie im Solution Explorer die Anzeige der verborgenen Dateien aktivieren. Statt die .RPT-Datei als Vorlage zu nehmen, sorgt die Anforderung einer neuen Instanz dieser Report-Klasse im Load-Ereignis des Formulars dafür, dass der Report völlig unabhängig von der RPT-Datei angezeigt wird, denn der Dateiinhalt selbst wird in der Voreinstellung von VS .NET bereits beim Kompilieren zu den Anwendungs-Ressourcen hinzugefügt (siehe Konfiguration von Build Action im Properties-Fenster):
  1. Private Sub Form1_Load(ByVal sender As Object, _<br></br> ByVal e As System.EventArgs) Handles MyBase.Load
  2. CrystalReportViewer1.ReportSource = New OSCustomerDemo1()
  3. End Sub
Was passiert aber, wenn die eigene Anwendung auch die Login-Daten, die für den Zugriff auf die Datenbank benötigt werden, übergeben soll? In diesem Fall müssen Sie die ReportDocument-Komponente von der Toolbox auf das Formular ziehen - VS .NET legt daraufhin im Component Tray-Bereich ein Icon für diese Komponente an. Über diese ReportDocument-Komponente legt die Anwendung für jede Tabelle (der Report darf Daten aus verschiedenen Datenbanken gleichzeitig nutzen) die Login-Daten fest, wobei in meinem Beispiel eine Schleife alle vorgefundenen Tabellen mit den gleichen Daten initialisiert (siehe Listing 2).

Listing 2
  1. Private Sub Form1_Load(ByVal sender As Object, _ <br></br> ByVal e As System.EventArgs) Handles MyBase.Load
  2. ' Step 1: Login-Daten übergeben
  3. Dim aCREngTbl As CrystalDecisions.CrystalReports.Engine.Table
  4. Dim aCRTLOI As CrystalDecisions.Shared.TableLogOnInfo
  5. For Each aCREngTbl In osLoginDemo21.Database.Tables
  6. aCRTLOI = aCREngTbl.LogOnInfo
  7. With aCRTLOI.ConnectionInfo
  8. .ServerName = "(local)"
  9. .UserID = "sa"
  10. .Password = "sa"
  11. .DatabaseName = "Northwind"
  12. End With
  13. aCREngTbl.ApplyLogOnInfo(aCRTLOI)
  14. Next aCREngTbl
  15. ' Step 2: ReportSource verbinden
  16. CrystalReportViewer1.ReportSource = osLoginDemo21
  17. End Sub
Übergibt das Programm im Sourcecode ein falsches Passwort, zeigt das Programm zur Laufzeit trotzdem automatisch den Login-Dialog mit dem leeren Passwortfeld an, sodass nach dem korrekten Passwort-Eintrag der Report erfolgreich genutzt werden kann.
Gibt es aber auch ein vergleichbares Gegenstück zu meinem Recordset-Beispiel für RDC? Selbstverständlich - wie das nächste Beispiel zeigt. Nachdem das DataSet OsDatasetReport1 mit dem Ergebnis der SELECT-Abfrage aus der Datenbank gefüllt wurde, füge ich zur Demonstration im Programm zwei neue Datensätze hinzu, wobei als Land jeweils die Zeichenkette S&S eingetragen wird. Die ReportDocument-Komponente wird auch hier dazu genutzt, die Datenquelle festzulegen. Beim Aufruf der Methode SetDataSource übergebe ich den Namen der gefüllten DataSet-Instanz, sodass der Viewer auch die beiden neu hinzugefügten Datensätze anzeigt (siehe Abb. 5). Außerdem demonstriert dieses Beispiel, wie das Ergebnis auch als PDF-Datei direkt aus dem Programm heraus exportiert werden kann (siehe Listing 3).

Listing 3
  1. Private Sub Form1_Load(ByVal sender As Object, _<br></br> ByVal e As System.EventArgs) Handles MyBase.Load
  2. SqlDataAdapter1.Fill(OsDatasetReport1)
  3. ' Zum Test 2 neue Datensätze dem DataSet hinzufügen
  4. OsDatasetReport1.Customers.AddCustomersRow("KOSCH", "OssiSoft", "Andreas Kosch", _
  5. "Entwickler", "Irgendwo", "Überall", "Thüringen", "99869", "S&S", "leer", "leer")
  6. OsDatasetReport1.Customers.AddCustomersRow("DYNDS", "DataRow:", "Dynamisch generiert", _
  7. "Laufzeit", " ", " ", " ", " ", "S&S", " ", " ")
  8. ' Erweitertes DataSet als Datenquelle für den Report zuweisen
  9. osCustomerDemo11.SetDataSource(OsDatasetReport1)
  10. CrystalReportViewer1.ReportSource = osCustomerDemo11
  11. ' Report als PDF-Datei exportieren
  12. MessageBox.Show("Export als PDF-Datei wird gestartet...", "Crystal Report 9")
  13. Dim aCRDFDO As New CrystalDecisions.Shared.DiskFileDestinationOptions()
  14. Dim sFileName As String = "C:\Temp\DataSetReport.pdf"
  15. aCRDFDO.DiskFileName = sFileName
  16. With osCustomerDemo11
  17. .ExportOptions.ExportDestinationType = _
  18. CrystalDecisions.Shared.ExportDestinationType.DiskFile
  19. .ExportOptions.ExportFormatType = _
  20. CrystalDecisions.Shared.ExportFormatType.PortableDocFormat
  21. .ExportOptions.DestinationOptions = aCRDFDO
  22. .Export()
  23. End With
  24. MessageBox.Show("...Export als PDF-Datei ist fertig!", "Crystal Report 9")
  25. End Sub
Ein DataSet als Datenquelle ist extrem flexibel, da man über diesen Weg zum Beispiel auch eine Stored Procedure als SELECT-Datenquelle verwenden kann, ohne sich um die Übergabe der Parameter auf dem Crystal Reports-Weg kümmern zu müssen. Dabei muss das DataSet selbst gar nicht von einer Datenbank abhängen, über den Solution Explorer und den XML Schema Designer dürfen Sie das DataSet auch völlig neu in eigener Regie zusammenbauen und mit eigenen Daten füllen. Wesentlich ist nur, dass unabhängig von der Datenquelle die Vorgehensweise beim Anbinden an den Report immer identisch ist - die Einarbeitungszeit für uns als Entwickler wird entsprechend kürzer.
Report Web Services (RWS)
Den Abschluss pictureet ein Beispielprojekt für einen Report Web Service, auf den sowohl eine ASP.NET-Anwendung (Web Forms) als auch eine Windows-Anwendung zugreifen, um das Ergebnis im Report Viewer anzuzeigen. Mit diesem Satz ist auch die Katze aus dem Sack: Ein RWS muss immer an den Crystal Reports Viewer gebunden werden. Dafür wird er aber kinderleicht zusammengebaut. Es reicht aus, sofort nach dem Anlegen eines neuen ASP.NET Web Service-Projekts eine bereits vorhandene RPT-Datei über den Solution Explorer hinzuzufügen und über die rechte Maustaste als Web Service zu veröffentlichen (Menüpunkt Publish as Web Service). Sowohl bei einem Web Form als auch bei einem Windows Form stellt die Toolbox die Komponente CrystalReportViewer zur Verfügung, sodass über deren Eigenschaft ReportSource entweder direkt die URL des Web Services als Zeichenkette übergeben wird oder aber über die über New angeforderte Instanz der Proxy-Klasse, welche VS .NET beim Import des Web Services automatisch generiert hat. Abpictureung 6 zeigt das Ergebnis - sowohl die vom Report Web Service verwendete RPT-Vorlage als auch die vom Report ausgewertete Datenbank stammt aus einem Beispielprojekt für den Report Application Server (RAS).
Was gibt's Neues in Crystal Reports 9?
Mit Version 9 von Crystal Reports erhebt Crystal Decisions den Anspruch, jedem Benutzer überall und zur jeden Zeit über ein beliebiges Gerät die Darstellung und Analyse von Daten zu erlauben. Je nach der Produktversion (Standard, Professional, Developer oder Advanced Edition) stehen dazu verschiedene Optionen und Werkzeuge bereit. Über eine Repository-Datenbank werden zum Beispiel Vorlagen und Funktionen effektiv wiederverwendet und auch die Smart Tags von Microsoft Office werden unterstützt. Für eine vollständige Auflistung aller Neuheiten und die Unterschiede zur bereits in VS .NET integrierten Version reicht der Platz nicht aus - auf den Webseiten von Crystal Decisions (siehe [1]) können Sie Ihren Informationshunger jederzeit stillen.

Auf der CD-ROM finden Sie zwei Beispielprojekte für Delphi und 7 Beispielprojekte für VS .NET vor. Selbst dann, wenn Ihnen Crystal Reports 9 nicht zur Verfügung steht, lässt sich die Hälfte der .NET-Beispiele auch mit der standardmäßig in VS .NET integrierten Crystal Reports-Version nachvollziehen.
Links und Literatur
[1] http://www.crystaldecisions.com/products/crystalreports/


Anzeige

Kommentare

zurück zum Seitenanfang