ELMAH and API controller in MVC4 not logging errors - asp.net-mvc

Using an API controller in MVC4, when the controller action throws an exception, ELMAH does not log the error.
I think the problem is that MVC4 sets the HTTP status code to 500, and it returns the exception details in a JSON object, but it does not throw an unhandled exception so ELMAH never sees it.
How can I get ELMAH to capture all responses where the status code is not 200?

The anwser described before doesn't work. I've tried on my test server and received an error ("The given filter instance must implement one or more of the following filter interfaces: IAuthorizationFilter, IActionFilter, IResultFilter, IExceptionFilter.")
Then I realized what happened .... you are trying to add the custom filter to the MVC Global Filter (filters.Add(new ElmahHandledErrorLoggerFilter());)
To fix that, I've split the filter registration in GlobalFilter and HttpFilter
FilterConfig.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterHttpFilters(HttpFilterCollection filters)
{
filters.Add(new ElmahHandledErrorLoggerFilter());
}
Global.asax
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
FilterConfig.RegisterHttpFilters(GlobalConfiguration.Configuration.Filters);
;-)

UPDATE: This answer does not work in latest versions. Use julianox's answer.
Answer found from information here: http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling
Where the exception filter logs to elmah:
public class ElmahHandledErrorLoggerFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
base.OnException(actionExecutedContext);
ErrorSignal.FromCurrentContext().Raise(actionExecutedContext.Exception);
}
}
but you also have to add the error filter to the GlobalConfiguration filters:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
GlobalConfiguration.Configuration.Filters.Add(new ElmahHandledErrorLoggerFilter());
filters.Add(new ElmahHandledErrorLoggerFilter());
filters.Add(new HandleErrorAttribute());
}

Related

Generic Handler with ValidateAntiForgeryToken Att on MVC 4 Project

I search and try, but couldnt success. Is it possible use ValidateAntiForgeryToken with Generic Handler (.ashx)?
I tried this code, but not working.
[ValidateAntiForgeryToken]
public void ProcessRequest(HttpContext context)
{
//Process
}
Thanks.

MVC GlobalFilters not firing

I have this
public class ExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
Exception exception = context.Exception;
if (!(exception is HttpException))
{
Trace.TraceError("ExceptionFilter: " + ExceptionUtilities.GetFullExceptionMessage(exception));
Trace.Flush();
}
}
}
and this in global.asax
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new Filters.ExceptionFilter());
filters.Add(new HandleErrorAttribute());
}
but when I trigger an error by creating a dangerous request like this
example.com/dsfgds:dfgd
I get an exception:
A potentially dangerous Request.Path value was detected from the
client (:)
and the filter doesn't fire and the breakpoint inside doesn't get hit.
That's because you're registering an IExceptionFilter with MVC, and as such it will only capture unhandled exceptions that were raised within an MVC Action (and I think maybe other MVC filters? Don't quote me on that). But the error about a potentially dangerous request is an ASP.NET error, the request never made it to MVC, so the MVC error filter never gets called. Likewise, any IIS level errors would also not be handled by this. For non-MVC errors you still need to monitor the Application_OnError event. Or in the case of exception handlers like Elmah, let it monitor the event for you.

Handling UnauthorizedAccessException with custom errors in MVC 4 Application

I have enabled the global error handling for an application by applying the HandleError attribute within the filterConfig registration.
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
I am then using the custom errors (web.config) to hopefully display a friendly error message for each server error.
<customErrors mode="On" ></customErrors>
This seemed to be working fine for most exceptions and I was getting the expected behaviour in that the custom error page View (Error.cshtml in the shared view folder) was being displayed.
However I have recently noticed that this is not the behaviour I see if the error thrown is an UnauthorizedAccessException.
I am a bit stumped with this, as looking in fiddler I see that this UnauthorizedAccessException exception returns a plain 500 internal server error as a standard exception does.
So how come the standard exception abides by my customError setup but the UnauthorizedAccessException does not?
ANd how can I get them to behave the same, as they are both essentially an error which I want to prevent the end user from seeing.
This blog post provided me with the overview of exception handling to enable me to decide how to handle the unauthorizedAccessException, which essentially means handling them within the Application_OnStart.
http://prideparrot.com/blog/archive/2012/5/exception_handling_in_asp_net_mvc
For my purposes there doesn't seem much point in handling the errors with the HandleErrorAttribute and in the global Application_OnStart so for my purposes I decided it was best to handle everything in the Application_OnSTart,
If you just want to force 'unhandled' exceptions like UnauthorizedAccessException to go through the normal custom-error page then you can override the controller's OnException method similar to the following:
protected override void OnException(ExceptionContext filterContext)
{
base.OnException(filterContext);
if (!filterContext.ExceptionHandled && filterContext.RequestContext.HttpContext.IsCustomErrorEnabled)
{
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
filterContext.Result = View("Error",
new HandleErrorInfo(filterContext.Exception, filterContext.GetCurrentControllerName(), filterContext.GetCurrentActionName()));
}
}
The article that you referenced is an excellent resource for a more thorough explanation of error-handling techniques, though, and should be considered as well.

Filters of GlobalFilterCollection run before Filters of ControllerInstanceFilterProvider

I came across a weird behavior but I am not sure if I am on the right track here.
I have a controller which overrides OnException method of the Controller base class.
public class ControllerFiltersController : Controller {
public ActionResult Index() {
throw new NotImplementedException();
}
protected override void OnException(ExceptionContext filterContext) {
Trace.TraceInformation(
"ControllerFiltersController Exception: " + DateTime.Now.ToString("hh:mm:ss.fff")
);
}
}
I also have an custom ExceptionFilter as follows:
public class HandleErrorCustom : IExceptionFilter {
public void OnException(ExceptionContext filterContext) {
Trace.TraceInformation(
"HandleErrorCustom Exception Message: " + DateTime.Now.ToString("hh:mm:ss.fff")
);
}
}
Then, I registered it as a global filter:
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new HandleErrorCustom());
}
What I expected is here for the controller instance filter to run before global filter since the order of filters which are provided by ControllerInstanceFilterProvider is Int32.MinValue and the scope of them is FilterScope.First.
As also explained here: ASP.NET MVC 3 Service Location, Part 4: Filters
But the result is different:
iisexpress.exe Information: 0 : HandleErrorCustom Exception Message:
06:56:49.972
iisexpress.exe Information: 0 : ControllerFiltersController Exception:
06:56:49.974
This is an ASP.NET MVC 4 application and I am not aware of any changes which effects the filter ordering behavior of ASP.NET MVC 3. What am I missing here?
This is expected behavior.
Filter ordering depends on the direction the information is flowing. If the information is flowing into the action, then the order is as you expect it; if the information is flowing back out of the action, then the order is reversed.
For example, assume you have three filters in this order: F1, F2, F3. Assume that these are action filters (meaning, they're listening to ActionExecuting and ActionExecuted). The order the system will run them is as follows:
F1.ActionExecuting()
F2.ActionExecuting()
F3.ActionExecuting()
Action()
F3.ActionExecuted()
F2.ActionExecuted()
F1.ActionExecuted()
Error handlers are, by definition, filters that run on the return-side of actions, so their order is reversed.

How do I handle uncaught exceptions in an ASP.NET MVC 3 application?

I want to handle uncaught exceptions in my ASP.NET MVC 3 application, so that I may communicate the error to the user via the application's error view. How do I intercept uncaught exceptions? I'd like to be able to do this globally, not for each controller (although I wouldn't mind knowing how to do this as well).
You can set up a global error filter in Global.asax
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
The above sets up a default error handler which directs all exceptions to the standard error View. The error view is typed to a System.Web.Mvc.HandleErrorInfo model object which exposes the exception details.
You also need to turn on custom errors in the web.config to see this on your local machine.
<customErrors mode="On"/>
You can also define multiple filters for specific error types:
filters.Add(new HandleErrorAttribute
{
ExceptionType = typeof(SqlException),
View = "DatabaseError",
Order = 1
});
/* ...other error type handlers here */
filters.Add(new HandleErrorAttribute()); // default handler
Note that HandleErrorAttribute will only handle errors that happen inside of the MVC pipeline (i.e. 500 errors).
you can use HandleErrorAttribute filters,
[ErrorHandler(ExceptionType = typeof(Exception), View = "UnhandledError", Order = 1)]
public abstract class BaseController : Controller
{
}
basically you can have this on top of a base controller and define the UnhandledError.cshtml in the Shared views folder.
And if you want to log the unhandled errors before you show the error message then you can extend the HandleErrorAttribute class and put the logic to do the logging inside the OnException method.
public class MyErrorHandlerAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext exceptionContext)
{
Logger.Error(exceptionContext.Exception.Message,exceptionContext.Exception);
base.OnException(exceptionContext);
}
}
For completeness sake, there is also the Application_Error handler in Global.asax.
Global Error Handling
Add in web.config
<customErrors mode="On"/>
Error will be displayed on Error.cshtml which is resides in shared
folder
Change in Error.cshtml
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = "Error"; }
<h2>
<p>Sorry, an error occurred while processing your request.</p>
<p>Controller Name: #Model.ControllerName</p>
<p>Action Name : #Model.ActionName</p>
<p>Message: #Model.Exception.Message</p> </h2>
in order to make this work I followed the following blog post and then make the following addition to both Web.config files (the root one and the one in the Views folder) inside the <system.web> node:
...
<system.web>
<customErrors mode="On"/>
...
Hope it helps...

Resources