Oliver
Oliver

Reputation: 11597

HttpNotFoundResult causes an HttpException to be thrown?

For testing purposes, I have this method:

public ActionResult Index()
{
    System.Diagnostics.Debug.Write("Index");
    return new HttpNotFoundResult();
}

The method is being called ('Index' is outputted). Somehow, it is causing a HttpException to be thrown. In my Global.asax file I have an Application_Error implementation:

void Application_Error(object sender, EventArgs e)
{
    Exception exc = Server.GetLastError();
    if (exc is System.Web.HttpException)
    {
        string msg = "UrlReferrer: "
            + Context.Request.UrlReferrer + " UserAgent: " + Context.Request.UserAgent
            + " UserHostAddress: " + Context.Request.UserHostAddress + " UserHostName: "
            + Context.Request.UserHostName;

        ErrorHandler.Error(exc.Message, msg);
    }
    else {
        ...
    }
}

This method is being called after the system has processed the request for Index. I think that the HttpNotFoundResult causes the exception to be thrown - or perhaps the exception is thrown for any ActionResult with a status code of 404.

This is quite annoying, as it is side-stepping the OnException handler on my controller. For my website, Application_Error is supposed to be a last-ditch fallback - most normal errors are intended to be handled in other places (by the controllers, or action filters). I only want Application_Error to log completely unexpected exceptions, or 404s for things like image or .js files.

Is there a way to stop asp.net from throwing exceptions for programatically generated 404s? Alternatively, is there a way to determine in Application_Error if the HttpException was caused by a programatically generated 404?

Upvotes: 2

Views: 1183

Answers (1)

VJAI
VJAI

Reputation: 32758

You can create a custom exception filter that handles 404 exceptions raised by all the actions. You could use HttpContext.Items collection to track whether it is a programatically raised 404 or not.

Custom exception filter

public class NotFoundExceptionFilter : IExceptionFilter
{        
    public void OnException(ExceptionContext filterContext)
    {
        // ignore if the exception is already handled or not a 404
        if (filterContext.ExceptionHandled || new HttpException(null, filterContext.Exception).GetHttpCode() != 404)
            return;

        filterContext.HttpContext.Items.Add("Programmatic404", true);
        filterContext.ExceptionHandled = true;
    }
}

You need to apply NotFoundExceptionFilter as a global filter.

Application_Error event

public static void Application_Error(object sender, EventArgs e)
{
    var httpContext = ((MvcApplication)sender).Context;

    // ignore if it is a programatically raised 404
    if(httpContext.Items["Programmatic404"] != null && bool.Parse(httpContext.Items["Programmatic404"].ToString()))
        return;

    // else, Log the exception
}

Upvotes: 2

Related Questions