I'm currently trying to centralize error handling in the global.asax in my asp.net MVC app. It has the following code to display a custom Error view in the default location (~/Views/Shared/Error.aspx) without using the HandleError attribute in the Controllers
and specifying the <customErrors> node in the web.config.
The code works under the following conditions:
- Visual studio 2008 built-in development Web Server
- IIS 6 with wildcard script mapping.
- IIS 7 with classic pipeline mode and wildcard script mapping.
The code does not work under the following conditions:
- IIS 7 with integrated pipeline mode.
My question is how can I setup IIS 7 or my MVC app to be hosted in the IIS7 integrated pipeline mode? Thank you all for your help!
My machine configuration: Windows 7, IIS7, Visual Studio 2008 SP1, ASP.NET MVC 1.0
My global.asax.cs code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace myApp {
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication {
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start() {
RegisterRoutes(RouteTable.Routes);
}
protected void Application_Error() {
HttpContext ctx = HttpContext.Current;
KeyValuePair<string, object> error = new KeyValuePair<string, object>("ErrorMessage", ctx.Server.GetLastError().ToString());
ctx.Response.Clear();
RequestContext rc = ((MvcHandler)ctx.CurrentHandler).RequestContext;
string controllerName = rc.RouteData.GetRequiredString("controller");
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controller = factory.CreateController(rc, controllerName);
ControllerContext cc = new ControllerContext(rc, (ControllerBase)controller);
ViewResult viewResult = new ViewResult { ViewName = "Error" };
viewResult.ViewData.Add(error);
viewResult.ExecuteResult(cc);
ctx.Response.End();
}
}
}
Thanks Ricka6. We're trying to avoid using customErrors in the web.config and decorating controllers with the HandlerError attribute. I tried subclassing all controllers in a custom controller base class that overrides the OnException method as follows.
It works in all situations, but this being that it will catch only errors in controllers. It would be nice to be able to show the error view from the global.asax's Error event handler itself.
I found out i was only missing a line of code (ctx.Server.ClearError();) to get it to display my custom error view intead of the default asp.net yellow screen of death. This code in the global.asax.cs will work on IIS6 and on IIS7 with the default app pool
in the integrated pipeline mode.
So no fussing with or need to do any of the following:
- decorating controllers or action methods with the HandleError attribute.
- subclassing every controller in a base controller class that overrides the OnException event handler just to handle errors.
- setting the customErrors node in the web.config to specify the mode and defaultRedirect attributes.
- setting Classic .NET AppPool in IIS7 and add a wildcard script mapping, which i read may have some performance implications.
Here's the code I settled on:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace myApp {
public class MvcApplication : System.Web.HttpApplication {
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start() {
RegisterRoutes(RouteTable.Routes);
}
protected void Application_Error() {
HttpContext ctx = HttpContext.Current;
KeyValuePair<string, object> error = new KeyValuePair<string, object>("ErrorMessage", ctx.Server.GetLastError().ToString());
ctx.Response.Clear();
RequestContext rc = ((MvcHandler)ctx.CurrentHandler).RequestContext;
string controllerName = rc.RouteData.GetRequiredString("controller");
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controller = factory.CreateController(rc, controllerName);
ControllerContext cc = new ControllerContext(rc, (ControllerBase)controller);
ViewResult viewResult = new ViewResult { ViewName = "Error" };
viewResult.ViewData.Add(error);
viewResult.ExecuteResult(cc);
ctx.Server.ClearError();
//ctx.Response.End();
}
}
}
I've used this technique in .net webforms applications for years, but haven't thought of using it in an MVC application.
I tried handling errors the MVC way by using [HandleError], setting a custom error in web.config, and overriding the controller OnException, but was running into all kinds of problems.
You have to have a HomeController with the ActionMethods "Error" and "NotFound". Remember never return detailed error messages to users in production environments.
jackh
Member
32 Points
10 Posts
Error Handling in global.asax
Dec 18, 2009 07:50 PM|LINK
Hi all,
I'm currently trying to centralize error handling in the global.asax in my asp.net MVC app. It has the following code to display a custom Error view in the default location (~/Views/Shared/Error.aspx) without using the HandleError attribute in the Controllers and specifying the <customErrors> node in the web.config.
The code works under the following conditions:
- Visual studio 2008 built-in development Web Server
- IIS 6 with wildcard script mapping.
- IIS 7 with classic pipeline mode and wildcard script mapping.
The code does not work under the following conditions:
- IIS 7 with integrated pipeline mode.
My question is how can I setup IIS 7 or my MVC app to be hosted in the IIS7 integrated pipeline mode? Thank you all for your help!
My machine configuration: Windows 7, IIS7, Visual Studio 2008 SP1, ASP.NET MVC 1.0
My global.asax.cs code
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace myApp { // Note: For instructions on enabling IIS6 or IIS7 classic mode, // visit http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } protected void Application_Error() { HttpContext ctx = HttpContext.Current; KeyValuePair<string, object> error = new KeyValuePair<string, object>("ErrorMessage", ctx.Server.GetLastError().ToString()); ctx.Response.Clear(); RequestContext rc = ((MvcHandler)ctx.CurrentHandler).RequestContext; string controllerName = rc.RouteData.GetRequiredString("controller"); IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory(); IController controller = factory.CreateController(rc, controllerName); ControllerContext cc = new ControllerContext(rc, (ControllerBase)controller); ViewResult viewResult = new ViewResult { ViewName = "Error" }; viewResult.ViewData.Add(error); viewResult.ExecuteResult(cc); ctx.Response.End(); } } }Jack
ricka6
All-Star
15070 Points
2272 Posts
Microsoft
Moderator
Re: Error Handling in global.asax
Dec 18, 2009 10:44 PM|LINK
Why don't you want to use
jackh
Member
32 Points
10 Posts
Re: Error Handling in global.asax
Dec 19, 2009 01:51 PM|LINK
Thanks Ricka6. We're trying to avoid using customErrors in the web.config and decorating controllers with the HandlerError attribute. I tried subclassing all controllers in a custom controller base class that overrides the OnException method as follows. It works in all situations, but this being that it will catch only errors in controllers. It would be nice to be able to show the error view from the global.asax's Error event handler itself.
Thanks again.
protected override void OnException(ExceptionContext filterContext) { filterContext.ExceptionHandled = true; this.View("Error").ExecuteResult(this.ControllerContext); }jackh
Member
32 Points
10 Posts
Re: Error Handling in global.asax
Dec 22, 2009 07:32 PM|LINK
I found out i was only missing a line of code (ctx.Server.ClearError();) to get it to display my custom error view intead of the default asp.net yellow screen of death. This code in the global.asax.cs will work on IIS6 and on IIS7 with the default app pool in the integrated pipeline mode.
So no fussing with or need to do any of the following:
- decorating controllers or action methods with the HandleError attribute.
- subclassing every controller in a base controller class that overrides the OnException event handler just to handle errors.
- setting the customErrors node in the web.config to specify the mode and defaultRedirect attributes.
- setting Classic .NET AppPool in IIS7 and add a wildcard script mapping, which i read may have some performance implications.
Here's the code I settled on:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace myApp { public class MvcApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } protected void Application_Error() { HttpContext ctx = HttpContext.Current; KeyValuePair<string, object> error = new KeyValuePair<string, object>("ErrorMessage", ctx.Server.GetLastError().ToString()); ctx.Response.Clear(); RequestContext rc = ((MvcHandler)ctx.CurrentHandler).RequestContext; string controllerName = rc.RouteData.GetRequiredString("controller"); IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory(); IController controller = factory.CreateController(rc, controllerName); ControllerContext cc = new ControllerContext(rc, (ControllerBase)controller); ViewResult viewResult = new ViewResult { ViewName = "Error" }; viewResult.ViewData.Add(error); viewResult.ExecuteResult(cc); ctx.Server.ClearError(); //ctx.Response.End(); } } }Thank you all and cheers!
jstabile
Member
2 Points
1 Post
Re: Error Handling in global.asax
Dec 29, 2009 07:34 PM|LINK
Thank you jackh:
I've used this technique in .net webforms applications for years, but haven't thought of using it in an MVC application.
I tried handling errors the MVC way by using [HandleError], setting a custom error in web.config, and overriding the controller OnException, but was running into all kinds of problems.
Your solution works great!!
pnvpratik
Member
2 Points
1 Post
Re: Error Handling in global.asax
May 07, 2010 10:31 AM|LINK
Hey Thanks that really helped on my application on IIS 7.
chuckhallman
Member
2 Points
2 Posts
Re: Error Handling in global.asax
Apr 05, 2011 04:42 PM|LINK
The following line ..... blows up with the following error message ..{"Unable to cast object of type 'System.Web.DefaultHttpHandler' to type 'System.Web.Mvc.MvcHandler'."}jackh
Member
32 Points
10 Posts
Re: Error Handling in global.asax
Jun 06, 2011 02:57 PM|LINK
Hi Chuck,
Are you trying to use this code on a non ASP.NET MVC project? If so, this code would not work.
Robs030
Member
2 Points
1 Post
Re: Error Handling in global.asax
Oct 27, 2011 01:51 PM|LINK
Assuming you have defined a default route in your Global.asax
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new String[] { "YourNamespace.Controllers" } // Parameter defaults ); }Modify the code from above.
void Application_Error(Object sender, EventArgs e) { Exception exception = Server.GetLastError(); Response.Clear(); HttpException httpException = exception as HttpException; if (httpException != null) { bool notfound; switch (httpException.GetHttpCode()) { case 404: notfound = true; break; default: notfound = false; break; } Server.ClearError(); if(notfound) this.Response.RedirectToRoute("Default", new { controller = "Home", action = "NotFound" }); else this.Response.RedirectToRoute("Default", new { controller = "Home", action = "Error" }); } }You have to have a HomeController with the ActionMethods "Error" and "NotFound". Remember never return detailed error messages to users in production environments.