ASP.NET MVC, Url Routing: Maximum Path (URL) Length

筅森魡賤 提交于 2019-11-26 17:15:36

I ended up using the following in the web.config to solve this problem using Mvc2 and .Net Framework 4.0

<httpRuntime maxUrlLength="1000" relaxedUrlToFileSystemMapping="true" />

To solve this, do this:

In the root web.config for your project, under the system.web node:

<system.web>
    <httpRuntime maxUrlLength="10999" maxQueryStringLength="2097151" />
...

In addition, I had to add this under the system.webServer node or I got a security error for my long query strings:

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxUrl="10999" maxQueryString="2097151" />
      </requestFiltering>
    </security>
...
David Richoz

Http.sys service is coded with default maximum of 260 characters per Url segment.

An "Url segment" in this context is the content between "/" characters in the Url. For example:

http://www.example.com/segment-one/segment-two/segment-three

The max allowed Url segment length can be changed with registry settings:

  • Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters
  • Value: UrlSegmentMaxLength
  • Type: REG_DWORD
  • Data: (Your desired new Url segment maximum allowed length, e.g. 4096)

More about http.sys settings: http://support.microsoft.com/kb/820129

The maximum allowed value is 32766. If a larger value is specified, it will be ignored. (Credit: Juan Mendes)

Restarting the PC is required to make a change to this setting take effect. (Credit: David Rettenbacher, Juan Mendes)

OK so part of the reason I posted this was also because we have found a work around.

I hope this will be useful to someone in the future :D

The workaround

The workaround is quite simple, and it's quite nice too.

Since we know which parts of the site will need to use dynamic parameters (and hence will have a dynamic path and length), we can avoid sending this long url to ASP.NET routing by intercepting it before it even hits ASP.NET

Enter IIS7 Url Rewriting (or any equivalent rewrite module).

We set up a rule like this:

    <rewrite>
        <rules>
            <rule>
                <rule name="Remove Category Request Parameters From Url">
                <match url="^category/(\d+)/{0,1}(.*)$" />
                <action type="Rewrite" url="category/{R:1}" />
            </rule>
        </rules>
    </rewrite>

Basically, what we're doing is just keeping enough of the path to be able to call the correct route downstream. The rest of the URL path we are hacking off.

Where does the rest of the URL go?

Well, when a rewrite rule is fired, the IIS7 URL Rewrite module automagically sets this header in the request:

HTTP_X_ORIGINAL_URL

Downstream, in the part of the app that parses the dynamic path, instead of looking at the path:

HttpContext.Request.Url.PathAndQuery

we look at that header instead:

HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]

Problem solved... almost!

The Snags

Accessing the Header

In case you need to know, to access the IIS7 Rewrite Module header, you can do so in two ways:

HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]

or

HttpContext.Request.Headers["X-ORIGINAL-URL"]

Fixing Relative Paths

What you will also notice is that, with the above setup, all relative paths break (URLs that were defined with a "~").

This includes URLs defined with the ASP.NET MVC HtmlHelper and UrlHelper methods (like Url.Route("Bla")).

This is where access to the ASP.NET MVC code is awesome.

In the System.Web.Mvc.PathHelper.GenerateClientUrlInternal() method, there is a check being made to see if the same URL Rewrite module header exists (see above):

// we only want to manipulate the path if URL rewriting is active, else we risk breaking the generated URL
NameValueCollection serverVars = httpContext.Request.ServerVariables;
bool urlRewriterIsEnabled = (serverVars != null && serverVars[_urlRewriterServerVar] != null);
if (!urlRewriterIsEnabled) {
    return contentPath;
}

If it does, some work is done to preserve the originating URL.

In our case, since we are not using URL rewriting in the "normal" way, we want to short circuit this process.

We want to pretend like no URL rewriting happened, since we don't want relative paths to be considered in the context of the original URL.

The simplest hack that I could think of was to remove that server variable completely, so ASP.NET MVC would not find it:

protected void Application_BeginRequest()
{
    string iis7UrlRewriteServerVariable = "HTTP_X_ORIGINAL_URL";

    string headerValue = Request.ServerVariables[iis7UrlRewriteServerVariable];

    if (String.IsNullOrEmpty(headerValue) == false)
    {
        Request.ServerVariables.Remove(iis7UrlRewriteServerVariable);

        Context.Items.Add(iis7UrlRewriteServerVariable, headerValue);
    }
}

(Note that, in the above method, I'm removing the header from Request.ServerVariables but still retaining it, stashing it in Context.Items. The reason for this is that I need access to the header value later on in the request pipe.)

Hope this helps!

I think you're trying to hard to use GET. Try changing the request method to POST and put those query string parameters into the request body.

Long URL does not help SEO as well, does it?

It appears that the hard-coded max URL length has been fixed in .NET 4.0. In particular, there is now a web.config section with:

<httpRuntime maxRequestPathLength="260" maxQueryStringLength="2048" /> 

that let you expand the range of allowed URLs.

I was having a similar max URL length issue using ASP.NET Web API 4, which generated a slightly different error:

404 Error

The fix for me was described above by updating the Web.config with BOTH of the following tags:

<system.web>
    <httpRuntime maxUrlLength="10999" maxQueryStringLength="2097151" />

and

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxUrl="10999" maxQueryString="2097151" />
      </requestFiltering>
    </security>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!