diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/Collections/Specialized/NameValueCollectionExtensions.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/Collections/Specialized/NameValueCollectionExtensions.cs new file mode 100644 index 00000000..29606e1d --- /dev/null +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/Collections/Specialized/NameValueCollectionExtensions.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Collections.Specialized; + +namespace MvcSiteMapProvider.Collections.Specialized +{ + /// + /// Provides extension methods for the . + /// + public static class NameValueCollectionExtensions + { + public static void AddWithCaseCorrection(this NameValueCollection nameValueCollection, string key, string value, IEnumerable correctCaseKeyset) + { + var loweredKey = key.ToLowerInvariant(); + foreach (var item in correctCaseKeyset) + { + if (item.ToLowerInvariant().Equals(loweredKey)) + { + // Add item with corrected case key + nameValueCollection.Add(item, value); + } + } + } + } +} diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/MvcSiteMapProvider.csproj b/src/MvcSiteMapProvider/MvcSiteMapProvider/MvcSiteMapProvider.csproj index 557d4d07..4b3949a0 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/MvcSiteMapProvider.csproj +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/MvcSiteMapProvider.csproj @@ -185,6 +185,7 @@ + diff --git a/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNode.cs b/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNode.cs index 872874a0..b26d7a06 100644 --- a/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNode.cs +++ b/src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNode.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Web; using System.Web.Mvc; using System.Web.Routing; @@ -620,7 +621,7 @@ protected virtual void PreserveRouteParameters() { var requestContext = this.mvcContextFactory.CreateRequestContext(); var routeDataValues = requestContext.RouteData.Values; - var queryStringValues = requestContext.HttpContext.Request.QueryString; + var queryStringValues = this.GetCaseCorrectedQueryString(requestContext.HttpContext); foreach (var item in this.PreservedRouteParameters) { @@ -642,6 +643,47 @@ protected virtual void PreserveRouteParameters() } } + /// + /// Gets a containing the query string + /// key value pairs for the passed in HTTP context. The casing of the keys corrected to be the same as the values that are + /// configured either in the dictionary or the collection. + /// + /// The HTTP context. + /// A containing the case-corrected + /// key value pairs of the query string. + protected virtual NameValueCollection GetCaseCorrectedQueryString(HttpContextBase httpContext) + { + var queryStringValues = httpContext.Request.QueryString; + // Note: we must use the configured route values, rather than the RouteValue property to avoid an + // infinite loop. + var caseInsensitiveRouteKeys = new HashSet(this.routeValues.Keys, StringComparer.InvariantCultureIgnoreCase); + var caseInsensitivePreservedRouteParameters = new HashSet(this.PreservedRouteParameters, StringComparer.InvariantCultureIgnoreCase); + var result = new NameValueCollection(); + + foreach (var key in queryStringValues.AllKeys) + { + // A malformed URL could have a null key + if (key != null) + { + if (caseInsensitivePreservedRouteParameters.Contains(key)) + { + result.AddWithCaseCorrection(key, queryStringValues[key], caseInsensitivePreservedRouteParameters); + } + else if (caseInsensitiveRouteKeys.Contains(key)) + { + result.AddWithCaseCorrection(key, queryStringValues[key], caseInsensitiveRouteKeys); + } + else + { + // If the value is not configured, add it to the dictionary with the original case. + result.Add(key, queryStringValues[key]); + } + } + } + + return result; + } + /// /// Flag to ensure the route values are only preserved from the current request a single time. /// @@ -718,7 +760,7 @@ protected virtual IDictionary MergeRouteValuesAndNamedQueryStrin var result = new Dictionary(routeValues); // Add any query string values from the current context - var queryStringValues = httpContext.Request.QueryString; + var queryStringValues = this.GetCaseCorrectedQueryString(httpContext); // QueryString collection might contain nullable keys foreach (var key in queryStringValues.AllKeys)