To generate charts on the fly, you can leverage the MsChart feature of ASP.Net and it’s a free component which makes it even more cool. Everything was working fine on my development machine which has Windows 7 and using .net framework 4.0 and IIS 7.5. However when I uploaded the files to the production server, the chart was not rendering on the live website and it took me the whole day yesterday (12 hours straight on) to fix the problem. I’ve been on lots and lots of blogs, forums and other websites trying to find a solution to my problem but I had inadvertently created a bug myself. Since you need at least 2 data points to create a chart, I inserted a line of code which would see if there were at least 2 data points before creating the chart, otherwise to return null and that was my biggest mistake. Since many people have reported problems with their asp.net charts not showing up, I find myself obliged to share my experiencing in getting yours fixed.
Which .net framework are you using?
In .net framework 4.0, the charting library has been included. For the 3.5 version, you may be required to have the following dlls in your bin folder:
using System.Web.UI.DataVisualization;
using System.Web.UI.DataVisualization.Charting;
using System.Drawing;
Remember on your dev machine, sometimes those assemblies are already in the GAC but not necessarily on your production servers. It is also worth mentioning the DataVisualization is located in the System.Web.DataVisualization dll (not the omission of UI in the namespace).
Set privateImages to false in your appSettings
In the web.config appSettings key, you might need to turn off privateImages because it is true by default and if the request is not authorised, the images won’t be displayed.
<add key="ChartImageHandler" value="storage=memory;deleteAfterServicing=true;privateImages=false;timeout=20;"/>
Explicitly define the ChartImg.axd http handlers in your web.config
The code below shows the main sections where the configurations need to be added:
<appSettings>
<add key="ChartImageHandler" value="storage=memory;deleteAfterServicing=true;privateImages=false;timeout=20;"/>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</assemblies>
</compilation>
<httpHandlers>
<add path="ChartImg.axd" verb="GET,HEAD,POST" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false" />
</httpHandlers>
<controls>
<add tagPrefix="asp" namespace="System.Web.UI.DataVisualization.Charting"
assembly="System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</controls>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="ChartImageHandler" />
<add name="ChartImageHandler" preCondition="integratedMode" verb="GET,HEAD,POST" path="ChartImg.axd" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</handlers>
<system.webServer>
Ignore routes to the chart image handler in your MVC
The MVC routing system may be messing up with your chart image handler sometimes. Many people have had success by ignoring the routes to the url where the charts are created, eg:
routes.IgnoreRoute("ChartImg.axd/{*pathInfo}");
routes.IgnoreRoute("{controller}/ChartImg.axd/{*pathInfo}");
routes.IgnoreRoute("{controller}/{action}/ChartImg.axd/{*pathInfo}");
How to use MsChart in your MVC application
In your view, you just need a an image tag with a url to your controller method which generates the chart as follows:
<img src="/chart/generate/1" alt="chart" />
And in your ChartController:
public FileContentResult Generate(int? id)
{
// Repository.GetData(id);
List<int> gisData = new List<int>();
gisData.Add(80);
gisData.Add(50);
gisData.Add(95);
gisData.Add(67);
gisData.Add(88);
var chart = new Chart();
chart.Width = 800;
var area = new ChartArea();
area.AxisY.Maximum = 100;
area.AxisX.Title = "Attempts";
area.AxisY.Title = "Points";
chart.ChartAreas.Add(area);
// create and customize your data series.
var series = new Series();
int count = 0;
foreach (int item in gisData)
{
count++;
series.Points.AddXY(count, item);
}
series.Font = new Font("Segoe UI", 8.0f, FontStyle.Bold);
series.ChartType = SeriesChartType.Line;
series["PieLabelStyle"] = "Outside";
chart.Series.Add(series);
using (MemoryStream ms = new MemoryStream())
{
chart.SaveImage(ms, ChartImageFormat.Png);
ms.Seek(0, SeekOrigin.Begin);
return File(ms.ToArray(), "image/png", "mycharg.png");
}
}
Instead of an ActionResult for the controller, I’m using a FileContentResult. You can also pass in an id which you can use to query your respository (database) for values to use as data points. In my example, I’m just hard coding the values.
Conclusion
It’s been a really long and frustrating day for me but I’m glad I managed to fix my problem which had nothing to do with the problems other people have faced. Hopefully this post is going to help someone and save their time!