How to Handle "Maximum request length exceeded" Error - ASP.NET MVC

Overview

When the user tries to upload a file larger that the configured maximum size, a "Maximum request length exceeded" exception will occur. This exception will not be caught by the usual means, such as a try/catch or a HandleErrorAttribute. This article explains how to respond to the exception by redirecting to an error page.

Solution

Global.asax

Add the following code to your global.asax file. If you have an existing Application_Error method, then adapt the code below as necessary.

protected void Application_Error(object sender, EventArgs e)
{
    try
    {
        if (IsMaxRequestExceededException(this.Server.GetLastError()))
        {
            this.Server.ClearError();
            HttpContext.Current.ClearError();
            /*  NOTE: Because of the special context we're in, Server.Execute and Server.Transfer
                *  won't work on the next line. */
            Response.Redirect("~/Home/UploadTooBig");
        }
    }
    catch (Exception ex)
    {
        throw;
    }
}

const int TimedOutExceptionCode = -2147467259;
private static bool IsMaxRequestExceededException(Exception e)
{
    // unhandled errors = caught at global.ascx level
    // http exception = caught at page level

    Exception main;
    var unhandled = e as HttpUnhandledException;

    if (unhandled != null && unhandled.ErrorCode == TimedOutExceptionCode)
    {
        main = unhandled.InnerException;
    }
    else
    {
        main = e;
    }


    var http = main as HttpException;

    if (http != null && http.ErrorCode == TimedOutExceptionCode)
    {
        // hack: no real method of identifying if the error is max request exceeded as 
        // it is treated as a timeout exception
        if (http.StackTrace.Contains("GetEntireRawContent"))
        {
            // MAX REQUEST HAS BEEN EXCEEDED
            return true;
        }
    }

    return false;
}

View Model

Create the following view model class.

public class UploadTooBigViewModel
{
    public UploadTooBigViewModel()
    {
        MaxRequestLength = GetMaxRequestLength();
    }
    public string MaxRequestLength { get; private set; }

    private string GetMaxRequestLength()
    {
        const int DEFAULT_VALUE = 4096;

        int byteQty = DEFAULT_VALUE;

        var fileSpec = HttpContext.Current.Server.MapPath("~/web.config");

        if (System.IO.File.Exists(fileSpec))
        {
            var contents = System.IO.File.ReadAllText(fileSpec);
            var doc = new System.Xml.XmlDocument();

            /* We'll assume the web.config file is a valid XML document. We wouldn't have made it 
                * this far otherwise. */
            doc.LoadXml(contents);

            var xPath = "//configuration/system.web/httpRuntime/@maxRequestLength";
            var node = doc.SelectSingleNode(xPath);
            byteQty = node == null ? DEFAULT_VALUE : int.Parse(node.Value);
        }

        var result = ReduceBytes(byteQty * 1024);
        return result;
    }
    private string ReduceBytes(int byteQty)
    {
        float byteResult = byteQty;
        const string PREFIX = " KMGTPEZY";
        var index = 0;

        while (byteResult > 1024)
        {
            byteResult /= 1024F;
            index++;
        }

        var result = byteResult.ToString("#,##0.0") + " " + PREFIX.Substring(index, 1) + "B";
        return result;
    }
}

Controller Method

Add the following method to your HomeController class.

public ActionResult UploadTooBig()
{
    return View(new UploadTooBigViewModel());
}

Razor View

Create the following view for the HomeController.UploadToBig method.

@model MyWebsite.Models.UploadTooBigViewModel
@{
    ViewBag.Title = "Upload Too Large";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<p>You cannot upload a file that large.  The largest file that 
can be uploaded is @Model.MaxRequestLength</p>

<a href="javascript:history.go(-1);">Back</a>