Using a Windows Azure worker role to generate reports using Azure Reporting

Using a Windows Azure worker role to generate reports using Azure Reporting

While trying to reproduce an issue in Azure Reporting, I found myself building a simple worker role that generated a report using the ReportViewer control in server mode. I found a couple gaps in the overall content available, so I thought I would try to post a more complete example here.

NOTE: I am assuming that you know how to create an Azure deployment and an Azure Reporting instance, plus design and publish a basic report.

The first thing I had to do was create a basic report. The report and the datasource look like this:

I then published this report and the associated data source to my Azure Reporting Instance using the built-in BIDS functionality.

Next, I created a Windows Azure Worker Role project. Because Azure Reporting is protected by Forms Authentication, I had a to add a custom class to manage the user credentials. Although I modified the code a bit so I didn’t have to hardcode the credentials, it is pretty much identical to the MSDN documentation on this class. However, because the MSDN code sample is missing the Using statements, here is the complete code:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using Microsoft.Reporting.WebForms;

using System.Net;

using System.Security.Principal;

namespace WebRole1

{

/// <summary>

/// Implementation of IReportServerCredentials to supply forms credentials to SQL Reporting using GetFormsCredentials()

Next, I had to write the worker role code. Again, this code is stock worker role code with the exception of the code inside the Run method. The ReportViewer manipulation code is stock ReportViewer code from MSDN as is the blob storage code.

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Net;

using System.Threading;

using Microsoft.WindowsAzure.Diagnostics;

using Microsoft.WindowsAzure.ServiceRuntime;

using Microsoft.WindowsAzure.Storage;

using Microsoft.WindowsAzure.Storage.Auth;

using Microsoft.WindowsAzure.Storage.Blob;

using Microsoft.Reporting.WebForms;

using System.IO;

namespace WorkerRole1

{

publicclass WorkerRole : RoleEntryPoint

{

publicoverridevoid Run()

{

// This is a sample worker implementation. Replace with your logic.

Trace.WriteLine("$projectname$ entry point called", "Information");

while (true)

{

try

{

Trace.WriteLine("Rendering a report", "Information");

//Instantiate an instance of the ReportViewer control

//Since all I am doing is rendering, this is much easier than doing SOAP API calls

Those of you who are paying close attention might have noticed that I use RoleEnvironment.ConfigurationsSetting(“XXXXX”) for all of my passwords, connection strings, etc. This is handy because it allows me to configure those values at run time instead of design time using standard Windows Azure methods. You can edit these either via the Windows Azure portal in production or in Visual Studio during development. Here’s what the Visual Studio dialog looks like:

Now, here is the tricky part. Because I elected to use the ReportViewer control, I need to ensure that the ReportViewer assemblies are accessible to my Windows Azure role. They aren’t part of the standard Azure deployment so that leaves me with two choices:

Add a startup task to install the ReportViewer control

Upload copies to the assemblies as part of my deployment

Option 1 isn’t very difficult, but I wanted to minimize the size of my deployment package, so I elected to go with option 2. The easy part was to make sure the the Copy Local setting of the Microsoft.ReportViewer.Common and Microsoft.ReportViewer.WebForms assemblies was set to True. Doing the same for Microsoft.ReportViewer.DataVisualization and Microsoft.ReportViewer.ProcessingObjectModel was a bit trickier because they live in the GAC. First, I had to manually copy them out of the GAC and into my project folder and then I had to add explicit references the local copies of these assemblies. Lastly, just like the other ReportViewer assemblies, I had the ensure that the Copy Local property was set to True.

Now, after deploying my worker role to Azure using standard techniques I could watch my blob storage and see reports being generated from my worker role.

At this point, I want to take a minute and plug Windows Azure’s scalability. By increasing the number of instances behind my worker role to 50 (just a simple configuration change), I was able to generate more than 60K reports over the course of the next 8 hours. Then, once my testing was done, I deleted the deployment. Try configuring 50 on-premises machines and then finding a new home for them after just 8 hours. You will probably find lots of people who will take them, but good luck getting paid anywhere near the purchase price!

Thankyou for outlining the 2 choices for getting local reporting to work. The error messages are not very conclusive if you forget to set copy local on the report viewer dlls, took a while, eventually we enabled remote desktop so we could remote in and view the local event logs. Felt like such a noob.

Although we acheived this before your i read your blog, I hope other people starting out find it as it's the first concise article that shows all the code neccessary to render Azure Reports using the report viewer control.

I am confused by the application of a worker role, we used a web role basically so we could embed our reports in office 365 applications without users having to login to the Azure reporting instance.

Worker role does however demonstrate how you could implement your own custom report schedules, this is something I will be investigating next.

I am glad this was helpful. I wrote it because I ran into the same issue you did and was frustrated because the other samples didn't have all the details necessary. I did a worker role just to demonstrate the concept. If you needed end user interaction, you could certainly use a web role.