I\'ve just upgraded to .NET 4 and my ASP.NET Chart Control no longer displays.
For .NET 3.5, the HTML produced by the control used to look like this:
We had this same problem on IIS 6 after upgrading from ASP.NET 3.5 to ASP.NET 4.0 with ASP.NET MVC. Everything was working fine on IIS 7, but IIS 6 gave us a problem.
The problem was that the HttpContext.Current.Request.CurrentExecutionFilePath property gave a different result in IIS 6 and IIS 7:
/Controller.mvc/Action/1/2
/Controller.mvc/Action/1/2
/Controller.mvc
Which resulted in Urls for the charts like:
/Controller.mvc/Action/1/ChartImg.axd?i=chart_...
/ChartImg.axd?i=chart_...
The ChartHttpHandler has got a function in there that calculates the path based off the HttpContext.Current.Request.CurrentExecutionFilePath:
private static string GetHandlerUrl()
{
string str = Path.GetDirectoryName(HttpContext.Current.Request.CurrentExecutionFilePath ?? "").Replace(@"\", "/");
if (!str.EndsWith("/", StringComparison.Ordinal))
{
str = str + "/";
}
return (str + "ChartImg.axd?");
}
The way that the ASP.NET UrlRewriting was working, since the paths to ChartImg.axd still had .mvc in them, the MVC handler was getting invoked instead of the Chart handler.
There were 3 ways we found to deal with it (see below for details):
(1) Turns out that if we added a script map for .mvc via IIS 6.0 for .mvc the Request.CurrentExecutionFilePath would get calculated as the root path how we wanted it instead of as the deeper path
(2) We found that adding some route table entries would work, but we had to account for all depths possible in the paths to get ASP.NET MVC to ignore the ChartImg.axd if it were deeply embedded in the path and not at the root:
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
RouteTable.Routes.IgnoreRoute("{a}/{resource}.axd/{*pathInfo}");
RouteTable.Routes.IgnoreRoute("{a}/{b}/{resource}.axd/{*pathInfo}");
RouteTable.Routes.IgnoreRoute("{a}/{b}/{c}/{resource}.axd/{*pathInfo}");
RouteTable.Routes.IgnoreRoute("{a}/{b}/{c}/{d}/{resource}.axd/{*pathInfo}");
(3) By overriding the Execute() on all our controllers by making a base controller that all our controllers inherit from, we could globally override the Execute() to account for this situation and redirect to /ChartImg.axd
public partial class MyController: Controller
{
protected override void Execute(RequestContext cc)
{
// the url for chartimg.axd to be in the application root. /Controller.mvc/Action/Param1/ChartImg.axd gets here first,
// but we want it to go to /ChartImg.axd, in which case the IgnoreRoute does work and the chart http handler does it's thing.
if (cc.HttpContext.Request.Url.AbsoluteUri.Contains("ChartImg.axd"))
{
var url = new UriBuilder(cc.HttpContext.Request.Url);
url.Path = "/ChartImg.axd";
cc.HttpContext.Response.Redirect(url.ToString());
return;
}
}
}
Thanks for your answers, but I don't think mine was an IIS6/IIS7 problem.
I traced it to the fact that the default value for ImageStorageMode
on a ChartControl
has changed from UseImageLocation
to UseHttpHandler
. My ChartControl
now has some extra attributes and all works fine.
<asp:Chart ... ImageStorageMode="UseImageLocation" ImageLocation="/Temp/ChartPic_#SEQ(300,3)">
I had to also change the ImageLocation
to be non-relative (by adding /Temp/
) as that also caused a problem when iterating over the ChartControl
's DataPoints
in some code-behind.
While @Michael's solution is informative on why this problem exists, there is a simpler solution. When registering the routes in your controllers handle in global.asax.cs, you could add an ignored route with a contstraint, as follows:
protected void Application_Start() {
...
RouteTable.Routes.Ignore("{*pathInfo}", new { pathInfo = @"^.*(ChartImg.axd)$" });
...
}