Thursday, February 17, 2011

Data Dynamics Reports: One touch printing on the web

Preface
Some time ago I blogged around ideas on no-touch printing on the web in ActiveReports. A lot of the new features were added in both of ActiveReports and Data Dynamics Reports since from that blog post was published. Particularly we have updated PDF export capabilities so that they allow performing one touch printing easily. In this article I will explain it in details.

The problem
Let's imagine that we have the simple Html page. It hosts the list of the product categories(obtained from Northwind database, Categories table) and "Print" button. We need to implement the following functionality: a user selects the category, clicks Print, the server returns the PDF document that shows the list of the products from the selected category(obtained from Northwind database, Products table), PDF document starts printing immediately - a user should get the print dialog of PDF viewer and the document should not be opened in the viewer.

One-touch printing in action
Let's create the web-site that implements the functionality described in "Problem" section:
products.xml(change the extension to Rdlx) is the report that accepts category id parameter and displays the list of the products accordingly. Copy products.rdlx in the root folder of the web-site.
Now copy default.htm in the root folder of the web-site and let's look at the page body:

<body>
<label>Select the category to print the list of the product of:</label><br />
<select id="categoryList">
<option value="1">Beverages</option>
<option value="2">Condiments</option>
<option value="3">Confections</option>
<option value="4">Dairy Products</option>
<option value="5">Grains/Cereals</option>
<option value="6">GMeat/Poultry</option>
<option value="7">Produce</option>
<option value="8">Seafood</option>
</select>
<input id="btnPrint" type="button" value="Print" />
<script>
$("#btnPrint").click(function() {
var catId = $("#categoryList").val();
$("#pdfContentPlaceHolder").attr("src", "GetData.aspx?catID="+catId);
});
</script>
<iframe style="visibility:hidden" id="pdfContentPlaceHolder" width="0" height="0" />
</body>

So, in the handler of of Print button click we set the source of the invisible frame to the data that are returned by GetData.aspx page. Once the document is loaded in the frame, the printing should start immediately. How is it achieved? Copy GetData.aspx in the root folder of the web-site and let's look at its Page_Load code:

void Page_Load(object sender, EventArgs e)
{
int catId;
if(!int.TryParse(Request.QueryString["catId"], out catId))
{
Response.Write("Invalid category Id parametere value! No output you will get");
return;
}
var fi = new FileInfo(Server.MapPath("~/Products.rdlx"));
var def = new ReportDefinition(fi);
var runtime = new ReportRuntime(def);
runtime.Parameters[0].CurrentValue = catId;
var pdf = new PdfRenderingExtension();
var streams = new MemoryStreamProvider();
var settings = (pdf as IConfigurable).GetSupportedSettings().GetSettings();
settings["PrintOnOpen"] = "true";
runtime.Render(pdf, streams, settings);
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "inline; filename=products.pdf");
using(var stream = streams.GetPrimaryStream().OpenStream())
{
var len = (int)stream.Length;
var bytes = new byte[len];
stream.Read(bytes, 0, len);
Response.BinaryWrite(bytes);
}
}

The code is quite trivial, there are two relatively new features in use though:

  • MemoryStreamProvider allows to export the reports to the memory instead of the disk files. It is pretty convenient for web-scenarios where you don't want to use file system aggressively.

  • We set PrintOnOpen setting of PDF export to true. It will force PDF document to start printing immediately once it is loaded in the invisible frame on default.htm

The task is completed.


ActiveReports
It is possible to use the same technology in ActiveReports. The setting for PDF export filter document option is called OnlyForPrint, it is hidden in the intellisence, but you can use it:

PdfExport pdf = new PdfExport();
pdf.PdfDocumentOptions.OnlyForPrint=true;

No comments:

Post a Comment