diff --git a/samples/RoutingSample.Web/DelegateRouteEndpoint.cs b/samples/RoutingSample.Web/DelegateRouteEndpoint.cs
index ee27c25a11..904404e1b4 100644
--- a/samples/RoutingSample.Web/DelegateRouteEndpoint.cs
+++ b/samples/RoutingSample.Web/DelegateRouteEndpoint.cs
@@ -25,8 +25,6 @@ namespace RoutingSample.Web
public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
- // We don't really care what the values look like.
- context.IsBound = true;
return null;
}
}
diff --git a/src/Microsoft.AspNet.Routing.Abstractions/VirtualPathContext.cs b/src/Microsoft.AspNet.Routing.Abstractions/VirtualPathContext.cs
index ac67152c52..deb7b1b97d 100644
--- a/src/Microsoft.AspNet.Routing.Abstractions/VirtualPathContext.cs
+++ b/src/Microsoft.AspNet.Routing.Abstractions/VirtualPathContext.cs
@@ -1,13 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System.Collections.Generic;
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing
{
+ ///
+ /// A context for virtual path generation operations.
+ ///
public class VirtualPathContext
{
+ ///
+ /// Creates a new .
+ ///
+ /// The associated with the current request.
+ /// The set of route values associated with the current request.
+ /// The set of new values provided for virtual path generation.
public VirtualPathContext(
HttpContext httpContext,
RouteValueDictionary ambientValues,
@@ -16,28 +24,43 @@ namespace Microsoft.AspNet.Routing
{
}
+ ///
+ /// Creates a new .
+ ///
+ /// The associated with the current request.
+ /// The set of route values associated with the current request.
+ /// The set of new values provided for virtual path generation.
+ /// The name of the route to use for virtual path generation.
public VirtualPathContext(
- HttpContext context,
+ HttpContext httpContext,
RouteValueDictionary ambientValues,
RouteValueDictionary values,
string routeName)
{
- Context = context;
+ HttpContext = httpContext;
AmbientValues = ambientValues;
Values = values;
RouteName = routeName;
}
- public string RouteName { get; }
-
- public IDictionary ProvidedValues { get; set; }
-
+ ///
+ /// Gets the set of route values associated with the current request.
+ ///
public RouteValueDictionary AmbientValues { get; }
- public HttpContext Context { get; }
+ ///
+ /// Gets the associated with the current request.
+ ///
+ public HttpContext HttpContext { get; }
- public bool IsBound { get; set; }
+ ///
+ /// Gets the name of the route to use for virtual path generation.
+ ///
+ public string RouteName { get; }
+ ///
+ /// Gets the set of new values provided for virtual path generation.
+ ///
public RouteValueDictionary Values { get; }
}
}
diff --git a/src/Microsoft.AspNet.Routing/RouteCollection.cs b/src/Microsoft.AspNet.Routing/RouteCollection.cs
index 1398e8cace..d5851a99db 100644
--- a/src/Microsoft.AspNet.Routing/RouteCollection.cs
+++ b/src/Microsoft.AspNet.Routing/RouteCollection.cs
@@ -86,123 +86,58 @@ namespace Microsoft.AspNet.Routing
public virtual VirtualPathData GetVirtualPath(VirtualPathContext context)
{
- EnsureOptions(context.Context);
-
- // If we're using Best-Effort link generation then it means that we'll first look for a route where
- // the route values are validated (context.IsBound == true). If we can't find a match like that, then
- // we'll return the path from the first route to return one.
- var useBestEffort = _options.UseBestEffortLinkGeneration;
+ EnsureOptions(context.HttpContext);
if (!string.IsNullOrEmpty(context.RouteName))
{
- var isValidated = false;
- VirtualPathData bestPathData = null;
+ VirtualPathData namedRoutePathData = null;
INamedRouter matchedNamedRoute;
if (_namedRoutes.TryGetValue(context.RouteName, out matchedNamedRoute))
{
- bestPathData = matchedNamedRoute.GetVirtualPath(context);
- isValidated = context.IsBound;
+ namedRoutePathData = matchedNamedRoute.GetVirtualPath(context);
}
- // If we get here and context.IsBound == true, then we know we have a match, we want to keep
- // iterating to see if we have multiple matches.
- foreach (var unnamedRoute in _unnamedRoutes)
+ var pathData = GetVirtualPath(context, _unnamedRoutes);
+
+ // If the named route and one of the unnamed routes also matches, then we have an ambiguity.
+ if (namedRoutePathData != null && pathData != null)
{
- // reset because we're sharing the context
- context.IsBound = false;
-
- var pathData = unnamedRoute.GetVirtualPath(context);
- if (pathData == null)
- {
- continue;
- }
-
- if (bestPathData != null)
- {
- // There was already a previous route which matched the name.
- throw new InvalidOperationException(
- Resources.FormatNamedRoutes_AmbiguousRoutesFound(context.RouteName));
- }
- else if (context.IsBound)
- {
- // This is the first 'validated' match that we've found.
- bestPathData = pathData;
- isValidated = true;
- }
- else
- {
- Debug.Assert(bestPathData == null);
-
- // This is the first 'unvalidated' match that we've found.
- bestPathData = pathData;
- isValidated = false;
- }
+ var message = Resources.FormatNamedRoutes_AmbiguousRoutesFound(context.RouteName);
+ throw new InvalidOperationException(message);
}
- if (isValidated || useBestEffort)
- {
- context.IsBound = isValidated;
-
- if (bestPathData != null)
- {
- bestPathData = new VirtualPathData(
- bestPathData.Router,
- NormalizeVirtualPath(bestPathData.VirtualPath),
- bestPathData.DataTokens);
- }
-
- return bestPathData;
- }
- else
- {
- return null;
- }
+ return NormalizeVirtualPath(namedRoutePathData ?? pathData);
}
else
{
- VirtualPathData bestPathData = null;
- for (var i = 0; i < Count; i++)
- {
- var route = this[i];
-
- var pathData = route.GetVirtualPath(context);
- if (pathData == null)
- {
- continue;
- }
-
- if (context.IsBound)
- {
- // This route has validated route values, short circuit.
- return new VirtualPathData(
- pathData.Router,
- NormalizeVirtualPath(pathData.VirtualPath),
- pathData.DataTokens);
- }
- else if (bestPathData == null)
- {
- // The values aren't validated, but this is the best we've seen so far
- bestPathData = pathData;
- }
- }
-
- if (useBestEffort)
- {
- return new VirtualPathData(
- bestPathData.Router,
- NormalizeVirtualPath(bestPathData.VirtualPath),
- bestPathData.DataTokens);
- }
- else
- {
- return null;
- }
+ return NormalizeVirtualPath(GetVirtualPath(context, _routes));
}
}
- private PathString NormalizeVirtualPath(PathString path)
+ private VirtualPathData GetVirtualPath(VirtualPathContext context, List routes)
{
- var url = path.Value;
+ for (var i = 0; i < routes.Count; i++)
+ {
+ var route = routes[i];
+
+ var pathData = route.GetVirtualPath(context);
+ if (pathData != null)
+ {
+ return pathData;
+ }
+ }
+
+ return null;
+ }
+
+ private VirtualPathData NormalizeVirtualPath(VirtualPathData pathData)
+ {
+ if (pathData == null)
+ {
+ return pathData;
+ }
+
+ var url = pathData.VirtualPath.Value;
if (!string.IsNullOrEmpty(url) && (_options.LowercaseUrls || _options.AppendTrailingSlash))
{
@@ -229,10 +164,10 @@ namespace Microsoft.AspNet.Routing
// queryString will contain the delimiter ? or # as the first character, so it's safe to append.
url = urlWithoutQueryString + queryString;
- return new PathString(url);
+ return new VirtualPathData(pathData.Router, url, pathData.DataTokens);
}
- return path;
+ return pathData;
}
private void EnsureOptions(HttpContext context)
diff --git a/src/Microsoft.AspNet.Routing/RouteOptions.cs b/src/Microsoft.AspNet.Routing/RouteOptions.cs
index aadb80a450..894b3eb249 100644
--- a/src/Microsoft.AspNet.Routing/RouteOptions.cs
+++ b/src/Microsoft.AspNet.Routing/RouteOptions.cs
@@ -69,13 +69,5 @@ namespace Microsoft.AspNet.Routing
{"required", typeof(RequiredRouteConstraint) },
};
}
-
- ///
- /// Gets or sets the value that enables best-effort link generation.
- ///
- /// If enabled, link generation will use allow link generation to succeed when the set of values provided
- /// cannot be validated.
- ///
- public bool UseBestEffortLinkGeneration { get; set; }
}
}
diff --git a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs
index e3f9538ccd..e835d4dceb 100644
--- a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs
+++ b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs
@@ -179,21 +179,19 @@ namespace Microsoft.AspNet.Routing.Template
return null;
}
- EnsureLoggers(context.Context);
- if (!RouteConstraintMatcher.Match(Constraints,
- values.CombinedValues,
- context.Context,
- this,
- RouteDirection.UrlGeneration,
- _constraintLogger))
+ EnsureLoggers(context.HttpContext);
+ if (!RouteConstraintMatcher.Match(
+ Constraints,
+ values.CombinedValues,
+ context.HttpContext,
+ this,
+ RouteDirection.UrlGeneration,
+ _constraintLogger))
{
return null;
}
- // Validate that the target can accept these values.
- var childContext = CreateChildVirtualPathContext(context, values.AcceptedValues);
-
- var pathData = _target.GetVirtualPath(childContext);
+ var pathData = _target.GetVirtualPath(context);
if (pathData != null)
{
// If the target generates a value then that can short circuit.
@@ -219,43 +217,9 @@ namespace Microsoft.AspNet.Routing.Template
}
}
- context.IsBound = childContext.IsBound;
-
return pathData;
}
- private VirtualPathContext CreateChildVirtualPathContext(
- VirtualPathContext context,
- IDictionary acceptedValues)
- {
- // We want to build the set of values that would be provided if this route were to generated
- // a link and then immediately match it. This includes all the accepted parameter values, and
- // the defaults. Accepted values that would go in the query string aren't included.
- var providedValues = new RouteValueDictionary();
-
- foreach (var parameter in _parsedTemplate.Parameters)
- {
- object value;
- if (acceptedValues.TryGetValue(parameter.Name, out value))
- {
- providedValues.Add(parameter.Name, value);
- }
- }
-
- foreach (var kvp in _defaults)
- {
- if (!providedValues.ContainsKey(kvp.Key))
- {
- providedValues.Add(kvp.Key, kvp.Value);
- }
- }
-
- return new VirtualPathContext(context.Context, context.AmbientValues, context.Values)
- {
- ProvidedValues = providedValues,
- };
- }
-
private static IReadOnlyDictionary GetConstraints(
IInlineConstraintResolver inlineConstraintResolver,
string template,
diff --git a/src/Microsoft.AspNet.Routing/Tree/TreeRouter.cs b/src/Microsoft.AspNet.Routing/Tree/TreeRouter.cs
index 7aa8a65333..ec48e11312 100644
--- a/src/Microsoft.AspNet.Routing/Tree/TreeRouter.cs
+++ b/src/Microsoft.AspNet.Routing/Tree/TreeRouter.cs
@@ -143,7 +143,6 @@ namespace Microsoft.AspNet.Routing.Tree
var path = GenerateVirtualPath(context, match.Entry);
if (path != null)
{
- context.IsBound = true;
return path;
}
}
@@ -382,7 +381,6 @@ namespace Microsoft.AspNet.Routing.Tree
var path = GenerateVirtualPath(context, entry);
if (path != null)
{
- context.IsBound = true;
return path;
}
}
@@ -430,7 +428,7 @@ namespace Microsoft.AspNet.Routing.Tree
var matched = RouteConstraintMatcher.Match(
entry.Constraints,
bindingResult.CombinedValues,
- context.Context,
+ context.HttpContext,
this,
RouteDirection.UrlGeneration,
_constraintLogger);
@@ -441,30 +439,13 @@ namespace Microsoft.AspNet.Routing.Tree
return null;
}
- // These values are used to signal to the next route what we would produce if we round-tripped
- // (generate a link and then parse). In MVC the 'next route' is typically the MvcRouteHandler.
- var providedValues = new Dictionary(
- bindingResult.AcceptedValues,
- StringComparer.OrdinalIgnoreCase);
- providedValues.Add(RouteGroupKey, entry.RouteGroup);
-
- var childContext = new VirtualPathContext(context.Context, context.AmbientValues, context.Values)
- {
- ProvidedValues = providedValues,
- };
-
- var pathData = _next.GetVirtualPath(childContext);
+ var pathData = _next.GetVirtualPath(context);
if (pathData != null)
{
// If path is non-null then the target router short-circuited, we don't expect this
// in typical MVC scenarios.
return pathData;
}
- else if (!childContext.IsBound)
- {
- // The target router has rejected these values. We don't expect this in typical MVC scenarios.
- return null;
- }
var path = entry.Binder.BindValues(bindingResult.AcceptedValues);
if (path == null)
diff --git a/test/Microsoft.AspNet.Routing.Tests/RouteCollectionTest.cs b/test/Microsoft.AspNet.Routing.Tests/RouteCollectionTest.cs
index 796e441857..e3ca1b34fa 100644
--- a/test/Microsoft.AspNet.Routing.Tests/RouteCollectionTest.cs
+++ b/test/Microsoft.AspNet.Routing.Tests/RouteCollectionTest.cs
@@ -47,7 +47,6 @@ namespace Microsoft.AspNet.Routing
var virtualPathContext = CreateVirtualPathContext(
options: GetRouteOptions(
lowerCaseUrls: lowercaseUrls,
- useBestEffortLinkGeneration: true,
appendTrailingSlash: appendTrailingSlash));
// Act
@@ -88,7 +87,7 @@ namespace Microsoft.AspNet.Routing
}
[Theory]
- [MemberData("DataTokensTestData")]
+ [MemberData(nameof(DataTokensTestData))]
public void GetVirtualPath_ReturnsDataTokens(RouteValueDictionary dataTokens, string routerName)
{
// Arrange
@@ -286,306 +285,13 @@ namespace Microsoft.AspNet.Routing
innerRouteCollection.Add(namedRoute);
routeCollection.Add(innerRouteCollection);
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = true,
- };
-
- var virtualPathContext = CreateVirtualPathContext("Ambiguous", options: options);
+ var virtualPathContext = CreateVirtualPathContext("Ambiguous", options: new RouteOptions());
// Act & Assert
var ex = Assert.Throws(() => routeCollection.GetVirtualPath(virtualPathContext));
Assert.Equal("The supplied route name 'Ambiguous' is ambiguous and matched more than one route.", ex.Message);
}
- [Fact]
- public void GetVirtualPath_NamedRoute_BestEffort_BestInTopCollection()
- {
- // Arrange
- var bestMatch = CreateNamedRoute("Match", accept: true, matchValue: "best");
- var noMatch = CreateNamedRoute("NoMatch", accept: true, matchValue: "bad");
-
- var routeCollection = new RouteCollection();
- routeCollection.Add(bestMatch);
-
- var innerRouteCollection = new RouteCollection();
- innerRouteCollection.Add(noMatch);
- routeCollection.Add(innerRouteCollection);
-
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = true,
- };
-
- var virtualPathContext = CreateVirtualPathContext("Match", options: options);
-
- // Act
- var pathData = routeCollection.GetVirtualPath(virtualPathContext);
-
- Assert.Equal(new PathString("/best"), pathData.VirtualPath);
- var namedRouter = Assert.IsAssignableFrom(pathData.Router);
- Assert.Equal("Match", namedRouter.Name);
- Assert.Empty(pathData.DataTokens);
- }
-
- [Fact]
- public void GetVirtualPath_NamedRoute_BestEffort_BestMatchInNestedCollection()
- {
- // Arrange
- var bestMatch = CreateNamedRoute("NoMatch", accept: true, matchValue: "bad");
- var noMatch = CreateNamedRoute("Match", accept: true, matchValue: "best");
-
- var routeCollection = new RouteCollection();
- routeCollection.Add(noMatch);
-
- var innerRouteCollection = new RouteCollection();
- innerRouteCollection.Add(bestMatch);
- routeCollection.Add(innerRouteCollection);
-
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = true,
- };
-
- var virtualPathContext = CreateVirtualPathContext("Match", options: options);
-
- // Act
- var pathData = routeCollection.GetVirtualPath(virtualPathContext);
-
- Assert.Equal(new PathString("/best"), pathData.VirtualPath);
- var namedRouter = Assert.IsAssignableFrom(pathData.Router);
- Assert.Equal("Match", namedRouter.Name);
- Assert.Empty(pathData.DataTokens);
- }
-
- [Fact]
- public void GetVirtualPath_NamedRoute_BestEffort_FirstRouteWins()
- {
- // Arrange
- var bestMatch = CreateNamedRoute("Match", accept: false, matchValue: "best");
- var noMatch = CreateNamedRoute("NoMatch", accept: false, matchValue: "bad");
-
- var routeCollection = new RouteCollection();
- routeCollection.Add(noMatch);
-
- var innerRouteCollection = new RouteCollection();
- innerRouteCollection.Add(bestMatch);
- routeCollection.Add(innerRouteCollection);
-
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = true,
- };
-
- var virtualPathContext = CreateVirtualPathContext("Match", options: options);
-
- // Act
- var pathData = routeCollection.GetVirtualPath(virtualPathContext);
-
- Assert.Equal(new PathString("/best"), pathData.VirtualPath);
- var namedRouter = Assert.IsAssignableFrom(pathData.Router);
- Assert.Equal("Match", namedRouter.Name);
- Assert.Empty(pathData.DataTokens);
- }
-
- [Fact]
- public void GetVirtualPath_BestEffort_FirstRouteWins()
- {
- // Arrange
- var route1 = CreateRoute(accept: false, match: true, matchValue: "best");
- var route2 = CreateRoute(accept: false, match: true, matchValue: "bad");
- var route3 = CreateRoute(accept: false, match: true, matchValue: "bad");
-
- var routeCollection = new RouteCollection();
- routeCollection.Add(route1.Object);
- routeCollection.Add(route2.Object);
- routeCollection.Add(route3.Object);
-
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = true,
- };
-
- var virtualPathContext = CreateVirtualPathContext(options: options);
-
- // Act
- var pathData = routeCollection.GetVirtualPath(virtualPathContext);
-
- Assert.Equal(new PathString("/best"), pathData.VirtualPath);
- Assert.Same(route1.Object, pathData.Router);
- Assert.Empty(pathData.DataTokens);
-
- // All of these should be called
- route1.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route2.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route3.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- }
-
- [Fact]
- public void GetVirtualPath_NoBestEffort_NoMatch()
- {
- // Arrange
- var route1 = CreateRoute(accept: false, match: true, matchValue: "best");
- var route2 = CreateRoute(accept: false, match: true, matchValue: "bad");
- var route3 = CreateRoute(accept: false, match: true, matchValue: "bad");
-
- var routeCollection = new RouteCollection();
- routeCollection.Add(route1.Object);
- routeCollection.Add(route2.Object);
- routeCollection.Add(route3.Object);
-
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = false,
- };
-
- var virtualPathContext = CreateVirtualPathContext(options: options);
-
- // Act
- var path = routeCollection.GetVirtualPath(virtualPathContext);
-
- Assert.Null(path);
-
- // All of these should be called
- route1.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route2.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route3.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- }
-
- [Fact]
- public void GetVirtualPath_BestEffort_FirstRouteWins_WithNonMatchingRoutes()
- {
- // Arrange
- var route1 = CreateRoute(accept: false, match: false, matchValue: "bad");
- var route2 = CreateRoute(accept: false, match: true, matchValue: "best");
- var route3 = CreateRoute(accept: false, match: true, matchValue: "bad");
-
- var routeCollection = new RouteCollection();
- routeCollection.Add(route1.Object);
- routeCollection.Add(route2.Object);
- routeCollection.Add(route3.Object);
-
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = true,
- };
-
- var virtualPathContext = CreateVirtualPathContext(options: options);
-
- // Act
- var pathData = routeCollection.GetVirtualPath(virtualPathContext);
-
- Assert.Equal(new PathString("/best"), pathData.VirtualPath);
- Assert.Same(route2.Object, pathData.Router);
- Assert.Empty(pathData.DataTokens);
-
- // All of these should be called
- route1.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route2.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route3.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- }
-
- [Fact]
- public void GetVirtualPath_BestEffort_FirstValidatedValuesWins()
- {
- // Arrange
- var route1 = CreateRoute(accept: false, match: true, matchValue: "bad");
- var route2 = CreateRoute(accept: false, match: true, matchValue: "bad");
- var route3 = CreateRoute(accept: true, match: true, matchValue: "best");
-
- var routeCollection = new RouteCollection();
- routeCollection.Add(route1.Object);
- routeCollection.Add(route2.Object);
- routeCollection.Add(route3.Object);
-
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = true,
- };
-
- var virtualPathContext = CreateVirtualPathContext(options: options);
-
- // Act
- var pathData = routeCollection.GetVirtualPath(virtualPathContext);
-
- Assert.Equal(new PathString("/best"), pathData.VirtualPath);
- Assert.Same(route3.Object, pathData.Router);
- Assert.Empty(pathData.DataTokens);
-
- // All of these should be called
- route1.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route2.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route3.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- }
-
- [Fact]
- public void GetVirtualPath_BestEffort_FirstValidatedValuesWins_ShortCircuit()
- {
- // Arrange
- var route1 = CreateRoute(accept: false, match: true, matchValue: "bad");
- var route2 = CreateRoute(accept: true, match: true, matchValue: "best");
- var route3 = CreateRoute(accept: true, match: true, matchValue: "bad");
-
- var routeCollection = new RouteCollection();
- routeCollection.Add(route1.Object);
- routeCollection.Add(route2.Object);
- routeCollection.Add(route3.Object);
-
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = true,
- };
-
- var virtualPathContext = CreateVirtualPathContext(options: options);
-
- // Act
- var pathData = routeCollection.GetVirtualPath(virtualPathContext);
-
- Assert.Equal(new PathString("/best"), pathData.VirtualPath);
- Assert.Same(route2.Object, pathData.Router);
- Assert.Empty(pathData.DataTokens);
-
- route1.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route2.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route3.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Never());
- }
-
- [Fact]
- public void GetVirtualPath_BestEffort_FirstValidatedValuesWins_Nested()
- {
- // Arrange
- var route1 = CreateRoute(accept: false, match: true, matchValue: "bad");
- var route2 = CreateRoute(accept: false, match: true, matchValue: "bad");
- var route3 = CreateRoute(accept: true, match: true, matchValue: "best");
-
- var routeCollection = new RouteCollection();
- routeCollection.Add(route1.Object);
-
- var innerRouteCollection = new RouteCollection();
- innerRouteCollection.Add(route2.Object);
- innerRouteCollection.Add(route3.Object);
- routeCollection.Add(innerRouteCollection);
-
- var options = new RouteOptions()
- {
- UseBestEffortLinkGeneration = true,
- };
-
- var virtualPathContext = CreateVirtualPathContext(options: options);
-
- // Act
- var pathData = routeCollection.GetVirtualPath(virtualPathContext);
-
- Assert.Equal(new PathString("/best"), pathData.VirtualPath);
- Assert.Same(route3.Object, pathData.Router);
- Assert.Empty(pathData.DataTokens);
-
- // All of these should be called
- route1.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route2.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- route3.Verify(r => r.GetVirtualPath(It.IsAny()), Times.Once());
- }
-
// "Integration" tests for RouteCollection
public static IEnumerable