Thursday, September 9

On-The-Fly Binaries via ASP.NET

The problem: Allow reports to be arbitrarily generated via a web form. The idea to allow the user to select a report to generate, set a few more options, and then click a "Generate" button to get the report in a PDF embedded in the browser window.

But how to serve something that doesn't exist yet? The first solution that comes to mind is to generate the file on the web server's filesystem, serve it, then delete it. Not particularly elegant, and may not even work if the file system permissions are not set as the developer would like them to be.

Instead we use the magic contained in IO Streams. Or more specifically a .NET MemoryStream. When you're ready to serve your binary include the following code:

MemoryStream mStream = null; // using System.IO
mStream = (MemoryStream)ExportPDFToStream();
Response.Clear();
Response.ContentType = "application/pdf";
Response.Buffer= true;
Response.AddHeader("Content-Disposition",
"inline; filename=Report.pdf");
Response.BinaryWrite(mStream.ToArray());
Response.End();

And that's it. Bear in mind that Response.End() will stop any further processing of the ASP.NET page, and so the runtime will therefore throw "Thread Ending" exceptions if you try to do anything useful after that point. You might also want to incorporate try, catch and finally blocks to make this a bit safer.

The only caveat in using this method is that whichever classes you are using to generate the binary has to be able to export to System.IO.Stream. The cast will do the rest. Fortunately, in my case, Crystal Reports.NET does this (its saving grace, imo).

It's also easy to see how this technique can be generalised to other binaries irrespective of how they were generated. Don't forget to adapt the content types and disposition to your particular circumstance.

Credit to Chris Wong's article here.

1 comment: