HTML Report Generation by making an application a Web Server.
This post may turn into article once I've got more time so this may just cover the concept rather that giving technical details and code samples. In my last post Printing shortcut in .NET v2.0 (windows apps) I wrote about how you can use HTML and the WebBrowser control to make reporting and printing a little bit easier in Windows applications.
The application I tried this on was driven by XML data so it made producing HTML very straighforward.
Over the last couple of days I've been working on a method of building a reporting system into the same application that allowed the definition, generation, and printing of a collection of HTML based reports. Unfortunately at the moment the number of reports is unknown and all I know is the types of reports will change after deployment. So that meant I needed a way to create new reports without needing to recompile the application.
The application needed to dynamically create an HTML report from it's internal XML based on a collection of parameters that describes the report and how to generate it. The application needed to be a web server.
You can built a web sever into an application using the System.Net.HttpListener class. It's a relatively straightforward class and it's very easy to use. Here's an example taken from Patrick Smacchia's Practical .NET 2.0 book.
HttpListener httpListener = new HttpListener();
string uri = string.Format( "http://localhost:8008/hello/" );
httpListener.Prefixes.Add(uri);
httpListener.Start();
while (true) {
// Blocking method...
HttpListenerContext ctx = httpListener.GetContext();
ctx.Response.ContentType = "text/html";
TextWriter writer = new StreamWriter(
ctx.Response.OutputStream, System.Text.Encoding.Unicode);
writer.WriteLine(
"<html><body><b>Page asked at {0}</b><br/>URL:{1}</body></html>",
System.DateTime.Now, ctx.Request.Url);
writer.Flush();
writer.Close();
}
The important thing is the HttpListeners.Prefixes property. These are the urls you register as the ones handled by the web server. Another important object is the HttpListenerContext object. This contains information about the Request, the Response, and the User. You could think of this is a small HttpContext object. It even contains information on the QueryStrings passed on the url and this was the key to building the reporting system.
In order to tell the application to build and display a HTML report the reporting system needed a way to pass parameters defining things like the XSLT script used to create the HTML report, a report title, and so on. Of course thats what QueryStrings are for.
So the concept is easy, have the applications data accessible as XML, create a XSLT stylesheet to build a report from this XML, have your application listen to a single [localhost] prefix, use this prefix to request a report using QueryStrings to pass parameters about the report (it's XSLT script location, title, etc), and on handling the request process the XML with the XSLT stylesheet and return the HTML report.
So for example registering the prefix http://localhost:8080/application.report allows you to generate an HTML report using a url similar to...
http://localhost:8080/application.report?xslt=SalesSummary.xslt&title=Sales%20%Summary
The whole idea becomes even more useful when you use the WebBrowser control. Setting the controls url to the above will display the report on the user interface and by adding JavaScript to the report lets you create some dynamic elements, CSS for formatting and so on. The example below shows a screenshot of a Fault Summary report used by the application. It reports the descriptions and type of all the user input faults made in the application.
http://localhost:8080/application.report?xslt=FaultsSummary.xslt&title=Faults%20%Summary
