You are reading a MIX Online Opinion. In which we speak our minds. Karsten Januszewski Meet Karsten Arrow

Lab Notes

7Comment Retweet

Using the ASP.NET Chart Control With Multiple Web Roles In Windows Azure

May 20, 2010 In Development By Karsten Januszewski

I use the ASP.NET Chart Control in Azure in an ASP.NET page with both markup and code-behind. I do this because the chart control overlays hrefs and tooltips on the chart. (Check out this post for a little more about how I use the charts: http://visitmix.com/LabNotes/ASPNET-Charts-and-ASPNET-MVC–Controller-vs-View.)

Things work fine if I configure the chart control to generate images in memory. But, with more than one web role, things break. This is expected, as the documentation states:  “Do not use this [the memory storage] option in a server cluster or a multiple-process site.”

Somehow, I need to store the image to disk instead of memory, and then let the chart control know where to do it. Azure supports writing to disk through what they call a ‘local resource’, so I started using a LocalResource. But I kept hitting the following problem: I don’t know the path to the LocalResource until runtime, but the Chart Control expects this information to be in the Web.Config file. And, if I changed the Web.Config at runtime, Azure got very unhappy.

I looked into using XDrive, which is similar to using a LocalResource, but the same problem ensued.  Each web role ended up mounting its own drive,and the drive letter became dynamic. I need to know it to pass that drive letter to Web.Config.

But I found a solution: I just implement my own instance of IChartStorageHandler and have it point to blob storage. Here’s what the code looks like:

    public class ChartImageHandler : IChartStorageHandler
    {
        CloudStorageAccount account;
        CloudBlobClient client;
        CloudBlobContainer tweetContainer;
        public ChartImageHandler()
        {
            //wire up azure
            account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
            client = account.CreateCloudBlobClient();
            tweetContainer = client.GetContainerReference(Urls.archiveContainer);

        }
        #region IChartStorageHandler Members

        public void Delete(string key)
        {
            CloudBlob image = tweetContainer.GetBlobReference(Urls.imageURL + key);
            image.Delete();
        }

        public bool Exists(string key)
        {
            bool exists = true;
            WebClient webClient = new WebClient();
            try
            {
                using (Stream stream = webClient.OpenRead(Urls.imageURL + key))
                { }
            }
            catch (WebException)
            {
                exists = false;
            }
            return exists;
        }

        public byte[] Load(string key)
        {
            //sometimes load gets called before save is done

            CloudBlob image = tweetContainer.GetBlobReference(Urls.imageURL + key);
            byte[] imageArray;
            try
            {
                imageArray = image.DownloadByteArray();
            }
            catch (Exception)
            {
                System.Threading.Thread.Sleep(1000);
                imageArray = image.DownloadByteArray();

            }
            return imageArray;
        }

        public void Save(string key,byte[] data)
        {
            CloudBlob image = tweetContainer.GetBlobReference(Urls.imageURL + key);
            image.UploadByteArray(data);
        }

        #endregion
    }

Implementing this interface turns out to be pretty easy, especially because the Azure Storage Client CloudBlob class supports DownloadByteArray and UploadByteArray. Because the signature of the interface uses byte[] all over the place, this comes in real handy. Thanks Azure Storage Client!

You’ll note that I’m using this static Urls.imageURL for pointing to blob storage. This string is simply a path to a container in Azure.

The only tricky bit is that sometimes the Load method gets called before the Save function is finished. This is probably because of the latency with blob storage, which is going to be a little slower than writing to disk. I deal with this by adding try/catch. This simply puts a 1 second sleep delay in the call before trying to download the image. This solves the problem, and I’ve never seen the Save function take any longer than that.

I then update the web.config to specify that the ChartImageHandler key passed the fully qualified namespace and location of my handler, instead of the default handler.

And now I can use the ASP.NET Chart Control in Windows Azure with multiple web roles. Rockin.

Follow the Conversation

7 comments so far. You should leave one, too.

Sanjay Sanjay said on May 21, 2010

Thank you for sharing your learning Karsten. I feel, blob storage might incur some performance overheads in comparison to file storage under heavy load. I hope ASP.NET/ Chart team is reading your post and they will make charts ''Azure Compatible'' in next release :)

Aji Issac Aji Issac said on Jun 12, 2010

Thanks for the post but I was always inclined towards fancy graphs

Have you tried http://www.fusioncharts.com/aspnet/ (The product used by Google, FB and over 14000 top fellows) ... What I like the most is the simplicity it offers to the developers.

Peter Grimshaw said on Aug 2, 2011

You post was offered as a solution on the Azure forum as it is seems to be the only way to get this to work (so Bravo!).

I would love to see some more code to help implement this (having not played with the Blob storage service), any chance you could provide a working example?

karstenj said on Aug 3, 2011

@Peter Grimshaw -- Check out all the code from The Archivist: http://archive.msdn.microsoft.com/archivist/Release/ProjectReleases.aspx?ReleaseId=4417

That's where I implement the charts as discussed above. For example, see any detail screen from The Archivist, aka: http://archivist.visitmix.com/irhetoric/131

The key file to check out is ArchivistWeb/Controllers/VisualizationController.cs -- in particular the GetChart() method. This is where I build up the chart (programmatically) and then save it out to storage and return it to the view:

MemoryStream imageStream = new MemoryStream();
chart.SaveImage(imageStream, ChartImageFormat.Png);
return File(imageStream.GetBuffer(), @"image/png");

I use a slightly different methodology for the "big charts", aka: http://archivist.visitmix.com/irhetoric/131/User

Here, the charts are declared in the ArchivistWeb/Views/*.aspx pages with code-behind in the view which is where the data is wired up.

Peter Grimshaw said on Aug 5, 2011

Using Karsten's code as the basis, I have created some simple instructions for people wanting to implement this approach to display charts in Azure.

The post is here: http://social.msdn.microsoft.com/Forums/en-US/windowsazuredevelopment/thread/fe6ccbdf-ec70-49f5-aef4-aada217938ed

Azure & Chart Controls « Bernie Cook's Blog said on Nov 26, 2011

[...] to Karsten’s article: Using the ASP.NET Chart Control With Multiple Web Roles In Windows Azure. In this article you’ll find an example of a chart image handler written specifically to work [...]

Coach Diaper Bag said on Apr 27, 2012

One of the best sites for relevant facts on this niche !?!