113

I'm writing an upload function, and have problems catching "System.Web.HttpException: Maximum request length exceeded" with files larger than the specified max size in httpRuntimein web.config (max size set to 5120). I'm using a simple <input> for the file.

The problem is that the exception is thrown before the upload button's click-event, and the exception happens before my code is run. So how do I catch and handle the exception?

EDIT: The exception is thrown instantly, so I'm pretty sure it's not a timeout issue due to slow connections.

Jonathan Moffatt
  • 13,309
  • 8
  • 51
  • 49
Marcus L
  • 4,030
  • 6
  • 34
  • 42
  • 5
    Did anyone try this with MVC? I seem to be able to catch the exception in the right way, but I'm unable to stop it: every time I try to render an error page the same exception occurs. – Andy Jul 25 '10 at 12:46
  • This error message is thrown by IIS before reaching the controller. To notify the user that the file exceeds the maximum upload limit (set in your web-config), you can directly validate the file size via JS with an onchange event. For e.g. `` Inside `showFileSize()`, you can display an error message based on your file size via `var input = document.getElementById("upload"); var file = input.files[0];` and append an html tag. – Alfred Wallace Mar 28 '19 at 03:16

16 Answers16

97

There is no easy way to catch such exception unfortunately. What I do is either override the OnError method at the page level or the Application_Error in global.asax, then check if it was a Max Request failure and, if so, transfer to an error page.

protected override void OnError(EventArgs e) .....


private void Application_Error(object sender, EventArgs e)
{
    if (GlobalHelper.IsMaxRequestExceededException(this.Server.GetLastError()))
    {
        this.Server.ClearError();
        this.Server.Transfer("~/error/UploadTooLarge.aspx");
    }
}

It's a hack but the code below works for me

const int TimedOutExceptionCode = -2147467259;
public 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;
}
Pona
  • 167
  • 1
  • 17
Damien McGivern
  • 3,954
  • 3
  • 27
  • 21
  • 2
    Thanks. OnError didn't work, but Application_Error did. We actually have a handler for this, but someone had turned it off in the code. – Marcus L Mar 20 '09 at 11:35
  • even two years ago, but I still want to ask whether this worked fine till now? does the string comparison of 'GetEntireRawContent' work fine? I don't think this is a timeout issue. is there anyone standing out for pointing me to uncloudy somewhere regarding this? – Elaine May 18 '11 at 06:07
  • @Elaine yeah this technique still works with ASP.Net 4.0. If you attempt to upload a request that is greater than the maximum request length ASP.Net throws a HttpException with the timeout code. Have a look in System.Web.HttpRequest.GetEntireRawContent() using reflector. – Damien McGivern May 19 '11 at 10:00
  • Hi, I tried your code and it successfuly catches the error, unfortunately, I wasn't redirected to the page I provided in the `Server.Transfer` method. Am I missing anything? – KaeL Jul 21 '11 at 06:10
  • I'm not sure why your checking for this specific error is so complicated. All I have to do is "if (exception is HttpUnhandledException && exception.InnerException.Message == "Maximum request length exceeded."") – Sam Rueby Feb 11 '12 at 23:44
  • 14
    @sam-rueby I didn't want to reply on a string error message that could change due to localisation. – Damien McGivern Feb 12 '12 at 19:15
  • The event doesn't fire for me. Any ideas? – Ian Warburton Jan 21 '13 at 17:23
  • This worked in my MVC app but only after I changed this.Server.Transfer to this.Response.Redirect. – Mike Strother Aug 28 '13 at 15:12
  • @DamienMcGivern : what namespace should I use for accessing GlobalHelper Methods? Its giving me error of "GlobalHelper" does not exist in current context. – Sohail Jan 29 '14 at 05:49
  • 4
    For .NET 4.0 and later there is better way to identify if max request size was exceeded. You can check this condition for HttpException: `httpException.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge` - using System.Web.Management.WebEventCodes – mco May 05 '15 at 08:47
  • @Sohail GlobalHelper is simply the name of the class that I created that contains the IsMaxRequestExceededException static method – Damien McGivern May 14 '15 at 10:01
  • I already had an Application_Error handler which worked for everything else. The problem with this error was inside that handler accessing the Request content...it throws another exception – Garr Godfrey Mar 05 '21 at 02:00
58

As GateKiller said you need to change the maxRequestLength. You may also need to change the executionTimeout in case the upload speed is too slow. Note that you don't want either of these settings to be too big otherwise you'll be open to DOS attacks.

The default for the executionTimeout is 360 seconds or 6 minutes.

You can change the maxRequestLength and executionTimeout with the httpRuntime Element.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <httpRuntime maxRequestLength="102400" executionTimeout="1200" />
    </system.web>
</configuration>

EDIT:

If you want to handle the exception regardless then as has been stated already you'll need to handle it in Global.asax. Here's a link to a code example.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Jonathan Parker
  • 6,705
  • 3
  • 43
  • 54
  • 2
    Thanks for your reply, but as I said in my comment to GK's answer this doesn't really solve my problem. It's not a timeout issue either, as the exception is thrown instantly. I'll edit the question to make that more clear. – Marcus L Mar 20 '09 at 09:57
  • 4
    The code example url points to a page that is not available...can anyone fix this? – deostroll Oct 11 '10 at 06:30
20

You can solve this by increasing the maximum request length in your web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <httpRuntime maxRequestLength="102400" />
    </system.web>
</configuration>

The example above is for a 100Mb limit.

GateKiller
  • 74,180
  • 73
  • 171
  • 204
  • 19
    Yes, and no. You push the limit further, but it doesn't really handle the exception. You'll still get the same problem if someone tries to upload 101+ Mb. The limit really needs to be 5 Mb. – Marcus L Mar 20 '09 at 09:50
10

If you are wanting a client side validation also so you get less of a need to throw exceptions you could try to implement client side file size validation.

Note: This only works in browsers that support HTML5. http://www.html5rocks.com/en/tutorials/file/dndfiles/

<form id="FormID" action="post" name="FormID">
    <input id="target" name="target" class="target" type="file" />
</form>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>

<script type="text/javascript" language="javascript">

    $('.target').change(function () {

        if (typeof FileReader !== "undefined") {
            var size = document.getElementById('target').files[0].size;
            // check file size

            if (size > 100000) {

                $(this).val("");

            }
        }

    });

</script>

Andrew
  • 1,696
  • 2
  • 16
  • 20
9

Hi solution mentioned by Damien McGivern, Works on IIS6 only,

It does not work on IIS7 and ASP.NET Development Server. I get page displaying "404 - File or directory not found."

Any ideas?

EDIT:

Got it... This solution still doesn't work on ASP.NET Development Server, but I got the reason why it was not working on IIS7 in my case.

The reason is IIS7 has a built-in request scanning which imposes an upload file cap which defaults to 30000000 bytes (which is slightly less that 30MB).

And I was trying to upload file of size 100 MB to test the solution mentioned by Damien McGivern (with maxRequestLength="10240" i.e. 10MB in web.config). Now, If I upload the file of size > 10MB and < 30 MB then the page is redirected to the specified error page. But if the file size is > 30MB then it show the ugly built-in error page displaying "404 - File or directory not found."

So, to avoid this, you have to increase the max. allowed request content length for your website in IIS7. That can be done using following command,

appcmd set config "SiteName" -section:requestFiltering -requestLimits.maxAllowedContentLength:209715200 -commitpath:apphost

I have set the max. content length to 200MB.

After doing this setting, the page is succssfully redirected to my error page when I try to upload file of 100MB

Refer, http://weblogs.asp.net/jgalloway/archive/2008/01/08/large-file-uploads-in-asp-net.aspx for more details.

Vinod T. Patil
  • 2,951
  • 3
  • 26
  • 21
8

Here's an alternative way, that does not involve any "hacks", but requires ASP.NET 4.0 or later:

//Global.asax
private void Application_Error(object sender, EventArgs e)
{
    var ex = Server.GetLastError();
    var httpException = ex as HttpException ?? ex.InnerException as HttpException;
    if(httpException == null) return;

    if(httpException.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge)
    {
        //handle the error
        Response.Write("Sorry, file is too big"); //show this message for instance
    }
}
Serge Shultz
  • 5,888
  • 3
  • 27
  • 17
4

One way to do this is to set the maximum size in web.config as has already been stated above e.g.

<system.web>         
    <httpRuntime maxRequestLength="102400" />     
</system.web>

then when you handle the upload event, check the size and if its over a specific amount, you can trap it e.g.

protected void btnUploadImage_OnClick(object sender, EventArgs e)
{
    if (fil.FileBytes.Length > 51200)
    {
         TextBoxMsg.Text = "file size must be less than 50KB";
    }
}
BaggieBoy
  • 57
  • 1
  • 1
3

In IIS 7 and beyond:

web.config file:

<system.webServer>
  <security >
    <requestFiltering>
      <requestLimits maxAllowedContentLength="[Size In Bytes]" />
    </requestFiltering>
  </security>
</system.webServer>

You can then check in code behind, like so:

If FileUpload1.PostedFile.ContentLength > 2097152 Then ' (2097152 = 2 Mb)
  ' Exceeded the 2 Mb limit
  ' Do something
End If

Just make sure the [Size In Bytes] in the web.config is greater than the size of the file you wish to upload then you won't get the 404 error. You can then check the file size in code behind using the ContentLength which would be much better

Walery Strauch
  • 6,792
  • 8
  • 50
  • 57
3

A solution that works with IIS7 and upwards: Display custom error page when file upload exceeds allowed size in ASP.NET MVC

Community
  • 1
  • 1
Marcus
  • 2,470
  • 1
  • 22
  • 29
2

As you probably know, the maximum request length is configured in TWO places.

  1. maxRequestLength - controlled at the ASP.NET app level
  2. maxAllowedContentLength - under <system.webServer>, controlled at the IIS level

The first case is covered by other answers to this question.

To catch THE SECOND ONE you need to do this in global.asax:

protected void Application_EndRequest(object sender, EventArgs e)
{
    //check for the "file is too big" exception if thrown at the IIS level
    if (Response.StatusCode == 404 && Response.SubStatusCode == 13)
    {
        Response.Write("Too big a file"); //just an example
        Response.End();
    }
}
jazzcat
  • 4,351
  • 5
  • 36
  • 37
2

I'm using a FileUpload control and client side script to check the file size.
HTML (note the OnClientClick - executed before OnClick):

<asp:FileUpload ID="FileUploader" runat="server" />
<br />
<asp:Button ID="btnUpload" Text="Upload" runat="server" OnClientClick="return checkFileSize()" OnClick="UploadFile" />
<br />
<asp:Label ID="lblMessage" runat="server" CssClass="lblMessage"></asp:Label>

Then the script (note the 'return false' if the size is too big: this is to cancel the OnClick):

function checkFileSize() 
{
    var input = document.getElementById("FileUploader");
    var lbl = document.getElementById("lblMessage");
    if (input.files[0].size < 4194304)
    {
        lbl.className = "lblMessage";
        lbl.innerText = "File was uploaded";
    }
    else
    {
        lbl.className = "lblError";
        lbl.innerText = "Your file cannot be uploaded because it is too big (4 MB max.)";
        return false;
    }
}
1

After tag

<security>
     <requestFiltering>
         <requestLimits maxAllowedContentLength="4500000" />
     </requestFiltering>
</security>

add the following tag

 <httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="404" subStatusCode="13" />
  <error statusCode="404" subStatusCode="13" prefixLanguageFilePath="" path="http://localhost/ErrorPage.aspx" responseMode="Redirect" />
</httpErrors>

you can add the Url to the error page...

Diego
  • 2,238
  • 4
  • 31
  • 68
0

You can solve this by increasing the maximum request length and execution time out in your web.config:

-Please Clarify the maximum execution time out grater then 1200

<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <httpRuntime maxRequestLength="102400" executionTimeout="1200" /> </system.web> </configuration>
0

How about catch it at EndRequest event?

protected void Application_EndRequest(object sender, EventArgs e)
    {
        HttpRequest request = HttpContext.Current.Request;
        HttpResponse response = HttpContext.Current.Response;
        if ((request.HttpMethod == "POST") &&
            (response.StatusCode == 404 && response.SubStatusCode == 13))
        {
            // Clear the response header but do not clear errors and
            // transfer back to requesting page to handle error
            response.ClearHeaders();
            HttpContext.Current.Server.Transfer(request.AppRelativeCurrentExecutionFilePath);
        }
    }
Khoa Tran
  • 121
  • 1
  • 9
0

It can be checked via:

        var httpException = ex as HttpException;
        if (httpException != null)
        {
            if (httpException.WebEventCode == System.Web.Management.WebEventCodes.RuntimeErrorPostTooLarge)
            {
                // Request too large

                return;

            }
        }
Raghav
  • 8,772
  • 6
  • 82
  • 106
0

Following up on Martin van Bergeijk's answer, I added an additional if block to check if they actually selected a file before submission.

if(input.files[0] == null)
{lbl.innertext = "You must select a file before selecting Submit"}
return false;        
pmcs
  • 51
  • 1
  • 10