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:
- Url:
/Controller.mvc/Action/1/2
- IIS 6:
/Controller.mvc/Action/1/2
- IIS 7:
/Controller.mvc
Which resulted in Urls for the charts like:
- IIS 6:
/Controller.mvc/Action/1/ChartImg.axd?i=chart_...
- IIS 7:
/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):
- Add an explicit script map for ".mvc" to the ASP.NET 4.0 dll
- Add some additional ignore routes to the route table to cover permutations
- Override the Execute() of Controller and put in a redirect back to /ChartImg.axd
(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
- IIS 6.0 Manager
- Properties -> Home Directory -> Configuration
- Mappings tab
- Executable: c:\winnt\microsoft.net\framework\v4.0.30319\aspnet_isapi.dll, Extension: .mvc
(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;
}
}
}