diff --git a/src/AttributeRouting/Framework/AttributeRouteVisitor.cs b/src/AttributeRouting/Framework/AttributeRouteVisitor.cs
index cac2e00..fbc8f47 100644
--- a/src/AttributeRouting/Framework/AttributeRouteVisitor.cs
+++ b/src/AttributeRouting/Framework/AttributeRouteVisitor.cs
@@ -1,42 +1,42 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text.RegularExpressions;
+using System.Linq;
+using System.Text.RegularExpressions;
using System.Threading;
-using AttributeRouting.Helpers;
-
-namespace AttributeRouting.Framework
-{
- ///
- /// Visitor-ish used to extend implementations of .
- ///
- ///
- /// Due to different route implementations in
- /// System.Web.Routing (used for MVC controller routes) and
- /// System.Web.Http.Routing (used for Web API controller routes).
- ///
+using AttributeRouting.Helpers;
+
+namespace AttributeRouting.Framework
+{
+ ///
+ /// Visitor-ish used to extend implementations of .
+ ///
+ ///
+ /// Due to different route implementations in
+ /// System.Web.Routing (used for MVC controller routes) and
+ /// System.Web.Http.Routing (used for Web API controller routes).
+ ///
public class AttributeRouteVisitor
{
- private static readonly Regex PathAndQueryRegex = new Regex(@"(?[^\?]*)(?\?.*)?");
-
- private readonly IAttributeRoute _route;
+ private static readonly Regex PathAndQueryRegex = new Regex(@"(?[^\?]*)(?\?.*)?");
+
+ private readonly IAttributeRoute _route;
private readonly ConfigurationBase _configuration;
private string _staticLeftPartOfUrl;
-
- ///
- /// Creates a new visitor extending implementations of IAttributeRoute with common logic.
- ///
- /// The route
- /// The route's configuration
- public AttributeRouteVisitor(IAttributeRoute route, ConfigurationBase configuration)
- {
- if (route == null) throw new ArgumentNullException("route");
- if (configuration == null) throw new ArgumentNullException("configuration");
-
- _route = route;
- _configuration = configuration;
- }
-
+
+ ///
+ /// Creates a new visitor extending implementations of IAttributeRoute with common logic.
+ ///
+ /// The route
+ /// The route's configuration
+ public AttributeRouteVisitor(IAttributeRoute route, ConfigurationBase configuration)
+ {
+ if (route == null) throw new ArgumentNullException("route");
+ if (configuration == null) throw new ArgumentNullException("configuration");
+
+ _route = route;
+ _configuration = configuration;
+ }
+
private string StaticLeftPartOfUrl
{
get
@@ -50,12 +50,12 @@ private string StaticLeftPartOfUrl
}
return _staticLeftPartOfUrl;
}
- }
-
+ }
+
///
/// Adds querystring default values to route values collection if they aren't already present.
///
- /// The route values.
+ /// The route values.
public void AddQueryStringDefaultsToRouteValues(IDictionary routeValues)
{
foreach (var queryStringDefault in _route.QueryStringDefaults)
@@ -72,190 +72,190 @@ public void AddQueryStringDefaultsToRouteValues(IDictionary rout
routeValues.Add(queryStringDefault.Key, queryStringDefault.Value);
}
}
- }
-
- ///
- /// Performs lowercasing and appends trailing slash if this route is so configured.
- ///
- /// The current virtual path, after translation
- /// The final virtual path
- public string GetFinalVirtualPath(string virtualPath)
- {
- /**
- * Lowercase urls.
- * NOTE: The initial lowercasing of all BUT url params occurs in RouteBuilder.CreateRouteUrl().
- * This is just a final lowercasing of the final, parameter-replaced url.
- */
-
- var lower = _route.UseLowercaseRoute.GetValueOrDefault(_configuration.UseLowercaseRoutes);
- var preserve = _route.PreserveCaseForUrlParameters.GetValueOrDefault(_configuration.PreserveCaseForUrlParameters);
-
- if (lower && !preserve)
- {
- virtualPath = TransformVirtualPathToLowercase(virtualPath);
- }
-
- /**
- * Append trailing slashes
- */
-
- var appendTrailingSlash = _route.AppendTrailingSlash.GetValueOrDefault(_configuration.AppendTrailingSlash);
- if (appendTrailingSlash)
- {
- virtualPath = AppendTrailingSlashToVirtualPath(virtualPath);
- }
-
- return virtualPath;
- }
-
- ///
- /// Gets the translated virtual path for this route.
- ///
- ///
- /// The type of virtual path data to be returned.
- /// This varies based on whether the route is a
- /// System.Web.Routing.Route or System.Web.Http.Routing.HttpRoute.
- ///
- /// A delegate that can get the TVirtualPathData from a translated route
- /// Returns null if no translation is available.
- public TVirtualPathData GetTranslatedVirtualPath(Func fromTranslation)
- where TVirtualPathData : class
- {
- if (_route.Translations == null)
- {
- return null;
- }
-
- var translations = _route.Translations.ToArray();
- if (!translations.Any())
- {
- return null;
- }
-
- var currentCultureName = Thread.CurrentThread.CurrentUICulture.Name;
-
- // Try and get the language-culture translation, then fall back to language translation
- var translation = translations.FirstOrDefault(t => t.CultureName == currentCultureName)
- ?? translations.FirstOrDefault(t => currentCultureName.StartsWith(t.CultureName));
-
- if (translation == null)
- {
- return null;
- }
-
- return fromTranslation(translation);
}
- ///
- /// Tests whether the route matches the current UI culture.
- ///
- /// The name of the UI culture to test to test.
- ///
- public bool IsCultureNameMatched(string cultureName)
- {
- // If not constraining by culture, then do not apply this check.
- if (!_configuration.ConstrainTranslatedRoutesByCurrentUICulture)
- {
- return true;
- }
-
- // If no translations are available, then true.
- if (!_configuration.TranslationProviders.Any())
- {
- return true;
- }
-
- // Need the neutral culture as a fallback during matching.
- var neutralCultureName = cultureName.Split('-').First();
-
- if (_route.SourceLanguageRoute == null)
- {
- // This is a source language route:
-
- // Match if this route has no translations.
- var translations = _route.Translations.ToArray();
- if (!translations.Any())
- {
- return true;
- }
-
- // Match if this route has no translations for the current UI culture's language.
- if (!translations.Any(t => t.CultureName.ValueEquals(neutralCultureName)))
- {
- return true;
- }
- }
- else
- {
- // This is a translated route:
-
- var routeCultureName = _route.CultureName;
-
- // Match if the current UI culture is the culture of this route.
- if (cultureName.ValueEquals(routeCultureName))
- {
- return true;
- }
-
- // Match if:
- // - the route's culture name is neutral,
- // - and it matches the current UI culture's language,
- // - and no translation exists for the specific current UI culture.
- if (routeCultureName.Split('-').Length == 1 /* neutral culture name */
- && neutralCultureName == routeCultureName /* matches the current UI culture's language */
- && !_route.SourceLanguageRoute.Translations.Any(t => t.CultureName.ValueEquals(cultureName)))
- {
- return true;
- }
- }
-
- // Otherwise, don't match.
- return false;
- }
-
- ///
- /// Optimizes route matching by comparing the static left part of a route's URL with the requested path.
- ///
- /// The path of the requested URL.
- /// True if the requested URL path starts with the static left part of the route's URL.
- /// Thanks: http://samsaffron.com/archive/2011/10/13/optimising-asp-net-mvc3-routing
- public bool IsStaticLeftPartOfUrlMatched(string requestedPath)
- {
- // Compare the left part with the requested path
- var comparableRequestedPath = requestedPath.TrimEnd('/');
- return comparableRequestedPath.StartsWith(StaticLeftPartOfUrl, StringComparison.OrdinalIgnoreCase);
- }
-
- ///
- /// Tests whether the configured subdomain (if any) matches the current host.
- ///
- /// The subdomain part of the host from the current request
- /// True if the subdomain for this route matches the current request host.
- public bool IsSubdomainMatched(string requestedSubdomain)
- {
- // If no subdomains are mapped with AR, then yes.
- if (!_configuration.MappedSubdomains.Any())
- {
- return true;
- }
-
- // Match if subdomain is null and this route has no subdomain.
- if (requestedSubdomain.HasNoValue() && _route.Subdomain.HasNoValue())
- {
- return true;
- }
-
- // Match if this route is mapped to the requested host's subdomain
- var routeSubdomain = _route.Subdomain ?? _configuration.DefaultSubdomain;
- if (routeSubdomain.ValueEquals(requestedSubdomain))
- {
- return true;
- }
-
- // Otherwise, this route does not match the request.
- return false;
- }
-
+ ///
+ /// Performs lowercasing and appends trailing slash if this route is so configured.
+ ///
+ /// The current virtual path, after translation
+ /// The final virtual path
+ public string GetFinalVirtualPath(string virtualPath)
+ {
+ /**
+ * Lowercase urls.
+ * NOTE: The initial lowercasing of all BUT url params occurs in RouteBuilder.CreateRouteUrl().
+ * This is just a final lowercasing of the final, parameter-replaced url.
+ */
+
+ var lower = _route.UseLowercaseRoute.GetValueOrDefault(_configuration.UseLowercaseRoutes);
+ var preserve = _route.PreserveCaseForUrlParameters.GetValueOrDefault(_configuration.PreserveCaseForUrlParameters);
+
+ if (lower && !preserve)
+ {
+ virtualPath = TransformVirtualPathToLowercase(virtualPath);
+ }
+
+ /**
+ * Append trailing slashes
+ */
+
+ var appendTrailingSlash = _route.AppendTrailingSlash.GetValueOrDefault(_configuration.AppendTrailingSlash);
+ if (appendTrailingSlash)
+ {
+ virtualPath = AppendTrailingSlashToVirtualPath(virtualPath);
+ }
+
+ return virtualPath;
+ }
+
+ ///
+ /// Gets the translated virtual path for this route.
+ ///
+ ///
+ /// The type of virtual path data to be returned.
+ /// This varies based on whether the route is a
+ /// System.Web.Routing.Route or System.Web.Http.Routing.HttpRoute.
+ ///
+ /// A delegate that can get the TVirtualPathData from a translated route
+ /// Returns null if no translation is available.
+ public TVirtualPathData GetTranslatedVirtualPath(Func fromTranslation)
+ where TVirtualPathData : class
+ {
+ if (_route.Translations == null)
+ {
+ return null;
+ }
+
+ var translations = _route.Translations.ToArray();
+ if (!translations.Any())
+ {
+ return null;
+ }
+
+ var currentCultureName = Thread.CurrentThread.CurrentUICulture.Name;
+
+ // Try and get the language-culture translation, then fall back to language translation
+ var translation = translations.FirstOrDefault(t => t.CultureName == currentCultureName)
+ ?? translations.FirstOrDefault(t => currentCultureName.StartsWith(t.CultureName));
+
+ if (translation == null)
+ {
+ return null;
+ }
+
+ return fromTranslation(translation);
+ }
+
+ ///
+ /// Tests whether the route matches the current UI culture.
+ ///
+ /// The name of the UI culture to test to test.
+ ///
+ public bool IsCultureNameMatched(string cultureName)
+ {
+ // If not constraining by culture, then do not apply this check.
+ if (!_configuration.ConstrainTranslatedRoutesByCurrentUICulture)
+ {
+ return true;
+ }
+
+ // If no translations are available, then true.
+ if (!_configuration.TranslationProviders.Any())
+ {
+ return true;
+ }
+
+ // Need the neutral culture as a fallback during matching.
+ var neutralCultureName = cultureName.Split('-').First();
+
+ if (_route.SourceLanguageRoute == null)
+ {
+ // This is a source language route:
+
+ // Match if this route has no translations.
+ var translations = _route.Translations.ToArray();
+ if (!translations.Any())
+ {
+ return true;
+ }
+
+ // Match if this route has no translations for the current UI culture's language.
+ if (!translations.Any(t => t.CultureName.ValueEquals(neutralCultureName)))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ // This is a translated route:
+
+ var routeCultureName = _route.CultureName;
+
+ // Match if the current UI culture is the culture of this route.
+ if (cultureName.ValueEquals(routeCultureName))
+ {
+ return true;
+ }
+
+ // Match if:
+ // - the route's culture name is neutral,
+ // - and it matches the current UI culture's language,
+ // - and no translation exists for the specific current UI culture.
+ if (routeCultureName.Split('-').Length == 1 /* neutral culture name */
+ && neutralCultureName == routeCultureName /* matches the current UI culture's language */
+ && !_route.SourceLanguageRoute.Translations.Any(t => t.CultureName.ValueEquals(cultureName)))
+ {
+ return true;
+ }
+ }
+
+ // Otherwise, don't match.
+ return false;
+ }
+
+ ///
+ /// Optimizes route matching by comparing the static left part of a route's URL with the requested path.
+ ///
+ /// The path of the requested URL.
+ /// True if the requested URL path starts with the static left part of the route's URL.
+ /// Thanks: http://samsaffron.com/archive/2011/10/13/optimising-asp-net-mvc3-routing
+ public bool IsStaticLeftPartOfUrlMatched(string requestedPath)
+ {
+ // Compare the left part with the requested path
+ var comparableRequestedPath = requestedPath.TrimEnd('/').TrimStart('/');
+ return comparableRequestedPath.StartsWith(StaticLeftPartOfUrl, StringComparison.OrdinalIgnoreCase);
+ }
+
+ ///
+ /// Tests whether the configured subdomain (if any) matches the current host.
+ ///
+ /// The subdomain part of the host from the current request
+ /// True if the subdomain for this route matches the current request host.
+ public bool IsSubdomainMatched(string requestedSubdomain)
+ {
+ // If no subdomains are mapped with AR, then yes.
+ if (!_configuration.MappedSubdomains.Any())
+ {
+ return true;
+ }
+
+ // Match if subdomain is null and this route has no subdomain.
+ if (requestedSubdomain.HasNoValue() && _route.Subdomain.HasNoValue())
+ {
+ return true;
+ }
+
+ // Match if this route is mapped to the requested host's subdomain
+ var routeSubdomain = _route.Subdomain ?? _configuration.DefaultSubdomain;
+ if (routeSubdomain.ValueEquals(requestedSubdomain))
+ {
+ return true;
+ }
+
+ // Otherwise, this route does not match the request.
+ return false;
+ }
+
///
/// Processes query constraints separately from route constraints.
///
@@ -270,7 +270,7 @@ public bool IsSubdomainMatched(string requestedSubdomain)
/// that is not present in the url template. See logic in:
/// - System.Web.Http.Routing.HttpParsedRoute.Bind(...)
/// - System.Web.Routing.ParsedRoute.Bind(...)
- ///
+ ///
public bool ProcessQueryStringConstraints(Func