I'm using a global action filter to handle and log all exceptions.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ElmahHandleErrorAttribute());
filters.Add(new HandleErrorAttribute());
}
This is how the global action filter ElmahHandleErrorAttribute
is defined - it overrides the OnException
method.
public class ElmahHandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
//Is the exception handled already? context.ExceptionHandled seems to be true here
if (!context.IsChildAction && (context.HttpContext.IsCustomErrorEnabled))
{
//Do other stuff stuff
//Log to Elmah
}
}
...
}
I don't understand why the value of context.ExceptionHandled
is true when the OnException
method executes.
How is this exception getting handled?
-EDIT-
I have a customErrors
section in the Web.Config
. I have an ErrorController
class, and actions called General
and Http404
.
<customErrors mode ="On" defaultRedirect="Error/General">
<error statusCode="404" redirect="Error/Http404"/>
</customErrors>
What I don't understand is, the controller action General
is not executed (breakpoint is never hit), but the value of ExceptionContext.ExceptionHandled
is set to true when the OnException
method of ElmahHandleErrorAttribute
starts executing.
When an exception occurs, the order of the global filters executes in reverse order. This means that HandleErrorAttribute
runs first.
You can view the code of HandleErrorAttribute
here, but in short, it:
ExceptionHandled
is false, and custom errors are enabled.Error
.ExceptionHandled
to true.As it's the first filter, then ExceptionHandled
is false when it executes, causing it to set the view to Error and setting ExceptionHandled
to true. So, then, when your own filter executes, that is why ExceptionHandled
is already set to true. Note that if custom errors were disabled, then ExceptionHandled
would still be false, as HandleErrorAttribute
wouldn't have done its stuff. In this case, ELMAH will log the error anyway, as it's unhandled (yellow screen of death), so the test in your class is to prevent duplicate logging of the error.
Now, on to your other question about whey the General
action isn't executed, the defaultRedirect
is only used if the filters don't set some explicit redirect themselves, so it's actually ignored when an exception occurs inside an ActionMethod and you have the global filter HandleErrorAttribute
registered. It would however, be called if you entered a URL that didn't exist, i.e. an error that doesn't occur from within an ActionMethod. Also, if you comment out the line to register the HandleErrorAttribute
in Global.asax.cs, then you'll always get the General
controller action executing.