54

I am trying to return a view not issue a redirect to the user based on certain errors that could occur from my application, I want to handle the errors + log them inside my base controller, I do not want the error to propagate up to my Global.asax - Application_Error() method as I want this method to handle any other errors inside my app e.g. user enters a bogus URL, has anyone found a way around this?

NOTE: I have left my commented code as I had a workaround for some issues, this also shows I have multiple exceptions to possible handle...

EDIT: If I issue a RedirectToAction within this OnException override everything works as expected, but I only want to return the view and no redirection...

My base controller method is:

    protected override void OnException(ExceptionContext filterContext)
    {
        //dont interfere if the exception is already handled
        if (filterContext.ExceptionHandled)
            return;

        //let the next request know what went wrong
        filterContext.Controller.TempData["exception"] = filterContext.Exception;

        //log exception
        _logging.Error(User.Identity.Name, ExceptionHelper.BuildWebExceptionMessage(filterContext.Exception));


        //set up redirect to my global error handler
        //if (filterContext.Exception.GetType() == typeof(NoAccessException))
        //    filterContext.Result = View(new RouteValueDictionary
        //    (new { area = "", controller = "Error", action = "PublicError" }));

        //else {
        //Only return view, no need for redirection
        filterContext.Result = View(new RouteValueDictionary
        (new { area = "", controller = "Error", action = "NoAccess" }));
        //}
        //advise subsequent exception filters not to interfere and stop
        // asp.net from showing yellow screen of death
        filterContext.ExceptionHandled = true;

        //erase any output already generated
        filterContext.HttpContext.Response.Clear();

        //base.OnException(filterContext);
    }

This method should handle any other errors that could appear in my app, I do not want the errors above being handled inside my Application_Error()

protected void Application_Error()
        {

            Exception exception = Server.GetLastError();
            // Log the exception.

            var logger = Container.Get<ILoggingService>();
            logger.Error(User.Identity.Name, ExceptionHelper.BuildWebExceptionMessage(exception));

            Response.Clear();

            HttpException httpException = exception as HttpException;

            RouteData routeData = new RouteData();
            routeData.Values.Add("controller", "Error");

            //if (httpException == null)
            //{
            routeData.Values.Add("action", "PublicError");
            //}
            //else //It's an Http Exception, Let's handle it.
            //{
            //    switch (httpException.GetHttpCode())
            //    {
            //        case 404:
            //            // Page not found.
            //            routeData.Values.Add("action", "HttpError404");
            //            break;
            //        case 500:
            //            // Server error.
            //            routeData.Values.Add("action", "HttpError500");
            //            break;

            //        // Here you can handle Views to other error codes.
            //        // I choose a General error template  
            //        default:
            //            routeData.Values.Add("action", "General");
            //            break;
            //    }
            //}

            // Pass exception details to the target error View.
            routeData.Values.Add("error", exception);

            // Clear the error on server.
            Server.ClearError();

            // Avoid IIS7 getting in the middle
            Response.TrySkipIisCustomErrors = true;

            // Call target Controller and pass the routeData.
            IController errorController = new ErrorController();
            errorController.Execute(new RequestContext(
                 new HttpContextWrapper(Context), routeData));
        }
Manfred
  • 5,320
  • 3
  • 35
  • 29
Haroon
  • 3,402
  • 6
  • 43
  • 74

1 Answers1

79

The following should work:

protected override void OnException(ExceptionContext filterContext)
{
    if (filterContext.ExceptionHandled)
    {
        return;
    }
    filterContext.Result = new ViewResult
    {
        ViewName = "~/Views/Shared/Error.aspx"
    };
    filterContext.ExceptionHandled = true;
}

Also make sure that no exception is thrown in this method or it will propagate to Application_Error.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Would the URL remain as it was originally...??? That is what I am trying to achieve by the method above i.e. if an error occurs the relevant view is sent back and the url remains the same/ the url does not change... – Haroon Jun 14 '11 at 09:54
  • 1
    @Haroon, yes absolutely, it will remain the same. It will be the initial url that caused the exception, except that instead of a Yellow Screen of Death the custom view will be rendered. – Darin Dimitrov Jun 14 '11 at 09:55
  • 2
    may be my question is silly... but can anyone tell me where this `OnException()` (the above code) is to be placed in application. In any `controller` class or in `global.ascx.cs`. Where? – blue May 09 '13 at 11:51
  • 1
    @bluesky OnException() is part of the controller class and can be overridden. – Kyle May 13 '13 at 16:58
  • Darin, I wish their may come a time when I will be able to work with you, you are an MVC genius.... – Serj Sagan Aug 12 '13 at 23:35
  • 2
    I found setting a few other properties such as view data (model of type `HandleErrorInfo`) and the response code was also helpful http://devproconnections.com/aspnet-mvc/aspnet-mvc-tutorial-handling-errors-and-exceptions – row1 Jun 09 '14 at 08:49
  • @DarinDimitrov: What if this is an AjaxRequest? I did like this, `if (ajaxReq) { filterContext.Result = new JsonResult() { Data = new { IsException = "true", RedirectUrl = "Error" }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; }` and in js `$(document).ajaxSuccess(function (e, xhr, Opt, d) { var jD = JSON.parse(d); if (jD.IsException) { window.location.href = jD.RedirectUrl; } });` but it redirect me to 'localhost:8787/Error' page, giving 404 error. – Razort4x Mar 16 '15 at 16:02
  • @DarinDimitrov `filterContext.ExceptionHandled` will always be true because of `filters.Add(new HandleErrorAttribute());` in `FilterConfig.cs`. So what is the purpose of checking it? – joym8 Jun 19 '19 at 20:24