ASP.NET – Maximum Request Length Exceeded
This one issue has turned out to be a lot more difficult and complicated than one would imagine it to be. You’ll most likely run into this when you try to upload a file greater than 4 MB using ASP.NET.
ASP.NET
The first point of concern is the configuration/system.web/httpRuntime@maxRequestLength attribute. This value defaults to 4096KB or 4MB. If you happen to attempt to upload a file between 4 MB and ~28.61 MB on IIS 7 or IIS 7.5 (I’ll get to this in a minute) or greater than 4 MB on IIS 6 or lower, you’ll see something like this:
Server Error in '/Test' Application. Maximum request length exceeded. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: System.Web.HttpException: Maximum request length exceeded. Source Error: An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. Stack Trace: [HttpException (0x80004005): Maximum request length exceeded.] System.Web.HttpRequest.GetEntireRawContent() +11342583 System.Web.HttpRequest.GetMultipartContent() +221 System.Web.HttpRequest.FillInFormCollection() +345 System.Web.HttpRequest.get_Form() +137 Microsoft.Web.Infrastructure.DynamicValidationHelper.<>c__DisplayClass12.b__e() +63 Microsoft.Web.Infrastructure.DynamicValidationHelper.<>c__DisplayClass12.b__11() +20 Microsoft.Web.Infrastructure.DynamicValidationHelper.DeferredCountArrayList.get_Count() +20 System.Web.HttpRequest.ValidateNameValueCollection(NameValueCollection nvc, RequestValidationSource requestCollection) +34 System.Web.HttpRequest.get_Form() +186 System.Web.Mvc.FormValueProvider..ctor(ControllerContext controllerContext, IUnvalidatedRequestValues unvalidatedValues) +55 System.Web.Mvc.FormValueProviderFactory.GetValueProvider(ControllerContext controllerContext) +65 System.Web.Mvc.<>c__DisplayClassc.b__7(ValueProviderFactory factory) +28 System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +238 System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +148 System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +472 System.Linq.Enumerable.ToList(IEnumerable`1 source) +80 System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) +343 System.Web.Mvc.ControllerBase.get_ValueProvider() +57 System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +80 System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +152 System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +785360 System.Web.Mvc.Controller.ExecuteCore() +159 System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +335 System.Web.Mvc.<>c__DisplayClassb.b__5() +62 System.Web.Mvc.Async.<>c__DisplayClass1.b__0() +20 System.Web.Mvc.<>c__DisplayClasse.b__d() +54 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +453 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +371
IIS 7 / IIS 7.5
Now, if you happen to upload a file greater than ~28.61 MB on IIS 7 or IIS 7.5, you’ll see something a little bit different.
Server Error in Application "DEFAULT WEB SITE/TEST" Internet Information Services 7.5 Error Summary HTTP Error 404.13 - Not Found The request filtering module is configured to deny a request that exceeds the request content length. Detailed Error Information Module RequestFilteringModule Notification BeginRequest Handler StaticFile Error Code 0x00000000 Requested URL http://localhost:80/Test/Home/Post Physical Path D:\Users\rasmussa\Documents\Visual Studio 2010\Projects\MvcApplication2\MvcApplication2\Home\Post Logon Method Not yet determined Logon User Not yet determined Most likely causes: Request filtering is configured on the Web server to deny the request because the content length exceeds the configured value.
This little gem was added in IIS 7 and it’s called Request Filtering, and the settings for it live in the configuration/system.webServer/security/requestFiltering node of web.config. There is an attribute called maxAllowedContentLength, which performs a similar function to the maxRequestLength setting for the ASP.NET HTTP runtime. The maxAllowedContentLength attribute defaults to 30000000 bytes, or ~28.61 MB.
Note: The maxAllowedContentLength setting is specified in bytes, whereas the maxRequestLength setting is specified in kilobytes.
ASP.NET Solution
So, now that you get the “Maximum Request Length Exceeded” exception, what can you do about it? As you can see from the stack trace above, at no point is it hitting any code that I’ve created; this exception is thrown before any page or action gets called. That means I had to turn to the global.asax exception handler, or Application_Error().
When I was trying to figure this out for myself, I came across several solutions…
One had some hacks in it to determine what was in the stack trace and then redirect based on the existence of a method in the stack trace (yuck) a la StackTrace.Contains(“GetEntireRawContent”). I think it’s relatively obvious why this doesn’t sound like a very good solution.
Another involved reading in the entire response and then redirecting the user after determining the content length of the request. This method is less than ideal since you would then be giving malicious users free reign over your network connection. Someone could intentionally upload several 50 GB files at the same time, and with this solution, your server would be forced to accept all of the content that user would be sending. This could cause your server’s network connection to become saturated.
I came across a little bit more elegant of a solution…
.NET 4
protected void Application_Error() { HttpException h = Server.GetLastError() as HttpException; if (h != null && h.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge) // System.Web.Management { Server.ClearError(); Response.Redirect("~/Error/UploadTooLarge"); } }
All .NET Versions
private const string UPLOAD_TOO_LARGE = "Maximum request length exceeded."; protected void Application_Error(object sender, EventArgs e) { HttpException exception = Server.GetLastError() as HttpException; Exception innerException = (exception == null) ? null : exception.InnerException; if (innerException != null && innerException.Message == UPLOAD_TOO_LARGE) { Server.ClearError(); Response.Redirect("~/Error/UploadTooLarge"); } }
This way, the ASP.NET HTTP runtime is still able to enforce the request limit, and the user will be redirected to an error page that informs them the size of their upload is too large.
IIS 7 / IIS 7.5 Solution
Fellow IIS 7 and 7.5 users, you are not out of the woods yet. Actually, the solution for IIS 7 and 7.5 is even simpler than handling the HttpException from ASP.NET. Do I hear you ask: “Oh really”? Please read on…
Since the request filtering that was discussed earlier is a security feature built into IIS (not ASP.NET), it is executed before ASP.NET gets to throw any exceptions. This is actually good news since it means we don’t need to write any code to handle the error.
First, you do need to make sure that the ASP.NET method of limiting the request length (maxRequestLength) is greater than or equal to the IIS method of limiting the request length (maxAllowedContentLength). So, if you want to restrict uploads to 10MB, set maxRequestLength to “10240” (or greater) and maxAllowedContentLength to “10485760”. Again, this essentially prevents the ASP.NET HTTP runtime from complaining about a request length that exceeds its limits, since the IIS feature will limit the length before ASP.NET has a chance to.
The specific status code, as you can see here, is 404.13 “Content Length Too Large”. In the web.config, you can add an override to this particular status and sub-status to tell IIS to redirect this particular status to a certain page.
Add the following block to the configuration/system.webServer section of your web.config.
<httpErrors errorMode="Custom" existingResponse="Replace"> <remove statusCode="404" subStatusCode="13" /> <error statusCode="404" subStatusCode="13" prefixLanguageFilePath="" path="/Error/UploadTooLarge" responseMode="Redirect" /> </httpErrors>
This configuration block will prevent IIS from displaying it’s default (read: user unfriendly) error page for 404.13, and allow you to redirect them to a more useful page that informs them they’ve uploaded a file that is too large. Be advised that the path attribute of error is an absolute path (you can’t reference the application root using ~) when the responseMode is set to “Redirect”.
So, with all of the changes here, your web.config file would look something like this… (I’ve removed the standard web.config elements for brevity)
<configuration> <system.web> <httpRuntime maxRequestLength="10240" /> </system.web> <system.webServer> <security> <requestFiltering> <requestLimits maxAllowedContentLength="10485760" /> </requestFiltering> </security> <httpErrors errorMode="Custom" existingResponse="Replace"> <remove statusCode="404" subStatusCode="13" /> <error statusCode="404" subStatusCode="13" prefixLanguageFilePath="" path="/Error/UploadTooLarge" responseMode="Redirect" /> </httpErrors> </system.webServer> </configuration>
This entry was posted on Saturday, April 23rd, 2011 at 3:54 pm and is filed under ASP.NET. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
Austin Rasmussen July 23rd, 2011 at 11:03 am
Hey Kael,
Nice catch. It didn’t dawn on me that the WebEventCode was a newly added property. I’ve updated the article to include an alternative solution, which doesn’t use the WebEventCode property, and does not involve changing IIS configurations.
It is a little less elegant, since we’re actually comparing the error message, but it works well.
Let me know how this works for you!