Error Handling - Controller's OnException and Application_Error
The OnException() methods does 2 things.   


It logs the exception
It creates an return value  


So let us refactor these two points to two separate methods.  

private void LogException(ExceptionContext exceptionContext)
{
    logger = log4net.LogManager.GetLogger(exceptionContext.Controller.ToString());
    logger.Error(exceptionContext.Exception.Message, exceptionContext.Exception);
}




private const String XMLHttpRequest = "XMLHttpRequest";
private const String XRequestedWithHeadername= "X-Requested-With";
private const String JSONErrorMessage = "Sorry, an error occurred while processing your request.";
private void CreateExceptionContextResult(ExceptionContext exceptionContext)
{
    if (exceptionContext.HttpContext.Request.Headers[XRequestedWithHeadername] == XMLHttpRequest )
    {
        //Return JSON
        exceptionContext.Result = new JsonResult
        {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new { error = true, message = JSONErrorMessage }
        };
    }
    else
    {
        //Redirect user to error page
        exceptionContext.ExceptionHandled = true;
        exceptionContext.Result = this.RedirectToAction("Index", "Error");
    }
}


If we want to handle the different error types, we should create a new class which only keeps the values for actionName and controllerName.  

public class ActionControllerName
{
     public String ActionName { get; private set; }
     public String ControllerName { get; private set; }
     public ActionControllerName(String actionName, String controllerName)
     {
         ActionName = actionName;
         ControllerName = controllerName;
     }
}  


Now we add a Dictionary and a method to fill this dictionary, which should be called in the constructor, or injected by an property.

private const int DefaultEntryKey = -1;
private Dictionary&lt;int,ActionControllerName&gt; redirectDictionary = new Dictionary&lt;int,ActionControllerName&gt;();
private void FillRedirectDictionary()
{
    redirectDictionary.Add(DefaultEntryKey , new ActionControllerName("Index", "Error"));
    // more to add
}  


Next we implement a method to get a RedirectToRouteResult passing the exception as parameter  

private RedirectToRouteResult GetRedirect(Exception exception)
{
    int errorCode = DefaultEntryKey;
    HttpException httpException = exception as HttpException;
    if (httpException != null) 
    {
        errorCode = httpException.ErrorCode;
        if (!redirectDictionary.ContainsKey(errorCode))
        {
            errorCode = DefaultEntryKey;
        }
    }
    ActionControllerName acn = redirectDictionary[errorCode];
    return this.RedirectToAction(acn.ActionName , acn.ControllerName);
}


We go back to this else part  


else
{
    //Redirect user to error page
    exceptionContext.ExceptionHandled = true;
    exceptionContext.Result = this.RedirectToAction("Index", "Error");
}  



and change it to

else
{
    //Redirect user to error page
    exceptionContext.ExceptionHandled = true;
    exceptionContext.Result = GetRedirect(exceptionContext.Exception);
}