How to set different Timeouts for different URLs in ASP.NET
Asked Answered
C

3

18

I want different connection limits for some URLs in my application. Some URLs accept file uploads and need to have a large Connection Timeout. All other URLs need a much smaller timeout to prevent denial of service and not waste resources.

Currently I have the Connection Timeout property in IIS set for the entire site to 60 minutes. Then I did this in the web.config:

<system.web>
    <httpRuntime executionTimeout="480" maxRequestLength="1024" />
</system.web>

<location path="FileUpload/WriteFile.rails">
    <system.web>
        <httpRuntime executionTimeout="3600" maxRequestLength="512000" />
    </system.web>
</location>

So i was hoping this would set all URLs to an 8 minute timeout and allow the WriteFile.rails URL to run for 60 minutes. Instead ALL URLs are allowed to run for 60 minutes. How do I get IIS to do what I want?

Corroboration answered 16/6, 2011 at 22:13 Comment(2)
So after doing a bunch of testing I believe that this configuration is more or less correct. However, in the logs, I'm getting some actions that take much longer than 480 seconds to time out that have not been explicitly configured as such. We log the request start time in OnBeginRequest and then the end time is logged in OnError when the "System.Web.HttpException (0x80004005): Request timed out." is thrown. Its hitting the global limit of 1 hour.Corroboration
This question may be what I'm really after here: #4490517Corroboration
C
29

The question asked specifically about timeouts but also implied setting maxRequestLength as well. I'm going to try and give a really comprehensive answer to both issues (now that I have spent most of a day working it out).

Lets say we have a single URL on our website that we want to process file uploads. We want to take in up to a Gigabyte of data on that URL and we will allow clients to be connected for, at most, 1 hour. All other URLs we want to only allow 90 seconds of connection time and a maximum of 4MB in the POST body.

Global Settings

First you have to globally raise the limits on time and size for the entire site. First you want to set the "Connection Timeout" for the entire site. This acts as an absolute upper bound and it cannot be set from within the web.config. The IIS7 website has good instructions here. You can also do it programatically with the Microsoft.Web.Administration library that shipped with IIS7/7.5:

var serverManager = ServerManager.OpenRemote("\\web-server-name");
var site = serverManager.Sites["Your-Site-Name"];
site.Limits.ConnectionTimeout = new TimeSpan(1, 0, 0);

Next you need to set the max size request that the site will allow. This is in a totally different place, in the Request Fitlering module. This module may not be installed by default on IIS7. Again Microsoft has good instructions for how to set the maxAllowedContentLength through the GUI. This is something you can set from within the Web.config:

<system.webServer>
    <security>
        <requestFiltering>
            <!-- Allow 1GB uploads -->
            <requestLimits maxAllowedContentLength="1073741824"></requestLimits>
        </requestFiltering>
    </security>
</system.webServer>

This setting is evaluated against the Content-Length header and requests larger than this will immediately result in a 404.13. The setting is in bytes and what comes next is in Kilobytes, very consistent this IIS7.

ASP.NET Settings

Next we want to cap all of the ASP.NET requests at 90 seconds/4MB. This can be done in the web.config:

<location>
    <system.web>
        <httpRuntime executionTimeout="90" maxRequestLength="4096" />
    </system.web>
</location>

To make the settings global the system.web tag is wrapped in a location tag that has no path attribute. (In the original question I did not wrap the system.web tag in the location tag which was probably the source of my problem.) maxRequestLength is in kilobytes this time.

Finally we want to allow our special upload URL to accept huge uploads. Setting these values higher than the ones you set globally wont work. The global values override these settings.

<location path="Uploads/PostFile.rails">
    <system.web>
        <httpRuntime executionTimeout="3600" maxRequestLength="1048576" />
    </system.web>
</location>

If everything else is set up right, that should do it. As Peter Bromberg suggested, you can add as many of these blocks as needed to raise the limits for specific URLs.

One last note: in debug mode IIS does not enforce the Connection Timeout or executionTimeout settings, to allow you more time for debugging. So to test your setting on a developer machine you should do a release build and you should set the 'Enable Server-Side Debugging' setting to false.

Corroboration answered 5/7, 2011 at 21:5 Comment(3)
"Setting these values higher than the ones you set globally wont work. The global values override these settings." Huh? Your example right here sets 90 sec for all then 3600 sec for specific location.Inelastic
Oh, you meant you cannot set maxRequestLength larger here than it was in requestFiltering.Inelastic
Well written answer and thanks for taking the time to share back with us your results.Kos
F
0

To set the timeout for a specific page, you can use as many <location path web.config elements as necessary:

<location path="Myfile.aspx">
  <system.web>
    <httpRuntime executionTimeout="180"/>
  </system.web>
</location>

As long as your path is defined correctly, and the .rails extension is mapped to ASP.NET, this should work. Could it be that the ASP.NET execution engine is not processing *.rails extensions?

NOTE: Man what a lousy post editor. Why can't you do the escaping for the user?

Fireresistant answered 16/6, 2011 at 22:36 Comment(1)
I'm using the monorail handler like so: <add name="MonoRail" path="*" verb="*" type="Castle.MonoRail.Framework.MonoRailHttpHandlerFactory, Castle.MonoRail.Framework" preCondition="integratedMode" /> I think that maybe what I should be doing is implementing a filter that will change Server.ScriptTimeout based on an optional attribute placed on the Action.Corroboration
G
0

You could always set the ScriptTimeout directly in your controller action. That way the configuration won't break if you change your routing.

Giese answered 20/6, 2011 at 9:58 Comment(1)
I like that idea, you could do it with attributes in c#. The only problem is you want to set the timeout before the action gets called. In the case of large uploads the action is only called after the entire file is received. I don't know how to get Monorail to tell me which action its going to execute before it gets executed, say in PostAcquireRequestState.Corroboration

© 2022 - 2024 — McMap. All rights reserved.