OK, so part of the reason I posted this was also because we found a job.
I hope this will be useful to someone in the future: D
Workaround
The workaround is quite simple, and it is also very pleasant.
Since we know which parts of the site will have to use dynamic parameters (and therefore will have a dynamic path and length), we can avoid sending this long URL to ASP.NET routing by intercepting it before it even gets into ASP . NET
Enter IIS7 Url Rewriting (or any equivalent rewrite module).
We have established the following rule:
<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 do just keeps enough paths to be able to call the right route downstream. The rest of the URL we are hacking.
Where is the remaining url located?
Well, when the rewrite rule is triggered, the Rewrite module of the IIS7 URL automatically sets this header in the request:
HTTP_X_ORIGINAL_URL
Downstream, in the part of the application that analyzes the dynamic path, instead of looking at the path:
HttpContext.Request.Url.PathAndQuery
instead, we look at this heading:
HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]
The problem is solved ... almost!
Snow
Heading access
If you need to know in order to access the IIS7 rewrite module header, you can do this in two ways:
HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]
or
HttpContext.Request.Headers["X-ORIGINAL-URL"]
Fix relative paths
What you will also notice is that with the above setting, all relative paths are interrupted (URLs that were identified with "~").
This includes URLs defined using the ASP.NET MVC HtmlHelper and UrlHelper (for example, Url.Route("Bla") ).
Access to ASP.NET MVC code is available here.
The System.Web.Mvc.PathHelper.GenerateClientUrlInternal() method checks to see if the same 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 so, some work is being done to keep the original URL.
In our case, since we do not use URL rewriting in the βnormalβ way, we want to shorten this process shortly.
We want to pretend that URL rewriting did not happen, because we do not want relative paths to be seen in the context of the original URL.
The easiest hack I could come up with was to completely remove this server variable, 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 remove the header from Request.ServerVariables , but save it by putting it in Context.Items . The reason for this is that I need access to the header value later on the request channel.)
Hope this helps!