Steeds vaker worden communicatieprocessen gedigitaliseerd waarbij gegevens worden omgezet naar een standaard formaat zoals PDF (Portable Document Format). Denk hierbij bijvoorbeeld aan facturaties maar ook managementrapportages et cetera.
Als .NET ontwikkelaar is het niet altijd even eenvoudig informatie te vinden over, hoe de juiste componenten op de juiste wijze toe te passen om dit proces te realiseren. In deze blog probeer ik een duidelijk stappenplan, zonder al te veel detail, weer te geven dat als leidraad kan dienen. De hierbij door Microsoft gehanteerde terminologie is SQL Server Reporting Services (SSRS), Report Builder, Report Viewer, Query Design Tool en Report Designer.
Stap 1: Lokale set aan data definiëren
Het is niet persé noodzakelijk om een lokale set aan data toe te passen. Je kunt er ook voor kiezen om vanuit het rapport direct met de database te communiceren door middel van queries. In dit voorbeeld is gekozen voor het gebruik van een lokale set aan data om de betreffende data met automatische tests te kunnen toetsen.
Binnen de backend (c#) omgeving zijn de klassen DataSet, DataTable en DataView te gebruiken die een in-memory cache van data representeren (namespace System.Data (ADO.NET)). Overigens volstaat het om elke willekeurig klasse met een publieke interface als dataset te definiëren. Deze klasse dien je wel binnen een collectie (namespace System.Collections.Generic) uit te voeren wanneer je deze wilt koppelen aan een tabel of matrix component op het rapport.
Het laden van de gedefinieerde set aan data kan op elke gewenste wijze worden uitgevoerd, bijvoorbeeld door middel van een DataAdapter met SQL queries, ADO.NET/EntityFramework of XML serializer, et cetera. Hierbij dien je altijd de basisregels in acht te nemen ten behoeve van de performance door alleen de werkelijk benodigde data ophalen uit de database met zo weinig mogelijk database calls.
Stap 2: Aanmaken rapport en definieer layout
In Visual Studio maak je een report definition language (rdlc) bestand aan door aan het betreffende project een nieuw Report item toe te voegen. Dit doe je door in de solution explorer met behulp van het contextmenu een nieuw item toe te voegen.
Het formaat van dit bestand is XML en bevat informatie over de datasources, de layout en rapportendata. Een datasource beschrijft de connectie naar de database of naar een lokale set met data. In dit voorbeeld is er gekozen voor een lokale set met data.
Het aanpassen van de layout van het rapport is zeer arbeidsintensief omdat de designer niet de modernste en gebruikersvriendelijkste is te noemen. Zo is het automatisch schalen van de layout niet mogelijk, zodat elke kolom en rij met de hand ingesteld moet worden! Om deze reden is het verstandig om de requirements in een zo vroeg mogelijk stadium helder te krijgen en de layout in één keer op te zetten.
Report Builder is zeer krachtig in het groeperen, sorteren en filteren van de data. Evenals het weergeven van totalen en subtotalen in tabellen (en matrixen) die op het rapport zijn opgenomen. Het is even puzzelen om de werkwijze in de designer door te krijgen, maar het is zeker de moeite waard.
Indien er niet is gekozen voor het toepassen van een lokale set aan data zijn er met behulp van de Query Design Tool, SQL queries op te nemen in de rapporten. Op deze wijze kan de data rechtstreeks in het rapport worden ingeladen. In dit geval dien je een DataSource als connectie naar de database in te stellen. Ook bij gebruik van queries geldt dat groepering, filtering en sortering het best uitbesteedt worden aan het rapport zelf, met als bijkomend voordeel dat de queries compacter blijven. Een van de nadelen van queries in rapporten is o.a. dat je minder controle over de data hebt. Queries kunnen ingewikkeld en onleesbaar worden waardoor onderhoud en uitbreidbaarheid lastig wordt. Een ander nadeel is dat het niet mogelijk is om queries binnen het rapport automatisch te testen.
Stap 3: Definiëren koppelingen
Elk component (tabel, matrix, et cetera) dat wordt toegevoegd aan de rapport-layout, dient te zijn voorzien van een koppeling met een dataset. Een koppeling met een lokale dataset kan worden gelegd via het scherm Report Data of handmatig in de XML van het rapport.
Om een overzicht te krijgen van datasources en datasets die gedefinieerd zijn in het rapport is het venster ‘Report Data’ te openen (onder menuoptie ‘View’). Let op, deze menuoptie is enkel beschikbaar als het rapport de ‘focus’ heeft. Het automatisch bijwerken van de koppeldefinities werkt niet altijd zoals je zou verwachten. Helaas is dit onderdeel erg onstabiel. Om controle over dit proces te krijgen is het raadzaam om de rdlc XML-structuur te leren kennen en gebruiken. Je bent daarmee minder afhankelijk van de nukken van Report Builder.
Nadat de koppelingen in het rapport (front-end) gedefinieerd zijn, dienen de lokale sets aan data vanuit de backend aangeboden te worden aan het rapport. Hiervoor kun je de LocalReport klasse gebruiken (namespace Microsoft.Reporting.WinForms). De sets met data dienen gekoppeld te worden door middel van de property DataSources. Dit is een foutgevoelig onderdeel waarbij de compiler geen ondersteuning biedt bij het toevoegen van verwijzingen naar lokale sets aan data (geen compile-time syntax checking). Om deze reden is het raadzaam, indien er meerdere rapporten zijn, om dit geheel te structureren en de Factory design pattern toe te passen.
Stap 4: Rapport genereren en exporteren
Om een output formaat te genereren naar het gewenste PDF bestandsformaat dient een LocalReport object (namespace Microsoft.Reporting.WinForms/WebForms) aangemaakt te worden om een array met bytes te genereren d.m.v. de LocalReport.Render methode. Er kan hier overigens ook gekozen worden voor andere bestandsformaten zoals CSV, Excel, PowerPoint, XML, et cetera. De array met bytes afkomstig van de LocalReport.Render methode kan nu als bestand, in het gewenste formaat, naar disk worden geschreven. Dit laatste wordt uitgevoerd door de WriteFile methode van de klasse System.IO.File.
Uiteraard is het ook mogelijk om de output van de methode LocalReport.Render, rechtstreeks naar de printer te sturen (gebruik hiervoor System.Drawing.Printing.PrintDocument.Print) of direct weer re geven in de Report Viewer. Indien het een webproject betreft dan is de gegenereerde pdf d.m.v. WebRequest naar de client (gebruiker) te streamen.
Tot slot
Er zijn meer wegen die naar Rome leiden. Uiteraard kun je ook third-party libraries inzetten om eenzelfde doel te bereiken. De voordelen om SQL Server Reporting Services te gebruiken is dat deze standaard is geïntegreerd in Microsoft Visual Studio en is afgestemd met de SQL-server standaarden. Het resultaat is een krachtige en robuuste engine met hoge performance.
Een kanttekening is de stabiliteit van de Report Data tool die de koppeling tussen de design interface met de lokale sets aan data verzorgt. Ook is het onderhoud aan layouts van rapporten in Report Designer arbeidsintensief. Dit zijn zeker zaken om rekening mee te houden als je voor de keuze staat.
Auteur: Sander Huisman / Bergler Competence Center © 2016