From 85225055b99fe7a1337e5563004a7466d5fca460 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Thu, 6 Feb 2014 11:56:48 -0800 Subject: [PATCH] removing datatokens/constraints/url-generation --- .../Template/BoundRouteTemplate.cs | 16 - .../Template/ITemplateRouteConstraint.cs | 12 - .../Template/IVirtualPathData.cs | 11 - .../Template/RouteDirection.cs | 10 - .../Template/TemplateParsedRoute.cs | 463 +---- .../Template/TemplateRoute.cs | 198 +- .../Template/VirtualPathData.cs | 42 - .../Template/TemplateRouteTests.cs | 1742 +---------------- 8 files changed, 73 insertions(+), 2421 deletions(-) delete mode 100644 src/Microsoft.AspNet.Routing/Template/BoundRouteTemplate.cs delete mode 100644 src/Microsoft.AspNet.Routing/Template/ITemplateRouteConstraint.cs delete mode 100644 src/Microsoft.AspNet.Routing/Template/IVirtualPathData.cs delete mode 100644 src/Microsoft.AspNet.Routing/Template/RouteDirection.cs delete mode 100644 src/Microsoft.AspNet.Routing/Template/VirtualPathData.cs diff --git a/src/Microsoft.AspNet.Routing/Template/BoundRouteTemplate.cs b/src/Microsoft.AspNet.Routing/Template/BoundRouteTemplate.cs deleted file mode 100644 index 8d73a43..0000000 --- a/src/Microsoft.AspNet.Routing/Template/BoundRouteTemplate.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace Microsoft.AspNet.Routing.Template -{ - /// - /// Represents a URI generated from a . - /// - public class BoundRouteTemplate - { - public string BoundTemplate { get; set; } - - public IDictionary Values { get; set; } - } -} diff --git a/src/Microsoft.AspNet.Routing/Template/ITemplateRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Template/ITemplateRouteConstraint.cs deleted file mode 100644 index 4f70d73..0000000 --- a/src/Microsoft.AspNet.Routing/Template/ITemplateRouteConstraint.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -using System.Collections.Generic; -using Microsoft.AspNet.Abstractions; - -namespace Microsoft.AspNet.Routing.Template -{ - public interface ITemplateRouteConstraint - { - bool Match(HttpContext context, IRoute route, string parameterName, IDictionary values, RouteDirection routeDirection); - } -} diff --git a/src/Microsoft.AspNet.Routing/Template/IVirtualPathData.cs b/src/Microsoft.AspNet.Routing/Template/IVirtualPathData.cs deleted file mode 100644 index f7f2caf..0000000 --- a/src/Microsoft.AspNet.Routing/Template/IVirtualPathData.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -namespace Microsoft.AspNet.Routing.Template -{ - public interface IVirtualPathData - { - IRoute Route { get; } - - string VirtualPath { get; set; } - } -} diff --git a/src/Microsoft.AspNet.Routing/Template/RouteDirection.cs b/src/Microsoft.AspNet.Routing/Template/RouteDirection.cs deleted file mode 100644 index 7f9bcc6..0000000 --- a/src/Microsoft.AspNet.Routing/Template/RouteDirection.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -namespace Microsoft.AspNet.Routing.Template -{ - public enum RouteDirection - { - UriResolution = 0, - UriGeneration - } -} diff --git a/src/Microsoft.AspNet.Routing/Template/TemplateParsedRoute.cs b/src/Microsoft.AspNet.Routing/Template/TemplateParsedRoute.cs index 9b65710..49db341 100644 --- a/src/Microsoft.AspNet.Routing/Template/TemplateParsedRoute.cs +++ b/src/Microsoft.AspNet.Routing/Template/TemplateParsedRoute.cs @@ -2,16 +2,12 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; -using System.Globalization; using System.Linq; -using System.Text; -using System.Text.RegularExpressions; namespace Microsoft.AspNet.Routing.Template { - public sealed class TemplateParsedRoute + public class TemplateParsedRoute { public TemplateParsedRoute(IList pathSegments) { @@ -21,392 +17,6 @@ namespace Microsoft.AspNet.Routing.Template internal IList PathSegments { get; private set; } - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Not changing original algorithm")] - [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode", Justification = "Not changing original algorithm")] - public BoundRouteTemplate Bind(IDictionary currentValues, IDictionary values, IDictionary defaultValues, IDictionary constraints) - { - if (currentValues == null) - { - currentValues = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - - if (values == null) - { - values = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - - if (defaultValues == null) - { - defaultValues = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - - // The set of values we should be using when generating the URI in this route - IDictionary acceptedValues = new Dictionary(StringComparer.OrdinalIgnoreCase); - - // Keep track of which new values have been used - HashSet unusedNewValues = new HashSet(values.Keys, StringComparer.OrdinalIgnoreCase); - - // Step 1: Get the list of values we're going to try to use to match and generate this URI - - // Find out which entries in the URI are valid for the URI we want to generate. - // If the URI had ordered parameters a="1", b="2", c="3" and the new values - // specified that b="9", then we need to invalidate everything after it. The new - // values should then be a="1", b="9", c=. - ForEachParameter(PathSegments, delegate(PathParameterSubsegment parameterSubsegment) - { - // If it's a parameter subsegment, examine the current value to see if it matches the new value - string parameterName = parameterSubsegment.ParameterName; - - object newParameterValue; - bool hasNewParameterValue = values.TryGetValue(parameterName, out newParameterValue); - if (hasNewParameterValue) - { - unusedNewValues.Remove(parameterName); - } - - object currentParameterValue; - bool hasCurrentParameterValue = currentValues.TryGetValue(parameterName, out currentParameterValue); - - if (hasNewParameterValue && hasCurrentParameterValue) - { - if (!RoutePartsEqual(currentParameterValue, newParameterValue)) - { - // Stop copying current values when we find one that doesn't match - return false; - } - } - - // If the parameter is a match, add it to the list of values we will use for URI generation - if (hasNewParameterValue) - { - if (IsRoutePartNonEmpty(newParameterValue)) - { - acceptedValues.Add(parameterName, newParameterValue); - } - } - else - { - if (hasCurrentParameterValue) - { - acceptedValues.Add(parameterName, currentParameterValue); - } - } - return true; - }); - - // Add all remaining new values to the list of values we will use for URI generation - foreach (var newValue in values) - { - if (IsRoutePartNonEmpty(newValue.Value)) - { - if (!acceptedValues.ContainsKey(newValue.Key)) - { - acceptedValues.Add(newValue.Key, newValue.Value); - } - } - } - - // Add all current values that aren't in the URI at all - foreach (var currentValue in currentValues) - { - string parameterName = currentValue.Key; - if (!acceptedValues.ContainsKey(parameterName)) - { - PathParameterSubsegment parameterSubsegment = GetParameterSubsegment(PathSegments, parameterName); - if (parameterSubsegment == null) - { - acceptedValues.Add(parameterName, currentValue.Value); - } - } - } - - // Add all remaining default values from the route to the list of values we will use for URI generation - ForEachParameter(PathSegments, delegate(PathParameterSubsegment parameterSubsegment) - { - if (!acceptedValues.ContainsKey(parameterSubsegment.ParameterName)) - { - object defaultValue; - if (!IsParameterRequired(parameterSubsegment, defaultValues, out defaultValue)) - { - // Add the default value only if there isn't already a new value for it and - // only if it actually has a default value, which we determine based on whether - // the parameter value is required. - acceptedValues.Add(parameterSubsegment.ParameterName, defaultValue); - } - } - return true; - }); - - // All required parameters in this URI must have values from somewhere (i.e. the accepted values) - bool hasAllRequiredValues = ForEachParameter(PathSegments, delegate(PathParameterSubsegment parameterSubsegment) - { - object defaultValue; - if (IsParameterRequired(parameterSubsegment, defaultValues, out defaultValue)) - { - if (!acceptedValues.ContainsKey(parameterSubsegment.ParameterName)) - { - // If the route parameter value is required that means there's - // no default value, so if there wasn't a new value for it - // either, this route won't match. - return false; - } - } - return true; - }); - if (!hasAllRequiredValues) - { - return null; - } - - // All other default values must match if they are explicitly defined in the new values - IDictionary otherDefaultValues = new Dictionary(defaultValues, StringComparer.OrdinalIgnoreCase); - ForEachParameter(PathSegments, delegate(PathParameterSubsegment parameterSubsegment) - { - otherDefaultValues.Remove(parameterSubsegment.ParameterName); - return true; - }); - - foreach (var defaultValue in otherDefaultValues) - { - object value; - if (values.TryGetValue(defaultValue.Key, out value)) - { - unusedNewValues.Remove(defaultValue.Key); - if (!RoutePartsEqual(value, defaultValue.Value)) - { - // If there is a non-parameterized value in the route and there is a - // new value for it and it doesn't match, this route won't match. - return null; - } - } - } - - // Step 2: If the route is a match generate the appropriate URI - - StringBuilder uri = new StringBuilder(); - StringBuilder pendingParts = new StringBuilder(); - - bool pendingPartsAreAllSafe = false; - bool blockAllUriAppends = false; - - for (int i = 0; i < PathSegments.Count; i++) - { - PathSegment pathSegment = PathSegments[i]; // parsedRouteUriPart - - if (pathSegment is PathSeparatorSegment) - { - if (pendingPartsAreAllSafe) - { - // Accept - if (pendingParts.Length > 0) - { - if (blockAllUriAppends) - { - return null; - } - - // Append any pending literals to the URI - uri.Append(pendingParts.ToString()); - pendingParts.Length = 0; - } - } - pendingPartsAreAllSafe = false; - - // Guard against appending multiple separators for empty segments - if (pendingParts.Length > 0 && pendingParts[pendingParts.Length - 1] == '/') - { - // Dev10 676725: Route should not be matched if that causes mismatched tokens - // Dev11 86819: We will allow empty matches if all subsequent segments are null - if (blockAllUriAppends) - { - return null; - } - - // Append any pending literals to the URI (without the trailing slash) and prevent any future appends - uri.Append(pendingParts.ToString(0, pendingParts.Length - 1)); - pendingParts.Length = 0; - blockAllUriAppends = true; - } - else - { - pendingParts.Append("/"); - } - } - else - { - PathContentSegment contentPathSegment = pathSegment as PathContentSegment; - if (contentPathSegment != null) - { - // Segments are treated as all-or-none. We should never output a partial segment. - // If we add any subsegment of this segment to the generated URI, we have to add - // the complete match. For example, if the subsegment is "{p1}-{p2}.xml" and we - // used a value for {p1}, we have to output the entire segment up to the next "/". - // Otherwise we could end up with the partial segment "v1" instead of the entire - // segment "v1-v2.xml". - bool addedAnySubsegments = false; - - foreach (PathSubsegment subsegment in contentPathSegment.Subsegments) - { - PathLiteralSubsegment literalSubsegment = subsegment as PathLiteralSubsegment; - if (literalSubsegment != null) - { - // If it's a literal we hold on to it until we are sure we need to add it - pendingPartsAreAllSafe = true; - pendingParts.Append(literalSubsegment.Literal); - } - else - { - PathParameterSubsegment parameterSubsegment = subsegment as PathParameterSubsegment; - if (parameterSubsegment != null) - { - if (pendingPartsAreAllSafe) - { - // Accept - if (pendingParts.Length > 0) - { - if (blockAllUriAppends) - { - return null; - } - - // Append any pending literals to the URI - uri.Append(pendingParts.ToString()); - pendingParts.Length = 0; - - addedAnySubsegments = true; - } - } - pendingPartsAreAllSafe = false; - - // If it's a parameter, get its value - object acceptedParameterValue; - bool hasAcceptedParameterValue = acceptedValues.TryGetValue(parameterSubsegment.ParameterName, out acceptedParameterValue); - if (hasAcceptedParameterValue) - { - unusedNewValues.Remove(parameterSubsegment.ParameterName); - } - - object defaultParameterValue; - defaultValues.TryGetValue(parameterSubsegment.ParameterName, out defaultParameterValue); - - if (RoutePartsEqual(acceptedParameterValue, defaultParameterValue)) - { - // If the accepted value is the same as the default value, mark it as pending since - // we won't necessarily add it to the URI we generate. - pendingParts.Append(Convert.ToString(acceptedParameterValue, CultureInfo.InvariantCulture)); - } - else - { - if (blockAllUriAppends) - { - return null; - } - - // Add the new part to the URI as well as any pending parts - if (pendingParts.Length > 0) - { - // Append any pending literals to the URI - uri.Append(pendingParts.ToString()); - pendingParts.Length = 0; - } - uri.Append(Convert.ToString(acceptedParameterValue, CultureInfo.InvariantCulture)); - - addedAnySubsegments = true; - } - } - else - { - Contract.Assert(false, "Invalid path subsegment type"); - } - } - } - - if (addedAnySubsegments) - { - // See comment above about why we add the pending parts - if (pendingParts.Length > 0) - { - if (blockAllUriAppends) - { - return null; - } - - // Append any pending literals to the URI - uri.Append(pendingParts.ToString()); - pendingParts.Length = 0; - } - } - } - else - { - Contract.Assert(false, "Invalid path segment type"); - } - } - } - - if (pendingPartsAreAllSafe) - { - // Accept - if (pendingParts.Length > 0) - { - if (blockAllUriAppends) - { - return null; - } - - // Append any pending literals to the URI - uri.Append(pendingParts.ToString()); - } - } - - // Process constraints keys - if (constraints != null) - { - // If there are any constraints, mark all the keys as being used so that we don't - // generate query string items for custom constraints that don't appear as parameters - // in the URI format. - foreach (var constraintsItem in constraints) - { - unusedNewValues.Remove(constraintsItem.Key); - } - } - - // Encode the URI before we append the query string, otherwise we would double encode the query string - StringBuilder encodedUri = new StringBuilder(); - encodedUri.Append(UriEncode(uri.ToString())); - uri = encodedUri; - - // Add remaining new values as query string parameters to the URI - if (unusedNewValues.Count > 0) - { - // Generate the query string - bool firstParam = true; - foreach (string unusedNewValue in unusedNewValues) - { - object value; - if (acceptedValues.TryGetValue(unusedNewValue, out value)) - { - uri.Append(firstParam ? '?' : '&'); - firstParam = false; - uri.Append(Uri.EscapeDataString(unusedNewValue)); - uri.Append('='); - uri.Append(Uri.EscapeDataString(Convert.ToString(value, CultureInfo.InvariantCulture))); - } - } - } - - return new BoundRouteTemplate - { - BoundTemplate = uri.ToString(), - Values = acceptedValues - }; - } - - private static string EscapeReservedCharacters(Match m) - { - return "%" + Convert.ToUInt16(m.Value[0]).ToString("x2", CultureInfo.InvariantCulture); - } - private static bool ForEachParameter(IList pathSegments, Func action) { for (int i = 0; i < pathSegments.Count; i++) @@ -458,47 +68,6 @@ namespace Microsoft.AspNet.Routing.Template return true; } - private static PathParameterSubsegment GetParameterSubsegment(IList pathSegments, string parameterName) - { - PathParameterSubsegment foundParameterSubsegment = null; - - ForEachParameter(pathSegments, delegate(PathParameterSubsegment parameterSubsegment) - { - if (String.Equals(parameterName, parameterSubsegment.ParameterName, StringComparison.OrdinalIgnoreCase)) - { - foundParameterSubsegment = parameterSubsegment; - return false; - } - else - { - return true; - } - }); - - return foundParameterSubsegment; - } - - private static bool IsParameterRequired(PathParameterSubsegment parameterSubsegment, IDictionary defaultValues, out object defaultValue) - { - if (parameterSubsegment.IsCatchAll) - { - defaultValue = null; - return false; - } - - return !defaultValues.TryGetValue(parameterSubsegment.ParameterName, out defaultValue); - } - - private static bool IsRoutePartNonEmpty(object routePart) - { - string routePartString = routePart as string; - if (routePartString != null) - { - return routePartString.Length > 0; - } - return routePart != null; - } - public IDictionary Match(string virtualPath, IDictionary defaultValues) { IList requestPathSegments = TemplateRouteParser.SplitUriToPathSegmentStrings(virtualPath); @@ -808,35 +377,5 @@ namespace Microsoft.AspNet.Routing.Template return true; } } - - private static bool RoutePartsEqual(object a, object b) - { - string sa = a as string; - string sb = b as string; - if (sa != null && sb != null) - { - // For strings do a case-insensitive comparison - return String.Equals(sa, sb, StringComparison.OrdinalIgnoreCase); - } - else - { - if (a != null && b != null) - { - // Explicitly call .Equals() in case it is overridden in the type - return a.Equals(b); - } - else - { - // At least one of them is null. Return true if they both are - return a == b; - } - } - } - - private static string UriEncode(string str) - { - string escape = Uri.EscapeUriString(str); - return Regex.Replace(escape, "([#?])", new MatchEvaluator(EscapeReservedCharacters)); - } } } diff --git a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs index c0ab8dc..76f4a68 100644 --- a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs +++ b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs @@ -2,68 +2,34 @@ using System; using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text.RegularExpressions; -using Microsoft.AspNet.Abstractions; namespace Microsoft.AspNet.Routing.Template { - /// - /// Route class for self-host (i.e. hosted outside of ASP.NET). This class is mostly the - /// same as the System.Web.Routing.Route implementation. - /// This class has the same URL matching functionality as System.Web.Routing.Route. However, - /// in order for this route to match when generating URLs, a special "httproute" key must be - /// specified when generating the URL. - /// public class TemplateRoute : IRoute { - /// - /// Key used to signify that a route URL generation request should include HTTP routes (e.g. Web API). - /// If this key is not specified then no HTTP routes will match. - /// - public static readonly string HttpRouteKey = "httproute"; + private readonly IDictionary _defaults; + private readonly IRouteEndpoint _endpoint; + private readonly TemplateParsedRoute _parsedRoute; + private readonly string _routeTemplate; - private string _routeTemplate; - private IDictionary _defaults; - private IDictionary _constraints; - private IDictionary _dataTokens; - - public TemplateRoute() - : this(routeTemplate: null, defaults: null, constraints: null, dataTokens: null, handler: null) + public TemplateRoute(IRouteEndpoint endpoint, string routeTemplate) + : this(endpoint, routeTemplate, null) { } - public TemplateRoute(string routeTemplate) - : this(routeTemplate, defaults: null, constraints: null, dataTokens: null, handler: null) + public TemplateRoute(IRouteEndpoint endpoint, string routeTemplate, IDictionary defaults) { - } + if (endpoint == null) + { + throw new ArgumentNullException("endpoint"); + } - public TemplateRoute(string routeTemplate, IDictionary defaults) - : this(routeTemplate, defaults, constraints: null, dataTokens: null, handler: null) - { - } - - public TemplateRoute(string routeTemplate, IDictionary defaults, IDictionary constraints) - : this(routeTemplate, defaults, constraints, dataTokens: null, handler: null) - { - } - - public TemplateRoute(string routeTemplate, IDictionary defaults, IDictionary constraints, IDictionary dataTokens) - : this(routeTemplate, defaults, constraints, dataTokens, handler: null) - { - } - - public TemplateRoute(string routeTemplate, IDictionary defaults, IDictionary constraints, IDictionary dataTokens, IRouteEndpoint handler) - { + _endpoint = endpoint; _routeTemplate = routeTemplate == null ? String.Empty : routeTemplate; _defaults = defaults ?? new Dictionary(StringComparer.OrdinalIgnoreCase); - _constraints = constraints ?? new Dictionary(StringComparer.OrdinalIgnoreCase); - _dataTokens = dataTokens ?? new Dictionary(StringComparer.OrdinalIgnoreCase); - Handler = handler; // The parser will throw for invalid routes. - ParsedRoute = TemplateRouteParser.Parse(RouteTemplate); + _parsedRoute = TemplateRouteParser.Parse(RouteTemplate); } public IDictionary Defaults @@ -71,159 +37,39 @@ namespace Microsoft.AspNet.Routing.Template get { return _defaults; } } - public IDictionary Constraints + public IRouteEndpoint Endpoint { - get { return _constraints; } + get { return _endpoint; } } - public IDictionary DataTokens - { - get { return _dataTokens; } - } - - public IRouteEndpoint Handler { get; private set; } - public string RouteTemplate { get { return _routeTemplate; } } - internal TemplateParsedRoute ParsedRoute { get; private set; } - - public virtual RouteMatch GetRouteData(HttpContext request) + public virtual RouteMatch Match(RouteContext context) { - if (request == null) + if (context == null) { - throw new ArgumentNullException("request"); + throw new ArgumentNullException("context"); } - var requestPath = request.Request.Path.Value; + var requestPath = context.RequestPath; if (!String.IsNullOrEmpty(requestPath) && requestPath[0] == '/') { requestPath = requestPath.Substring(1); } - IDictionary values = ParsedRoute.Match(requestPath, _defaults); + IDictionary values = _parsedRoute.Match(requestPath, _defaults); if (values == null) { // If we got back a null value set, that means the URI did not match return null; } - - // Validate the values - if (!ProcessConstraints(request, values, RouteDirection.UriResolution)) + else { - return null; + return new RouteMatch(_endpoint, values); } - - return new RouteMatch(null, values); - } - - /// - /// Attempt to generate a URI that represents the values passed in based on current - /// values from the and new values using the specified . - /// - /// The HTTP request message. - /// The route values. - /// A instance or null if URI cannot be generated. - public virtual IVirtualPathData GetVirtualPath(HttpContext request, IDictionary values) - { - if (request == null) - { - throw new ArgumentNullException("request"); - } - - // Only perform URL generation if the "httproute" key was specified. This allows these - // routes to be ignored when a regular MVC app tries to generate URLs. Without this special - // key an HTTP route used for Web API would normally take over almost all the routes in a - // typical app. - if (values != null && !values.Keys.Contains(HttpRouteKey, StringComparer.OrdinalIgnoreCase)) - { - return null; - } - // Remove the value from the collection so that it doesn't affect the generated URL - var newValues = GetRouteDictionaryWithoutHttpRouteKey(values); - - IRouteValues routeData = request.GetFeature(); - IDictionary requestValues = routeData == null ? null : routeData.Values; - - BoundRouteTemplate result = ParsedRoute.Bind(requestValues, newValues, _defaults, _constraints); - if (result == null) - { - return null; - } - - // Assert that the route matches the validation rules - if (!ProcessConstraints(request, result.Values, RouteDirection.UriGeneration)) - { - return null; - } - - return new VirtualPathData(this, result.BoundTemplate); - } - - private static IDictionary GetRouteDictionaryWithoutHttpRouteKey(IDictionary routeValues) - { - var newRouteValues = new Dictionary(StringComparer.OrdinalIgnoreCase); - if (routeValues != null) - { - foreach (var routeValue in routeValues) - { - if (!String.Equals(routeValue.Key, HttpRouteKey, StringComparison.OrdinalIgnoreCase)) - { - newRouteValues.Add(routeValue.Key, routeValue.Value); - } - } - } - return newRouteValues; - } - - protected virtual bool ProcessConstraint(HttpContext request, object constraint, string parameterName, IDictionary values, RouteDirection routeDirection) - { - ITemplateRouteConstraint customConstraint = constraint as ITemplateRouteConstraint; - if (customConstraint != null) - { - return customConstraint.Match(request, this, parameterName, values, routeDirection); - } - - // If there was no custom constraint, then treat the constraint as a string which represents a Regex. - string constraintsRule = constraint as string; - if (constraintsRule == null) - { - throw new InvalidOperationException(String.Format( - CultureInfo.CurrentCulture, - Resources.TemplateRoute_ValidationMustBeStringOrCustomConstraint, - parameterName, - RouteTemplate, - typeof(ITemplateRouteConstraint).Name)); - } - - object parameterValue; - values.TryGetValue(parameterName, out parameterValue); - string parameterValueString = Convert.ToString(parameterValue, CultureInfo.InvariantCulture); - string constraintsRegEx = "^(" + constraintsRule + ")$"; - return Regex.IsMatch(parameterValueString, constraintsRegEx, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); - } - - private bool ProcessConstraints(HttpContext request, IDictionary values, RouteDirection routeDirection) - { - if (Constraints != null) - { - foreach (KeyValuePair constraintsItem in Constraints) - { - if (!ProcessConstraint(request, constraintsItem.Value, constraintsItem.Key, values, routeDirection)) - { - return false; - } - } - } - - return true; - } - - public RouteMatch Match(RouteContext context) - { - throw new NotImplementedException(); } } } diff --git a/src/Microsoft.AspNet.Routing/Template/VirtualPathData.cs b/src/Microsoft.AspNet.Routing/Template/VirtualPathData.cs deleted file mode 100644 index e6ec047..0000000 --- a/src/Microsoft.AspNet.Routing/Template/VirtualPathData.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. - -using System; -namespace Microsoft.AspNet.Routing.Template -{ - public class VirtualPathData : IVirtualPathData - { - private string _virtualPath; - - public VirtualPathData(IRoute route, string virtualPath) - { - if (route == null) - { - throw new ArgumentNullException("route"); - } - - if (virtualPath == null) - { - throw new ArgumentNullException("virtualPath"); - } - - Route = route; - VirtualPath = virtualPath; - } - - public IRoute Route { get; private set; } - - public string VirtualPath - { - get { return _virtualPath; } - set - { - if (value == null) - { - throw new ArgumentNullException("value"); - } - - _virtualPath = value; - } - } - } -} diff --git a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs index c8e6c20..5c52254 100644 --- a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs +++ b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs @@ -2,9 +2,9 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Threading; +using System.Threading.Tasks; using Microsoft.AspNet.Abstractions; using Xunit; @@ -12,24 +12,6 @@ namespace Microsoft.AspNet.Routing.Template.Tests { public class TemplateRouteTests { - [Fact] - public void GetRouteDataWithConstraintsThatIsNotStringThrows() - { - // Arrange - HttpContext context = GetHttpContext("~/category/33"); - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = 5 }), - null); - - // Act - Assert.Throws(() => r.GetRouteData(context), - "The constraint entry 'category' on the route with route template 'category/{category}' must have a string value or " + - "be of a type which implements 'ITemplateRouteConstraint'."); - } - - [Fact] public void MatchSingleRoute() { @@ -38,7 +20,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("{controller}/{action}/{id}", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.Equal("Bank", rd.Values["controller"]); @@ -54,7 +36,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("{controller}/{action}/{id}", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.Null(rd); @@ -65,10 +47,10 @@ namespace Microsoft.AspNet.Routing.Template.Tests { // Arrange HttpContext context = GetHttpContext("~/Bank/DoAction"); - TemplateRoute r = CreateRoute("{controller}/{action}/{id}", new RouteValueDictionary(new { id = "default id" }), null); + TemplateRoute r = CreateRoute("{controller}/{action}/{id}", new RouteValueDictionary(new { id = "default id" })); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.Equal("Bank", rd.Values["controller"]); @@ -76,52 +58,15 @@ namespace Microsoft.AspNet.Routing.Template.Tests Assert.Equal("default id", rd.Values["id"]); } -#if URLGENERATION - - [Fact] - public void MatchSingleRouteWithEmptyDefaults() - { - IHttpVirtualPathData data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}", new RouteValueDictionary(new { val1 = "", val2 = "" }), new RouteValueDictionary(new { val2 = "SomeVal2" })); - Assert.Null(data); - - data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}", new RouteValueDictionary(new { val1 = "", val2 = "" }), new RouteValueDictionary(new { val1 = "a" })); - Assert.Equal("Test/a", data.VirtualPath); - - data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}", new RouteValueDictionary(new { val1 = "", val3 = "" }), new RouteValueDictionary(new { val2 = "a" })); - Assert.Null(data); - - data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}", new RouteValueDictionary(new { val1 = "", val2 = "" }), new RouteValueDictionary(new { val1 = "a", val2 = "b" })); - Assert.Equal("Test/a/b", data.VirtualPath); - - data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}", new RouteValueDictionary(new { val1 = "", val2 = "", val3 = "" }), new RouteValueDictionary(new { val1 = "a", val2 = "b", val3 = "c" })); - Assert.Equal("Test/a/b/c", data.VirtualPath); - - data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}", new RouteValueDictionary(new { val1 = "", val2 = "", val3 = "" }), new RouteValueDictionary(new { val1 = "a", val2 = "b" })); - Assert.Equal("Test/a/b", data.VirtualPath); - - data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}", new RouteValueDictionary(new { val1 = "", val2 = "", val3 = "" }), new RouteValueDictionary(new { val1 = "a" })); - Assert.Equal("Test/a", data.VirtualPath); - - } - - private IHttpVirtualPathData GetVirtualPathFromRoute(string path, string template, RouteValueDictionary defaults, RouteValueDictionary values) - { - TemplateRoute r = CreateRoute(template, defaults, null); - - HttpContext context = GetHttpContext(path); - return r.GetVirtualPath(context, values); - } -#endif - [Fact] public void NoMatchSingleRouteWithDefaults() { // Arrange HttpContext context = GetHttpContext("~/Bank"); - TemplateRoute r = CreateRoute("{controller}/{action}/{id}", new RouteValueDictionary(new { id = "default id" }), null); + TemplateRoute r = CreateRoute("{controller}/{action}/{id}", new RouteValueDictionary(new { id = "default id" })); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.Null(rd); @@ -132,10 +77,10 @@ namespace Microsoft.AspNet.Routing.Template.Tests { // Arrange HttpContext context = GetHttpContext("~/moo/111/bar/222"); - TemplateRoute r = CreateRoute("moo/{p1}/bar/{p2}", new RouteValueDictionary(new { p2 = "default p2" }), null); + TemplateRoute r = CreateRoute("moo/{p1}/bar/{p2}", new RouteValueDictionary(new { p2 = "default p2" })); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.Equal("111", rd.Values["p1"]); @@ -147,10 +92,10 @@ namespace Microsoft.AspNet.Routing.Template.Tests { // Arrange HttpContext context = GetHttpContext("~/moo/111/bar/"); - TemplateRoute r = CreateRoute("moo/{p1}/bar/{p2}", new RouteValueDictionary(new { p2 = "default p2" }), null); + TemplateRoute r = CreateRoute("moo/{p1}/bar/{p2}", new RouteValueDictionary(new { p2 = "default p2" })); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.Equal("111", rd.Values["p1"]); @@ -165,7 +110,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("moo/bar", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -180,7 +125,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("moo/bars", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.Null(rd); @@ -194,7 +139,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("moo/bar", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -209,7 +154,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("moo/bar/", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -224,7 +169,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("{p1}/{p2}/", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -240,7 +185,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("{p1}/{p2}/baz", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.Null(rd); @@ -254,7 +199,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("{p1}", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.Null(rd); @@ -268,7 +213,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("DEFAULT.ASPX", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -280,7 +225,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute(route, null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -304,10 +249,10 @@ namespace Microsoft.AspNet.Routing.Template.Tests { // Arrange HttpContext context = GetHttpContext("~/v1"); - TemplateRoute r = CreateRoute("{p1}/{p2}", new RouteValueDictionary(new { p2 = (string)null, foo = "bar" }), null); + TemplateRoute r = CreateRoute("{p1}/{p2}", new RouteValueDictionary(new { p2 = (string)null, foo = "bar" })); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -324,11 +269,10 @@ namespace Microsoft.AspNet.Routing.Template.Tests HttpContext context = GetHttpContext("~/date/2007/08"); TemplateRoute r = CreateRoute( "date/{y}/{m}/{d}", - new RouteValueDictionary(new { controller = "blog", action = "showpost", m = (string)null, d = (string)null }), - null); + new RouteValueDictionary(new { controller = "blog", action = "showpost", m = (string)null, d = (string)null })); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -340,114 +284,6 @@ namespace Microsoft.AspNet.Routing.Template.Tests Assert.Null(rd.Values["d"]); } - [Fact] - public void GetRouteDataWhenConstraintsMatchesExactlyReturnsMatch() - { - // Arrange - HttpContext context = GetHttpContext("~/category/12"); - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = @"\d\d" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.NotNull(rd); - Assert.Equal(3, rd.Values.Count); - Assert.Equal("store", rd.Values["controller"]); - Assert.Equal("showcat", rd.Values["action"]); - Assert.Equal("12", rd.Values["category"]); - } - - [Fact] - public void GetRouteDataShouldApplyRegExModifiersCorrectly1() - { - // DevDiv Bugs 173408: UrlRouting: Route validation doesn't handle ^ and $ correctly - - // Arrange - HttpContext context = GetHttpContext("~/category/FooBar"); - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = @"Foo|Bar" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - } - - [Fact] - public void GetRouteDataShouldApplyRegExModifiersCorrectly2() - { - // DevDiv Bugs 173408: UrlRouting: Route validation doesn't handle ^ and $ correctly - - // Arrange - HttpContext context = GetHttpContext("~/category/Food"); - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = @"Foo|Bar" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - } - - [Fact] - public void GetRouteDataShouldApplyRegExModifiersCorrectly3() - { - // DevDiv Bugs 173408: UrlRouting: Route validation doesn't handle ^ and $ correctly - - // Arrange - HttpContext context = GetHttpContext("~/category/Bar"); - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = @"Foo|Bar" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.NotNull(rd); - Assert.Equal(3, rd.Values.Count); - Assert.Equal("store", rd.Values["controller"]); - Assert.Equal("showcat", rd.Values["action"]); - Assert.Equal("Bar", rd.Values["category"]); - } - - [Fact] - public void GetRouteDataWithCaseInsensitiveConstraintsMatches() - { - // Arrange - HttpContext context = GetHttpContext("~/category/aBc"); - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = @"[a-z]{3}" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.NotNull(rd); - Assert.Equal(3, rd.Values.Count); - Assert.Equal("store", rd.Values["controller"]); - Assert.Equal("showcat", rd.Values["action"]); - Assert.Equal("aBc", rd.Values["category"]); - } - [Fact] public void GetRouteDataWithMultiSegmentParamsOnBothEndsMatches() { @@ -569,135 +405,11 @@ namespace Microsoft.AspNet.Routing.Template.Tests public void GetRouteDataWithMultiSegmentParamsOnBothEndsWithDefaultValuesMatches() { GetRouteDataHelper( - CreateRoute("language/{lang}-{region}", new RouteValueDictionary(new { lang = "xx", region = "yy" }), null), - "language/-", + CreateRoute("language/{lang}-{region}", new RouteValueDictionary(new { lang = "xx", region = "yy" })), + "language/-", null); } -#if URLGENERATION - - [Fact] - public void GetVirtualPathWithMultiSegmentParamsOnBothEndsMatches() - { - GetVirtualPathHelper( - CreateRoute("language/{lang}-{region}", null), - new RouteValueDictionary(new { lang = "en", region = "US" }), - new RouteValueDictionary(new { lang = "xx", region = "yy" }), - "language/xx-yy"); - } - - [Fact] - public void GetVirtualPathWithMultiSegmentParamsOnLeftEndMatches() - { - GetVirtualPathHelper( - CreateRoute("language/{lang}-{region}a", null), - new RouteValueDictionary(new { lang = "en", region = "US" }), - new RouteValueDictionary(new { lang = "xx", region = "yy" }), - "language/xx-yya"); - } - - [Fact] - public void GetVirtualPathWithMultiSegmentParamsOnRightEndMatches() - { - GetVirtualPathHelper( - CreateRoute("language/a{lang}-{region}", null), - new RouteValueDictionary(new { lang = "en", region = "US" }), - new RouteValueDictionary(new { lang = "xx", region = "yy" }), - "language/axx-yy"); - } - - [Fact] - public void GetVirtualPathWithMultiSegmentParamsOnNeitherEndMatches() - { - GetVirtualPathHelper( - CreateRoute("language/a{lang}-{region}a", null), - new RouteValueDictionary(new { lang = "en", region = "US" }), - new RouteValueDictionary(new { lang = "xx", region = "yy" }), - "language/axx-yya"); - } - - [Fact] - public void GetVirtualPathWithMultiSegmentParamsOnNeitherEndDoesNotMatch() - { - GetVirtualPathHelper( - CreateRoute("language/a{lang}-{region}a", null), - new RouteValueDictionary(new { lang = "en", region = "US" }), - new RouteValueDictionary(new { lang = "", region = "yy" }), - null); - } - - [Fact] - public void GetVirtualPathWithMultiSegmentParamsOnNeitherEndDoesNotMatch2() - { - GetVirtualPathHelper( - CreateRoute("language/a{lang}-{region}a", null), - new RouteValueDictionary(new { lang = "en", region = "US" }), - new RouteValueDictionary(new { lang = "xx", region = "" }), - null); - } - - [Fact] - public void GetVirtualPathWithSimpleMultiSegmentParamsOnBothEndsMatches() - { - GetVirtualPathHelper( - CreateRoute("language/{lang}", null), - new RouteValueDictionary(new { lang = "en" }), - new RouteValueDictionary(new { lang = "xx" }), - "language/xx"); - } - - [Fact] - public void GetVirtualPathWithSimpleMultiSegmentParamsOnLeftEndMatches() - { - GetVirtualPathHelper( - CreateRoute("language/{lang}-", null), - new RouteValueDictionary(new { lang = "en" }), - new RouteValueDictionary(new { lang = "xx" }), - "language/xx-"); - } - - [Fact] - public void GetVirtualPathWithSimpleMultiSegmentParamsOnRightEndMatches() - { - GetVirtualPathHelper( - CreateRoute("language/a{lang}", null), - new RouteValueDictionary(new { lang = "en" }), - new RouteValueDictionary(new { lang = "xx" }), - "language/axx"); - } - - [Fact] - public void GetVirtualPathWithSimpleMultiSegmentParamsOnNeitherEndMatches() - { - GetVirtualPathHelper( - CreateRoute("language/a{lang}a", null), - new RouteValueDictionary(new { lang = "en" }), - new RouteValueDictionary(new { lang = "xx" }), - "language/axxa"); - } - - [Fact] - public void GetVirtualPathWithMultiSegmentStandardMvcRouteMatches() - { - GetVirtualPathHelper( - CreateRoute("{controller}.mvc/{action}/{id}", new RouteValueDictionary(new { action = "Index", id = (string)null })), - new RouteValueDictionary(new { controller = "home", action = "list", id = (string)null }), - new RouteValueDictionary(new { controller = "products" }), - "products.mvc"); - } - - [Fact] - public void GetVirtualPathWithMultiSegmentParamsOnBothEndsWithDefaultValuesMatches() - { - GetVirtualPathHelper( - CreateRoute("language/{lang}-{region}", new RouteValueDictionary(new { lang = "xx", region = "yy" }), null), - new RouteValueDictionary(new { lang = "en", region = "US" }), - new RouteValueDictionary(new { lang = "zz" }), - "language/zz-yy"); - } - -#endif - [Fact] public void GetRouteDataWithUrlWithMultiSegmentWithRepeatedDots() { @@ -810,698 +522,11 @@ namespace Microsoft.AspNet.Routing.Template.Tests action = "ShowPilot", missionId = (string)null, name = (string)null - }), - null), + })), "Home/ShowPilot/777/12345./foobar", new RouteValueDictionary(new { controller = "Home", action = "ShowPilot", missionId = "777", name = "12345./foobar" })); } - [Fact] - public void GetRouteDataWhenConstraintsMatchesPartiallyDoesNotMatch() - { - // Arrange - HttpContext context = GetHttpContext("~/category/a12"); - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = @"\d\d" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - } - - [Fact] - public void GetRouteDataWhenConstraintsDoesNotMatch() - { - // Arrange - HttpContext context = GetHttpContext("~/category/ab"); - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = @"\d\d" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - } - - [Fact] - public void GetRouteDataWhenOneOfMultipleConstraintsDoesNotMatch() - { - // Arrange - HttpContext context = GetHttpContext("~/category/01/q"); - TemplateRoute r = CreateRoute( - "category/{category}/{sort}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = @"\d\d", sort = @"a|d" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - } - - [Fact] - public void GetRouteDataWithNonStringValueReturnsTrueIfMatches() - { - // Arrange - HttpContext context = GetHttpContext("~/category"); - TemplateRoute r = CreateRoute( - "category/{foo}", - new RouteValueDictionary(new { controller = "store", action = "showcat", foo = 123 }), - new RouteValueDictionary(new { foo = @"\d{3}" })); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.NotNull(rd); - } - - [Fact] - public void GetRouteDataWithNonStringValueReturnsFalseIfUnmatched() - { - // Arrange - HttpContext context = GetHttpContext("~/category"); - TemplateRoute r = CreateRoute( - "category/{foo}", - new RouteValueDictionary(new { controller = "store", action = "showcat", foo = 123 }), - new RouteValueDictionary(new { foo = @"\d{2}" })); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - } - -#if URLGENERATION - [Fact] - public void GetUrlWithDefaultValue() - { - // URL should be found but excluding the 'id' parameter, which has only a default value. - GetVirtualPathHelper( - CreateRoute("{controller}/{action}/{id}", - new RouteValueDictionary(new { id = "defaultid" }), null), - new RouteValueDictionary(new { controller = "home", action = "oldaction" }), - new RouteValueDictionary(new { action = "newaction" }), - "home/newaction"); - } - - [Fact] - public void GetVirtualPathWithEmptyStringRequiredValueReturnsNull() - { - GetVirtualPathHelper( - CreateRoute("foo/{controller}", null), - new RouteValueDictionary(new { }), - new RouteValueDictionary(new { controller = "" }), - null); - } - - [Fact] - public void GetVirtualPathWithNullRequiredValueReturnsNull() - { - GetVirtualPathHelper( - CreateRoute("foo/{controller}", null), - new RouteValueDictionary(new { }), - new RouteValueDictionary(new { controller = (string)null }), - null); - } - - [Fact] - public void GetVirtualPathWithRequiredValueReturnsPath() - { - GetVirtualPathHelper( - CreateRoute("foo/{controller}", null), - new RouteValueDictionary(new { }), - new RouteValueDictionary(new { controller = "home" }), - "foo/home"); - } - - [Fact] - public void GetUrlWithNullDefaultValue() - { - // URL should be found but excluding the 'id' parameter, which has only a default value. - GetVirtualPathHelper( - CreateRoute( - "{controller}/{action}/{id}", - new RouteValueDictionary(new { id = (string)null }), - null), - new RouteValueDictionary(new { controller = "home", action = "oldaction", id = (string)null }), - new RouteValueDictionary(new { action = "newaction" }), - "home/newaction"); - } - - [Fact] - public void GetUrlWithMissingValuesDoesntMatch() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r = CreateRoute("{controller}/{action}/{id}", null); - - var rd = CreateRouteData(); - rd.Values.Add("controller", "home"); - rd.Values.Add("action", "oldaction"); - var valuesDictionary = CreateRouteValueDictionary(); - valuesDictionary.Add("action", "newaction"); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.Null(vpd); - } - - [Fact] - public void GetUrlWithValuesThatAreCompletelyDifferentFromTheCurrenIRoute() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - IRouteCollection rt = new DefaultRouteCollection(); - rt.Add(CreateRoute("date/{y}/{m}/{d}", null)); - rt.Add(CreateRoute("{controller}/{action}/{id}", null)); - - var rd = CreateRouteData(); - rd.Values.Add("controller", "home"); - rd.Values.Add("action", "dostuff"); - - var values = CreateRouteValueDictionary(); - values.Add("y", "2007"); - values.Add("m", "08"); - values.Add("d", "12"); - - // Act - var vpd = rt.GetVirtualPath(context, values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("/app/date/2007/08/12", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithValuesThatAreCompletelyDifferentFromTheCurrentRouteAsSecondRoute() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - - IRouteCollection rt = new DefaultRouteCollection(); - rt.Add(CreateRoute("{controller}/{action}/{id}")); - rt.Add(CreateRoute("date/{y}/{m}/{d}")); - - var rd = CreateRouteData(); - rd.Values.Add("controller", "home"); - rd.Values.Add("action", "dostuff"); - - var values = CreateRouteValueDictionary(); - values.Add("y", "2007"); - values.Add("m", "08"); - values.Add("d", "12"); - - // Act - var vpd = rt.GetVirtualPath(context, values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("/app/date/2007/08/12", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithEmptyRequiredValuesReturnsNull() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r = CreateRoute("{p1}/{p2}/{p3}", new RouteValueDictionary(), null); - - var rd = CreateRouteData(); - rd.Values.Add("p1", "v1"); - - var valuesDictionary = CreateRouteValueDictionary(); - valuesDictionary.Add("p2", ""); - valuesDictionary.Add("p3", ""); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.Null(vpd); - } - - [Fact] - public void GetUrlWithEmptyOptionalValuesReturnsShortUrl() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r = CreateRoute("{p1}/{p2}/{p3}", new RouteValueDictionary(new { p2 = "d2", p3 = "d3", }), null); - - var rd = CreateRouteData(); - rd.Values.Add("p1", "v1"); - var valuesDictionary = CreateRouteValueDictionary(); - valuesDictionary.Add("p2", ""); - valuesDictionary.Add("p3", ""); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("v1", vpd.VirtualPath); - } - - [Fact] - public void GetUrlShouldIgnoreValuesAfterChangedParameter() - { - // DevDiv Bugs 157535 - - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "orig"); - rd.Values.Add("action", "init"); - rd.Values.Add("id", "123"); - - TemplateRoute r = CreateRoute("{controller}/{action}/{id}", new RouteValueDictionary(new { action = "Index", id = (string)null }), null); - - var valuesDictionary = CreateRouteValueDictionary(); - valuesDictionary.Add("action", "new"); - - // Act - var vpd = r.GetVirtualPath(GetHttpContext("/app1", "", ""), valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("orig/new", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithRouteThatHasExtensionWithSubsequentDefaultValueIncludesExtensionButNotDefaultValue() - { - // DevDiv Bugs 156606 - - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "Bank"); - rd.Values.Add("action", "MakeDeposit"); - rd.Values.Add("accountId", "7770"); - - IRouteCollection rc = new DefaultRouteCollection(); - rc.Add(CreateRoute( - "{controller}.mvc/Deposit/{accountId}", - new RouteValueDictionary(new { Action = "DepositView" }))); - - // Note: This route was in the original bug, but it turns out that this behavior is incorrect. With the - // recent fix to Route (in this changelist) this route would have been selected since we have values for - // all three required parameters. - //rc.Add(new Route { - // Url = "{controller}.mvc/{action}/{accountId}", - // RouteHandler = new DummyRouteHandler() - //}); - - // This route should be chosen because the requested action is List. Since the default value of the action - // is List then the Action should not be in the URL. However, the file extension should be included since - // it is considered "safe." - rc.Add(CreateRoute( - "{controller}.mvc/{action}", - new RouteValueDictionary(new { Action = "List" }))); - - var values = CreateRouteValueDictionary(); - values.Add("Action", "List"); - - // Act - var vpd = rc.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("/app1/Bank.mvc", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithRouteThatHasDifferentControllerCaseShouldStillMatch() - { - // DevDiv Bugs 159099 - - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "Bar"); - rd.Values.Add("action", "bbb"); - rd.Values.Add("id", null); - - IRouteCollection rc = new DefaultRouteCollection(); - rc.Add(CreateRoute("PrettyFooUrl", new RouteValueDictionary(new { controller = "Foo", action = "aaa", id = (string)null }))); - - rc.Add(CreateRoute("PrettyBarUrl", new RouteValueDictionary(new { controller = "Bar", action = "bbb", id = (string)null }))); - - rc.Add(CreateRoute("{controller}/{action}/{id}", new RouteValueDictionary(new { action = "Index", id = (string)null }))); - - var values = CreateRouteValueDictionary(); - values.Add("Action", "aaa"); - values.Add("Controller", "foo"); - - // Act - var vpd = rc.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("/app1/PrettyFooUrl", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithNoChangedValuesShouldProduceSameUrl() - { - // DevDiv Bugs 159469 - - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "Home"); - rd.Values.Add("action", "Index"); - rd.Values.Add("id", null); - - IRouteCollection rc = new DefaultRouteCollection(); - rc.Add(CreateRoute("{controller}.mvc/{action}/{id}", new RouteValueDictionary(new { action = "Index", id = (string)null }))); - - rc.Add(CreateRoute("{controller}/{action}/{id}", new RouteValueDictionary(new { action = "Index", id = (string)null }))); - - var values = CreateRouteValueDictionary(); - values.Add("Action", "Index"); - - // Act - var vpd = rc.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("/app1/Home.mvc", vpd.VirtualPath); - } - - [Fact] - public void GetUrlAppliesConstraintsRulesToChooseRoute() - { - // DevDiv Bugs 159678: MVC: URL generation chooses the wrong route for generating URLs when route validation is in place - - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "Home"); - rd.Values.Add("action", "Index"); - rd.Values.Add("id", null); - - IRouteCollection rc = new DefaultRouteCollection(); - rc.Add(CreateRoute( - "foo.mvc/{action}", - new RouteValueDictionary(new { controller = "Home" }), - new RouteValueDictionary(new { controller = "Home", action = "Contact", httpMethod = CreateHttpMethodConstraint("get") }))); - - rc.Add(CreateRoute( - "{controller}.mvc/{action}", - new RouteValueDictionary(new { action = "Index" }), - new RouteValueDictionary(new { controller = "Home", action = "(Index|About)", httpMethod = CreateHttpMethodConstraint("post") }))); - - var values = CreateRouteValueDictionary(); - values.Add("Action", "Index"); - - // Act - var vpd = rc.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("/app1/Home.mvc", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithNullForMiddleParameterIgnoresRemainingParameters() - { - // DevDiv Bugs 170859: UrlRouting: Passing null or empty string for a parameter in the middle of a route generates the wrong Url - - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "UrlRouting"); - rd.Values.Add("action", "Play"); - rd.Values.Add("category", "Photos"); - rd.Values.Add("year", "2008"); - rd.Values.Add("occasion", "Easter"); - rd.Values.Add("SafeParam", "SafeParamValue"); - - TemplateRoute r = CreateRoute( - "UrlGeneration1/{controller}.mvc/{action}/{category}/{year}/{occasion}/{SafeParam}", - new RouteValueDictionary(new { year = 1995, occasion = "Christmas", action = "Play", SafeParam = "SafeParamValue" })); - - // Act - RouteValueDictionary values = CreateRouteValueDictionary(); - values.Add("year", null); - values.Add("occasion", "Hola"); - var vpd = r.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("UrlGeneration1/UrlRouting.mvc/Play/Photos/1995/Hola", vpd.VirtualPath); - } - - [Fact] - public void GetUrlShouldValidateOnlyAcceptedParametersAndUserDefaultValuesForInvalidatedParameters() - { - // DevDiv Bugs 172913: UrlRouting: Parameter validation should not run against current request values if a new value has been supplied at a previous position - - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("Controller", "UrlRouting"); - rd.Values.Add("Name", "MissmatchedValidateParams"); - rd.Values.Add("action", "MissmatchedValidateParameters2"); - rd.Values.Add("ValidateParam1", "special1"); - rd.Values.Add("ValidateParam2", "special2"); - - IRouteCollection rc = new DefaultRouteCollection(); - rc.Add(CreateRoute( - "UrlConstraints/Validation.mvc/Input5/{action}/{ValidateParam1}/{ValidateParam2}", - new RouteValueDictionary(new { Controller = "UrlRouting", Name = "MissmatchedValidateParams", ValidateParam2 = "valid" }), - new RouteValueDictionary(new { ValidateParam1 = "valid.*", ValidateParam2 = "valid.*" }))); - - rc.Add(CreateRoute( - "UrlConstraints/Validation.mvc/Input5/{action}/{ValidateParam1}/{ValidateParam2}", - new RouteValueDictionary(new { Controller = "UrlRouting", Name = "MissmatchedValidateParams" }), - new RouteValueDictionary(new { ValidateParam1 = "special.*", ValidateParam2 = "special.*" }))); - - var values = CreateRouteValueDictionary(); - values.Add("Name", "MissmatchedValidateParams"); - values.Add("ValidateParam1", "valid1"); - - // Act - var vpd = rc.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("/app1/UrlConstraints/Validation.mvc/Input5/MissmatchedValidateParameters2/valid1", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithEmptyStringForMiddleParameterIgnoresRemainingParameters() - { - // DevDiv Bugs 170859: UrlRouting: Passing null or empty string for a parameter in the middle of a route generates the wrong Url - - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "UrlRouting"); - rd.Values.Add("action", "Play"); - rd.Values.Add("category", "Photos"); - rd.Values.Add("year", "2008"); - rd.Values.Add("occasion", "Easter"); - rd.Values.Add("SafeParam", "SafeParamValue"); - - TemplateRoute r = CreateRoute( - "UrlGeneration1/{controller}.mvc/{action}/{category}/{year}/{occasion}/{SafeParam}", - new RouteValueDictionary(new { year = 1995, occasion = "Christmas", action = "Play", SafeParam = "SafeParamValue" })); - - // Act - RouteValueDictionary values = CreateRouteValueDictionary(); - values.Add("year", String.Empty); - values.Add("occasion", "Hola"); - var vpd = r.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("UrlGeneration1/UrlRouting.mvc/Play/Photos/1995/Hola", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithEmptyStringForMiddleParameterShouldUseDefaultValue() - { - // DevDiv Bugs 172084: UrlRouting: Route.GetUrl generates the wrong route of new values has a different controller and route has an action parameter with default - - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("Controller", "Test"); - rd.Values.Add("Action", "Fallback"); - rd.Values.Add("param1", "fallback1"); - rd.Values.Add("param2", "fallback2"); - rd.Values.Add("param3", "fallback3"); - - TemplateRoute r = CreateRoute( - "{controller}.mvc/{action}/{param1}", - new RouteValueDictionary(new { Controller = "Test", Action = "Default" })); - - // Act - RouteValueDictionary values = CreateRouteValueDictionary(); - values.Add("controller", "subtest"); - values.Add("param1", "b"); - // The original bug for this included this value, but with the new support for - // creating query string values it changes the behavior such that the URL is - // not what was originally expected. To preserve the general behavior of this - // unit test the 'param2' value is no longer being added. - //values.Add("param2", "a"); - var vpd = r.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("subtest.mvc/Default/b", vpd.VirtualPath); - } - - [Fact] - public void GetUrlVerifyEncoding() - { - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "Home"); - rd.Values.Add("action", "Index"); - rd.Values.Add("id", null); - - TemplateRoute r = CreateRoute( - "{controller}.mvc/{action}/{id}", - new RouteValueDictionary(new { controller = "Home" })); - - // Act - RouteValueDictionary values = CreateRouteValueDictionary(); - values.Add("controller", "#;?:@&=+$,"); - values.Add("action", "showcategory"); - values.Add("id", 123); - values.Add("so?rt", "de?sc"); - values.Add("maxPrice", 100); - var vpd = r.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("%23%3b%3f%3a%40%26%3d%2b%24%2c.mvc/showcategory/123?so%3Frt=de%3Fsc&maxPrice=100", vpd.VirtualPath); - } - - [Fact] - public void GetUrlGeneratesQueryStringForNewValuesAndEscapesQueryString() - { - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "Home"); - rd.Values.Add("action", "Index"); - rd.Values.Add("id", null); - - TemplateRoute r = CreateRoute( - "{controller}.mvc/{action}/{id}", - new RouteValueDictionary(new { controller = "Home" })); - - // Act - RouteValueDictionary values = CreateRouteValueDictionary(); - values.Add("controller", "products"); - values.Add("action", "showcategory"); - values.Add("id", 123); - values.Add("so?rt", "de?sc"); - values.Add("maxPrice", 100); - var vpd = r.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("products.mvc/showcategory/123?so%3Frt=de%3Fsc&maxPrice=100", vpd.VirtualPath); - } - - [Fact] - public void GetUrlGeneratesQueryStringForNewValuesButIgnoresNewValuesThatMatchDefaults() - { - // Arrange - var rd = CreateRouteData(); - rd.Values.Add("controller", "Home"); - rd.Values.Add("action", "Index"); - rd.Values.Add("id", null); - - TemplateRoute r = CreateRoute("{controller}.mvc/{action}/{id}", new RouteValueDictionary(new { controller = "Home", Custom = "customValue" })); - - // Act - RouteValueDictionary values = CreateRouteValueDictionary(); - values.Add("controller", "products"); - values.Add("action", "showcategory"); - values.Add("id", 123); - values.Add("sort", "desc"); - values.Add("maxPrice", 100); - values.Add("custom", "customValue"); - var vpd = r.GetVirtualPath(GetHttpContext("/app1", "", ""), values); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("products.mvc/showcategory/123?sort=desc&maxPrice=100", vpd.VirtualPath); - } - - [Fact] - public void GetVirtualPathEncodesParametersAndLiterals() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r = CreateRoute("bl%og/{controller}/he llo/{action}", null); - var rd = CreateRouteData(); - rd.Values.Add("controller", "ho%me"); - rd.Values.Add("action", "li st"); - var valuesDictionary = CreateRouteValueDictionary(); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("bl%25og/ho%25me/he%20llo/li%20st", vpd.VirtualPath); - Assert.Equal(r, vpd.Route); - } - - [Fact] - public void GetVirtualPathUsesCurrentValuesNotInRouteToMatch() - { - // DevDiv Bugs 177401: UrlRouting: Incorrect route picked on urlgeneration if using controller from ambient values and route does not have a url parameter for controller - - // DevDiv Bugs 191162: UrlRouting: Route does not match when an ambient route value doesn't match a required default value in the target route - // Because of this bug the test was split into two separate verifications since the original test was verifying slightly incorrect behavior - - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r1 = CreateRoute( - "ParameterMatching.mvc/{Action}/{product}", - new RouteValueDictionary(new { Controller = "ParameterMatching", product = (string)null }), - null); - - TemplateRoute r2 = CreateRoute( - "{controller}.mvc/{action}", - new RouteValueDictionary(new { Action = "List" }), - new RouteValueDictionary(new { Controller = "Action|Bank|Overridden|DerivedFromAction|OverrideInvokeActionAndExecute|InvalidControllerName|Store|HtmlHelpers|(T|t)est|UrlHelpers|Custom|Parent|Child|TempData|ViewFactory|LocatingViews|AccessingDataInViews|ViewOverrides|ViewMasterPage|InlineCompileError|CustomView" }), - null); - - var rd = CreateRouteData(); - rd.Values.Add("controller", "Bank"); - rd.Values.Add("Action", "List"); - var valuesDictionary = CreateRouteValueDictionary(); - valuesDictionary.Add("action", "AttemptLogin"); - - // Act for first route - var vpd = r1.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("ParameterMatching.mvc/AttemptLogin", vpd.VirtualPath); - - // Act for second route - vpd = r2.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("Bank.mvc/AttemptLogin", vpd.VirtualPath); - } - -#endif [Fact] public void RouteWithCatchAllClauseCapturesManySlashes() { @@ -1510,7 +535,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("{p1}/{*p2}", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -1527,7 +552,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("{p1}/{*p2}", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -1544,7 +569,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests TemplateRoute r = CreateRoute("{p1}/{*p2}", null); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -1558,10 +583,10 @@ namespace Microsoft.AspNet.Routing.Template.Tests { // Arrange HttpContext context = GetHttpContext("~/v1"); - TemplateRoute r = CreateRoute("{p1}/{*p2}", new RouteValueDictionary(new { p2 = "catchall" }), null); + TemplateRoute r = CreateRoute("{p1}/{*p2}", new RouteValueDictionary(new { p2 = "catchall" })); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -1575,10 +600,10 @@ namespace Microsoft.AspNet.Routing.Template.Tests { // Arrange HttpContext context = GetHttpContext("~/v1/hello/whatever"); - TemplateRoute r = CreateRoute("{p1}/{*p2}", new RouteValueDictionary(new { p2 = "catchall" }), null); + TemplateRoute r = CreateRoute("{p1}/{*p2}", new RouteValueDictionary(new { p2 = "catchall" })); // Act - var rd = r.GetRouteData(context); + var rd = r.Match(new RouteContext(context)); // Assert Assert.NotNull(rd); @@ -1587,414 +612,6 @@ namespace Microsoft.AspNet.Routing.Template.Tests Assert.Equal("hello/whatever", rd.Values["p2"]); } - [Fact] - public void RouteWithCatchAllRejectsConstraints() - { - // Arrange - HttpContext context = GetHttpContext("~/v1/abcd"); - TemplateRoute r = CreateRoute( - "{p1}/{*p2}", - new RouteValueDictionary(new { p2 = "catchall" }), - new RouteValueDictionary(new { p2 = "\\d{4}" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - } - - [Fact] - public void RouteWithCatchAllAcceptsConstraints() - { - // Arrange - HttpContext context = GetHttpContext("~/v1/1234"); - TemplateRoute r = CreateRoute( - "{p1}/{*p2}", - new RouteValueDictionary(new { p2 = "catchall" }), - new RouteValueDictionary(new { p2 = "\\d{4}" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.NotNull(rd); - Assert.Equal(2, rd.Values.Count); - Assert.Equal("v1", rd.Values["p1"]); - Assert.Equal("1234", rd.Values["p2"]); - } - -#if URLGENERATION - - [Fact] - public void GetUrlWithCatchAllWithValue() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r = CreateRoute("{p1}/{*p2}", new RouteValueDictionary(new { id = "defaultid" }), null); - - var rd = CreateRouteData(); - rd.Values.Add("p1", "v1"); - var valuesDictionary = CreateRouteValueDictionary(); - valuesDictionary.Add("p2", "v2a/v2b"); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("v1/v2a/v2b", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithCatchAllWithEmptyValue() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r = CreateRoute("{p1}/{*p2}", new RouteValueDictionary(new { id = "defaultid" }), null); - - var rd = CreateRouteData(); - rd.Values.Add("p1", "v1"); - - var valuesDictionary = CreateRouteValueDictionary(); - valuesDictionary.Add("p2", ""); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("v1", vpd.VirtualPath); - } - - [Fact] - public void GetUrlWithCatchAllWithNullValue() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r = CreateRoute("{p1}/{*p2}", new RouteValueDictionary(new { id = "defaultid" }), null); - - var rd = CreateRouteData(); - rd.Values.Add("p1", "v1"); - var valuesDictionary = CreateRouteValueDictionary(); - valuesDictionary.Add("p2", null); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("v1", vpd.VirtualPath); - } - - [Fact] - public void GetVirtualPathWithDataTokensCopiesThemFromRouteToVirtualPathData() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r = CreateRoute("{controller}/{action}", null, null, new RouteValueDictionary(new { foo = "bar", qux = "quux" })); - - var rd = CreateRouteData(); - rd.Values.Add("controller", "home"); - rd.Values.Add("action", "index"); - var valuesDictionary = CreateRouteValueDictionary(); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("home/index", vpd.VirtualPath); - Assert.Equal(r, vpd.Route); - Assert.Equal(2, vpd.DataTokens.Count); - Assert.Equal("bar", vpd.DataTokens["foo"]); - Assert.Equal("quux", vpd.DataTokens["qux"]); - } - - [Fact] - public void GetVirtualPathWithValidCustomConstraints() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - CustomConstraintTemplateRoute r = new CustomConstraintTemplateRoute("{controller}/{action}", null, new RouteValueDictionary(new { action = 5 })); - - var rd = CreateRouteData(); - rd.Values.Add("controller", "home"); - rd.Values.Add("action", "index"); - - var valuesDictionary = CreateRouteValueDictionary(); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("home/index", vpd.VirtualPath); - Assert.Equal(r, vpd.Route); - Assert.NotNull(r.ConstraintData); - Assert.Equal(5, r.ConstraintData.Constraint); - Assert.Equal("action", r.ConstraintData.ParameterName); - Assert.Equal("index", r.ConstraintData.ParameterValue); - } - - [Fact] - public void GetVirtualPathWithInvalidCustomConstraints() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - CustomConstraintTemplateRoute r = new CustomConstraintTemplateRoute("{controller}/{action}", null, new RouteValueDictionary(new { action = 5 })); - - var rd = CreateRouteData(); - rd.Values.Add("controller", "home"); - rd.Values.Add("action", "list"); - - var valuesDictionary = CreateRouteValueDictionary(); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.Null(vpd); - Assert.NotNull(r.ConstraintData); - Assert.Equal(5, r.ConstraintData.Constraint); - Assert.Equal("action", r.ConstraintData.ParameterName); - Assert.Equal("list", r.ConstraintData.ParameterValue); - } - -#if DATATOKENS - - [Fact] - public void GetUrlWithCatchAllWithAmbientValue() - { - // Arrange - HttpContext context = GetHttpContext("/app", null, null); - TemplateRoute r = CreateRoute("{p1}/{*p2}", new RouteValueDictionary(new { id = "defaultid" }), null, null); - - var rd = CreateRouteData(); - rd.Values.Add("p1", "v1"); - rd.Values.Add("p2", "ambient-catch-all"); - var valuesDictionary = CreateRouteValueDictionary(); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.NotNull(vpd); - Assert.Equal("v1/ambient-catch-all", vpd.VirtualPath); - Assert.Equal(r, vpd.Route); - Assert.Equal(0, vpd.DataTokens.Count); - } -#endif -#endif - -#if DATATOKENS - - [Fact] - public void GetRouteDataWithDataTokensCopiesThemFromRouteToIRouteData() - { - // Arrange - HttpContext context = GetHttpContext(null, "~/category/33", null); - TemplateRoute r = CreateRoute("category/{category}", null, null, new RouteValueDictionary(new { foo = "bar", qux = "quux" })); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.NotNull(rd); - Assert.Equal(1, rd.Values.Count); - Assert.Equal(2, rd.DataTokens.Count); - Assert.Equal("33", rd.Values["category"]); - Assert.Equal("bar", rd.DataTokens["foo"]); - Assert.Equal("quux", rd.DataTokens["qux"]); - } - -#endif - - [Fact] - public void GetRouteDataWithValidCustomConstraints() - { - // Arrange - HttpContext context = GetHttpContext("~/home/index"); - CustomConstraintTemplateRoute r = new CustomConstraintTemplateRoute("{controller}/{action}", null, new RouteValueDictionary(new { action = 5 })); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.NotNull(rd); - Assert.Equal(2, rd.Values.Count); - Assert.Equal("home", rd.Values["controller"]); - Assert.Equal("index", rd.Values["action"]); - Assert.NotNull(r.ConstraintData); - Assert.Equal(5, r.ConstraintData.Constraint); - Assert.Equal("action", r.ConstraintData.ParameterName); - Assert.Equal("index", r.ConstraintData.ParameterValue); - } - - [Fact] - public void GetRouteDataWithInvalidCustomConstraints() - { - // Arrange - HttpContext context = GetHttpContext("~/home/list"); - CustomConstraintTemplateRoute r = new CustomConstraintTemplateRoute("{controller}/{action}", null, new RouteValueDictionary(new { action = 5 })); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - Assert.NotNull(r.ConstraintData); - Assert.Equal(5, r.ConstraintData.Constraint); - Assert.Equal("action", r.ConstraintData.ParameterName); - Assert.Equal("list", r.ConstraintData.ParameterValue); - } - - [Fact] - public void GetRouteDataWithConstraintIsCultureInsensitive() - { - // Arrange - HttpContext context = GetHttpContext("~/category/\u0130"); // Turkish upper-case dotted I - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { category = @"[a-z]+" }), - null); - - // Act - Thread currentThread = Thread.CurrentThread; - CultureInfo backupCulture = currentThread.CurrentCulture; - RouteMatch rd; - try - { - currentThread.CurrentCulture = new CultureInfo("tr-TR"); // Turkish culture - rd = r.GetRouteData(context); - } - finally - { - currentThread.CurrentCulture = backupCulture; - } - - // Assert - Assert.Null(rd); - } - - [Fact] - public void GetRouteDataWithConstraintThatHasNoValueDoesNotMatch() - { - // Arrange - HttpContext context = GetHttpContext(null, "~/category/33"); - TemplateRoute r = CreateRoute( - "category/{category}", - new RouteValueDictionary(new { controller = "store", action = "showcat" }), - new RouteValueDictionary(new { foo = @"\d\d\d" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - } - - [Fact] - public void GetRouteDataWithCatchAllConstraintThatHasNoValueDoesNotMatch() - { - // Arrange - HttpContext context = GetHttpContext(null, "~/category"); - TemplateRoute r = CreateRoute( - "category/{*therest}", - null, - new RouteValueDictionary(new { therest = @"hola" }), - null); - - // Act - var rd = r.GetRouteData(context); - - // Assert - Assert.Null(rd); - } - - [Fact] - public void ProcessConstraintShouldGetCalledForCustomConstraintDuringUrlGeneration() - { - // DevDiv Bugs 178588: UrlRouting: ProcessConstraint is not invoked on a custom constraint that is not mapped to a url parameter during urlgeneration - - // Arrange - HttpContext context = GetHttpContext("/app", null); - - DevDivBugs178588CustomRoute r = new DevDivBugs178588CustomRoute( - "CustomPath.mvc/{action}/{param1}/{param2}", - new RouteValueDictionary(new { Controller = "Test" }), - new RouteValueDictionary(new { foo = new DevDivBugs178588CustomConstraint() })); - - var rd = CreateRouteData(); - rd.Values.Add("action", "Test"); - rd.Values.Add("param1", "111"); - rd.Values.Add("param2", "222"); - rd.Values.Add("Controller", "Test"); - - var valuesDictionary = CreateRouteValueDictionary(); - - // Act - var vpd = r.GetVirtualPath(context, valuesDictionary); - - // Assert - Assert.Null(vpd); - } - - [Fact] - public void GetRouteDataMatchesEntireLiteralSegmentScenario1a() - { - TemplateRoute r = CreateRoute( - "CatchAllParamsWithDefaults/{Controller}.mvc/{Action}/{*therest}", - new RouteValueDictionary(new { therest = "Hello" }), - new RouteValueDictionary(new { Controller = "CatchAllParams" }), - null); - - // DevDiv Bugs 191180: UrlRouting: Wrong route getting matched if a url segment is a substring of the requested url - // Scenario 1.a. - GetRouteDataHelper( - r, - "CatchAllParamsWithDefaults/CatchAllParams.mvc/TestCatchAllParamInIRouteData", - new RouteValueDictionary(new { Controller = "CatchAllParams", Action = "TestCatchAllParamInIRouteData", therest = "Hello" })); - } - - [Fact] - public void GetRouteDataMatchesEntireLiteralSegmentScenario1b() - { - TemplateRoute r = CreateRoute( - "CatchAllParams/{Controller}.mvc/{Action}/{*therest}", - null, - new RouteValueDictionary(new { Controller = "CatchAllParams" }), - null); - - // DevDiv Bugs 191180: UrlRouting: Wrong route getting matched if a url segment is a substring of the requested url - // Scenario 1.b. - GetRouteDataHelper( - r, - "CatchAllParamsWithDefaults/CatchAllParams.mvc/TestCatchAllParamInIRouteData", - null); - } - - [Fact] - public void GetRouteDataMatchesEntireLiteralSegmentScenario2() - { - TemplateRoute r = CreateRoute( - "{controller}.mvc/Login", - new RouteValueDictionary(new { Action = "LoginView" }), - new RouteValueDictionary(new { Controller = "Bank" }), - null); - - // DevDiv Bugs 191180: UrlRouting: Wrong route getting matched if a url segment is a substring of the requested url - // Scenario 2 - GetRouteDataHelper( - r, - "Bank.mvc/AttemptLogin", - null); - } - [Fact] public void GetRouteDataDoesNotMatchOnlyLeftLiteralMatch() { @@ -2048,8 +665,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests { TemplateRoute r = CreateRoute( "foo/{ }/{.!$%}/{dynamic.data}/{op.tional}", - new RouteValueDictionary() { { " ", "not a space" }, { "op.tional", "default value" }, { "ran!dom", "va@lue" } }, - null); + new RouteValueDictionary() { { " ", "not a space" }, { "op.tional", "default value" }, { "ran!dom", "va@lue" } }); GetRouteDataHelper( r, @@ -2057,89 +673,11 @@ namespace Microsoft.AspNet.Routing.Template.Tests new RouteValueDictionary() { { " ", "space" }, { ".!$%", "weird" }, { "dynamic.data", "orderid" }, { "op.tional", "default value" }, { "ran!dom", "va@lue" } }); } -#if URLGENERATION - - [Fact] - public void UrlWithEscapedOpenCloseBraces() - { - RouteFormatHelper("foo/{{p1}}", "foo/{p1}"); - } - - private static void RouteFormatHelper(string routeUrl, string requestUrl) - { - RouteValueDictionary defaults = new RouteValueDictionary(new { route = "matched" }); - TemplateRoute r = CreateRoute(routeUrl, defaults, null); - - GetRouteDataHelper(r, requestUrl, defaults); - GetVirtualPathHelper(r, new RouteValueDictionary(), null, Uri.EscapeUriString(requestUrl)); - } - - [Fact] - public void UrlWithEscapedOpenBraceAtTheEnd() - { - RouteFormatHelper("bar{{", "bar{"); - } - - [Fact] - public void UrlWithEscapedOpenBraceAtTheBeginning() - { - RouteFormatHelper("{{bar", "{bar"); - } - - [Fact] - public void UrlWithRepeatedEscapedOpenBrace() - { - RouteFormatHelper("foo{{{{bar", "foo{{bar"); - } - - [Fact] - public void UrlWithEscapedCloseBraceAtTheEnd() - { - RouteFormatHelper("bar}}", "bar}"); - } - - [Fact] - public void UrlWithEscapedCloseBraceAtTheBeginning() - { - RouteFormatHelper("}}bar", "}bar"); - } - - [Fact] - public void UrlWithRepeatedEscapedCloseBrace() - { - RouteFormatHelper("foo}}}}bar", "foo}}bar"); - } - - [Fact] - public void GetVirtualPathWithUnusedNullValueShouldGenerateUrlAndIgnoreNullValue() - { - // DevDiv Bugs 194371: UrlRouting: Exception thrown when generating URL that has some null values - GetVirtualPathHelper( - CreateRoute( - "{controller}.mvc/{action}/{id}", - new RouteValueDictionary(new { action = "Index", id = "" }), - null), - new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }), - new RouteValueDictionary(new { controller = "Home", action = "TestAction", id = "1", format = (string)null }), - "Home.mvc/TestAction/1"); - } - - [Fact] - public void GetVirtualPathCanFillInSeparatedParametersWithDefaultValues() - { - GetVirtualPathHelper( - CreateRoute("{controller}/{language}-{locale}", new RouteValueDictionary(new { language = "en", locale = "US" }), null), - new RouteValueDictionary(), - new RouteValueDictionary(new { controller = "Orders" }), - "Orders/en-US"); - } -#endif - [Fact] public void GetRouteDataDoesNotMatchRouteWithLiteralSeparatorDefaultsButNoValue() { GetRouteDataHelper( - CreateRoute("{controller}/{language}-{locale}", new RouteValueDictionary(new { language = "en", locale = "US" }), null), + CreateRoute("{controller}/{language}-{locale}", new RouteValueDictionary(new { language = "en", locale = "US" })), "foo", null); } @@ -2148,7 +686,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests public void GetRouteDataDoesNotMatchesRouteWithLiteralSeparatorDefaultsAndLeftValue() { GetRouteDataHelper( - CreateRoute("{controller}/{language}-{locale}", new RouteValueDictionary(new { language = "en", locale = "US" }), null), + CreateRoute("{controller}/{language}-{locale}", new RouteValueDictionary(new { language = "en", locale = "US" })), "foo/xx-", null); } @@ -2157,7 +695,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests public void GetRouteDataDoesNotMatchesRouteWithLiteralSeparatorDefaultsAndRightValue() { GetRouteDataHelper( - CreateRoute("{controller}/{language}-{locale}", new RouteValueDictionary(new { language = "en", locale = "US" }), null), + CreateRoute("{controller}/{language}-{locale}", new RouteValueDictionary(new { language = "en", locale = "US" })), "foo/-yy", null); } @@ -2166,64 +704,11 @@ namespace Microsoft.AspNet.Routing.Template.Tests public void GetRouteDataMatchesRouteWithLiteralSeparatorDefaultsAndValue() { GetRouteDataHelper( - CreateRoute("{controller}/{language}-{locale}", new RouteValueDictionary(new { language = "en", locale = "US" }), null), + CreateRoute("{controller}/{language}-{locale}", new RouteValueDictionary(new { language = "en", locale = "US" })), "foo/xx-yy", new RouteValueDictionary { { "language", "xx" }, { "locale", "yy" }, { "controller", "foo" } }); } -#if URLGENERATION - - [Fact] - public void GetVirtualPathWithNonParameterConstraintReturnsUrlWithoutQueryString() - { - // DevDiv Bugs 199612: UrlRouting: UrlGeneration should not append parameter to query string if it is a Constraint parameter and not a Url parameter - GetVirtualPathHelper( - CreateRoute("{Controller}.mvc/{action}/{end}", null, new RouteValueDictionary(new { foo = CreateHttpMethodConstraint("GET") }), null), - new RouteValueDictionary(), - new RouteValueDictionary(new { controller = "Orders", action = "Index", end = "end", foo = "GET" }), - "Orders.mvc/Index/end"); - } - - [Fact] - public void DefaultRoutingValuesTestWithStringEmpty() - { - var data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}", new RouteValueDictionary(new { val1 = "42", val2 = "", val3 = "" }), new RouteValueDictionary()); - Assert.Equal("Test/42", data.VirtualPath); - - data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}/{val4}", new RouteValueDictionary(new { val1 = "21", val2 = "", val3 = "", val4 = "" }), new RouteValueDictionary(new { val1 = "42", val2 = "11", val3 = "", val4 = "" })); - Assert.Equal("Test/42/11", data.VirtualPath); - - } - - [Fact] - public void MixedDefaultAndExplicitRoutingValuesTestWithStringEmpty() - { - var data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}", new RouteValueDictionary(new { val1 = "21", val2 = "", val3 = "" }), new RouteValueDictionary(new { val1 = "42" })); - Assert.Equal("Test/42", data.VirtualPath); - - data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}/{val4}", new RouteValueDictionary(new { val1 = "21", val2 = "", val3 = "", val4 = "" }), new RouteValueDictionary(new { val1 = "42", val2 = "11" })); - Assert.Equal("Test/42/11", data.VirtualPath); - } - - [Fact] - public void DefaultRoutingValuesTestWithNull() - { - var data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}", new RouteValueDictionary(new { val1 = "42", val2 = (string)null, val3 = (string)null }), new RouteValueDictionary()); - Assert.Equal("Test/42", data.VirtualPath); - } - - [Fact] - public void MixedDefaultAndExplicitRoutingValuesTestWithNull() - { - var data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}", new RouteValueDictionary(new { val1 = "21", val2 = (string)null, val3 = (string)null }), new RouteValueDictionary(new { val1 = "42" })); - Assert.Equal("Test/42", data.VirtualPath); - - data = GetVirtualPathFromRoute("~/Test/", "Test/{val1}/{val2}/{val3}/{val4}", new RouteValueDictionary(new { val1 = "21", val2 = (string)null, val3 = (string)null, val4 = (string)null }), new RouteValueDictionary(new { val1 = "42", val2 = "11" })); - Assert.Equal("Test/42/11", data.VirtualPath); - } - -#endif - private static IRouteValues CreateRouteData() { return new RouteValues(new Dictionary(StringComparer.OrdinalIgnoreCase)); @@ -2241,58 +726,24 @@ namespace Microsoft.AspNet.Routing.Template.Tests HttpContext context = GetHttpContext(requestPath); // Act - var rd = route.GetRouteData(context); + var match = route.Match(new RouteContext(context)); // Assert if (expectedValues == null) { - Assert.Null(rd); + Assert.Null(match); } else { - Assert.NotNull(rd); - Assert.Equal(rd.Values.Count, expectedValues.Count); - foreach (string key in rd.Values.Keys) + Assert.NotNull(match); + Assert.Equal(match.Values.Count, expectedValues.Count); + foreach (string key in match.Values.Keys) { - Assert.Equal(expectedValues[key], rd.Values[key]); + Assert.Equal(expectedValues[key], match.Values[key]); } } } -#if URLGENERATION - private static void GetVirtualPathHelper(TemplateRoute route, RouteValueDictionary currentValues, RouteValueDictionary newValues, string expectedPath) - { - // Arrange - newValues = newValues ?? new RouteValueDictionary(); - - HttpContext context = GetHttpContext("/app", String.Empty, null); - var rd = CreateRouteData(); - foreach (var currentValue in currentValues) - { - rd.Values.Add(currentValue.Key, currentValue.Value); - } - - // Act - var vpd = route.GetVirtualPath(context, newValues); - - // Assert - if (expectedPath == null) - { - Assert.Null(vpd); - } - else - { - Assert.NotNull(vpd); - Assert.Equal(expectedPath, vpd.VirtualPath); - } - } - -#endif - private static ITemplateRouteConstraint CreateHttpMethodConstraint(params string[] methods) - { - return null; - } - internal static HttpContext GetHttpContext(string requestPath) { return GetHttpContext(null, requestPath); @@ -2319,112 +770,19 @@ namespace Microsoft.AspNet.Routing.Template.Tests private static TemplateRoute CreateRoute(string template) { - return CreateRoute(template, null, null, null); + return CreateRoute(template, null); } private static TemplateRoute CreateRoute(string template, RouteValueDictionary defaults) { - return CreateRoute(template, defaults, null, null); + return new TemplateRoute(new MockRouteEndpoint(), template, defaults); } - private static TemplateRoute CreateRoute(string template, RouteValueDictionary defaults, RouteValueDictionary constraints) + private class MockRouteEndpoint : IRouteEndpoint { - return CreateRoute(template, defaults, constraints, null); - } - - private static TemplateRoute CreateRoute(string template, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens) - { - return new TemplateRoute(template, defaults, constraints, dataTokens); - } - - private class DevDivBugs178588CustomConstraint - { - public string AllowedHeader + public Task Send(HttpContext context) { - get; - set; - } - } - - private class DevDivBugs178588CustomRoute : TemplateRoute - { - public DevDivBugs178588CustomRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints) - : base(url, defaults, constraints, null) - { - } - - protected override bool ProcessConstraint(HttpContext httpContext, object constraint, string parameterName, IDictionary values, RouteDirection routeDirection) - { - if (constraint is DevDivBugs178588CustomConstraint) - { - return false; - } - else - { - return base.ProcessConstraint(httpContext, constraint, parameterName, values, routeDirection); - } - } - } - - private sealed class ConstraintData - { - public object Constraint - { - get; - set; - } - public string ParameterName - { - get; - set; - } - public object ParameterValue - { - get; - set; - } - } - - private class CustomConstraintTemplateRoute : TemplateRoute - { - public CustomConstraintTemplateRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints) - : base(url, defaults, constraints, null) - { - } - - public ConstraintData ConstraintData - { - get; - set; - } - - protected override bool ProcessConstraint(HttpContext request, object constraint, string parameterName, IDictionary values, RouteDirection routeDirection) - { - object parameterValue; - values.TryGetValue(parameterName, out parameterValue); - - // Save the parameter values to validate them in the unit tests - ConstraintData = new ConstraintData - { - Constraint = constraint, - ParameterName = parameterName, - ParameterValue = parameterValue, - }; - - if (constraint is int) - { - int lengthRequirement = (int)constraint; - string paramString = parameterValue as string; - if (paramString == null) - { - throw new InvalidOperationException("This constraint only works with string values."); - } - return (paramString.Length == lengthRequirement); - } - else - { - return base.ProcessConstraint(request, constraint, parameterName, values, routeDirection); - } + throw new NotImplementedException(); } }