Simplify link generation code
- Removes ProvidedValues and IsBound - Removes best-effort link generation - simplify code where possible - lots of test simplification
This commit is contained in:
parent
c911a10692
commit
b01183f023
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// A context for virtual path generation operations.
|
||||
/// </summary>
|
||||
public class VirtualPathContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="VirtualPathContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="Http.HttpContext"/> associated with the current request.</param>
|
||||
/// <param name="ambientValues">The set of route values associated with the current request.</param>
|
||||
/// <param name="values">The set of new values provided for virtual path generation.</param>
|
||||
public VirtualPathContext(
|
||||
HttpContext httpContext,
|
||||
RouteValueDictionary ambientValues,
|
||||
|
|
@ -16,28 +24,43 @@ namespace Microsoft.AspNet.Routing
|
|||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="VirtualPathContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The <see cref="Http.HttpContext"/> associated with the current request.</param>
|
||||
/// <param name="ambientValues">The set of route values associated with the current request.</param>
|
||||
/// <param name="values">The set of new values provided for virtual path generation.</param>
|
||||
/// <param name="routeName">The name of the route to use for virtual path generation.</param>
|
||||
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<string, object> ProvidedValues { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the set of route values associated with the current request.
|
||||
/// </summary>
|
||||
public RouteValueDictionary AmbientValues { get; }
|
||||
|
||||
public HttpContext Context { get; }
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Http.HttpContext"/> associated with the current request.
|
||||
/// </summary>
|
||||
public HttpContext HttpContext { get; }
|
||||
|
||||
public bool IsBound { get; set; }
|
||||
/// <summary>
|
||||
/// Gets the name of the route to use for virtual path generation.
|
||||
/// </summary>
|
||||
public string RouteName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the set of new values provided for virtual path generation.
|
||||
/// </summary>
|
||||
public RouteValueDictionary Values { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<IRouter> 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)
|
||||
|
|
|
|||
|
|
@ -69,13 +69,5 @@ namespace Microsoft.AspNet.Routing
|
|||
{"required", typeof(RequiredRouteConstraint) },
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public bool UseBestEffortLinkGeneration { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string, object> 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<string, IRouteConstraint> GetConstraints(
|
||||
IInlineConstraintResolver inlineConstraintResolver,
|
||||
string template,
|
||||
|
|
|
|||
|
|
@ -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<string, object>(
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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<InvalidOperationException>(() => 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<INamedRouter>(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<INamedRouter>(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<INamedRouter>(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<VirtualPathContext>()), Times.Once());
|
||||
route2.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
route3.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), 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<VirtualPathContext>()), Times.Once());
|
||||
route2.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
route3.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), 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<VirtualPathContext>()), Times.Once());
|
||||
route2.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
route3.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), 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<VirtualPathContext>()), Times.Once());
|
||||
route2.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
route3.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), 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<VirtualPathContext>()), Times.Once());
|
||||
route2.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
route3.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), 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<VirtualPathContext>()), Times.Once());
|
||||
route2.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
route3.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
}
|
||||
|
||||
// "Integration" tests for RouteCollection
|
||||
|
||||
public static IEnumerable<object[]> IntegrationTestData
|
||||
|
|
@ -633,7 +339,7 @@ namespace Microsoft.AspNet.Routing
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData("IntegrationTestData")]
|
||||
[MemberData(nameof(IntegrationTestData))]
|
||||
public void GetVirtualPath_Success(
|
||||
string template,
|
||||
RouteValueDictionary values,
|
||||
|
|
@ -651,12 +357,37 @@ namespace Microsoft.AspNet.Routing
|
|||
var pathData = routeCollection.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.True(context.IsBound);
|
||||
Assert.Equal(new PathString(expectedUrl), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetVirtualPath_NoBestEffort_NoMatch()
|
||||
{
|
||||
// Arrange
|
||||
var route1 = CreateRoute(accept: false, match: false, matchValue: "bad");
|
||||
var route2 = CreateRoute(accept: false, match: false, matchValue: "bad");
|
||||
var route3 = CreateRoute(accept: false, match: false, matchValue: "bad");
|
||||
|
||||
var routeCollection = new RouteCollection();
|
||||
routeCollection.Add(route1.Object);
|
||||
routeCollection.Add(route2.Object);
|
||||
routeCollection.Add(route3.Object);
|
||||
|
||||
var virtualPathContext = CreateVirtualPathContext();
|
||||
|
||||
// Act
|
||||
var path = routeCollection.GetVirtualPath(virtualPathContext);
|
||||
|
||||
Assert.Null(path);
|
||||
|
||||
// All of these should be called
|
||||
route1.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
route2.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
route3.Verify(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()), Times.Once());
|
||||
}
|
||||
|
||||
// DataTokens test data for RouterCollection.GetVirtualPath
|
||||
public static IEnumerable<object[]> DataTokensTestData
|
||||
{
|
||||
|
|
@ -744,7 +475,6 @@ namespace Microsoft.AspNet.Routing
|
|||
var target = new Mock<INamedRouter>(MockBehavior.Strict);
|
||||
target
|
||||
.Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(c => c.IsBound = accept && c.RouteName == name)
|
||||
.Returns<VirtualPathContext>(c =>
|
||||
c.RouteName == name ? new VirtualPathData(target.Object, matchValue) : null)
|
||||
.Verifiable();
|
||||
|
|
@ -770,7 +500,6 @@ namespace Microsoft.AspNet.Routing
|
|||
var target = new Mock<IRouter>(MockBehavior.Strict);
|
||||
target
|
||||
.Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(c => c.IsBound = true)
|
||||
.Returns<VirtualPathContext>(rc => null);
|
||||
|
||||
var resolverMock = new Mock<IInlineConstraintResolver>();
|
||||
|
|
@ -876,7 +605,6 @@ namespace Microsoft.AspNet.Routing
|
|||
var target = new Mock<IRouter>(MockBehavior.Strict);
|
||||
target
|
||||
.Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(c => c.IsBound = accept)
|
||||
.Returns(accept || match ? new VirtualPathData(target.Object, matchValue) : null)
|
||||
.Verifiable();
|
||||
|
||||
|
|
@ -891,12 +619,10 @@ namespace Microsoft.AspNet.Routing
|
|||
|
||||
private static RouteOptions GetRouteOptions(
|
||||
bool lowerCaseUrls = false,
|
||||
bool useBestEffortLinkGeneration = true,
|
||||
bool appendTrailingSlash = false)
|
||||
{
|
||||
var routeOptions = new RouteOptions();
|
||||
routeOptions.LowercaseUrls = lowerCaseUrls;
|
||||
routeOptions.UseBestEffortLinkGeneration = useBestEffortLinkGeneration;
|
||||
routeOptions.AppendTrailingSlash = appendTrailingSlash;
|
||||
|
||||
return routeOptions;
|
||||
|
|
|
|||
|
|
@ -881,7 +881,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.True(context.IsBound);
|
||||
Assert.Equal(new PathString("/Home"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
|
|
@ -898,7 +897,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var path = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.False(context.IsBound);
|
||||
Assert.Null(path);
|
||||
}
|
||||
|
||||
|
|
@ -913,7 +911,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var target = new Mock<IRouter>(MockBehavior.Strict);
|
||||
target
|
||||
.Setup(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(c => c.IsBound = true)
|
||||
.Returns(() => new VirtualPathData(target.Object, path, dataTokens));
|
||||
|
||||
var routeDataTokens =
|
||||
|
|
@ -958,7 +955,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var target = new Mock<IRouter>(MockBehavior.Strict);
|
||||
target
|
||||
.Setup(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(c => c.IsBound = true)
|
||||
.Returns(() => null);
|
||||
|
||||
var route = CreateRoute(
|
||||
|
|
@ -998,7 +994,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.False(context.IsBound);
|
||||
Assert.Equal(new PathString("/Home"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
|
|
@ -1015,7 +1010,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.True(context.IsBound);
|
||||
Assert.Equal(new PathString("/Home/Index"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
|
|
@ -1037,7 +1031,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var virtualPath = r.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.False(context.IsBound);
|
||||
Assert.Null(virtualPath);
|
||||
}
|
||||
|
||||
|
|
@ -1057,7 +1050,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.True(context.IsBound);
|
||||
Assert.NotNull(pathData);
|
||||
Assert.Equal(new PathString("/hello/1234"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
|
|
@ -1080,7 +1072,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var virtualPath = r.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.False(context.IsBound);
|
||||
Assert.Null(virtualPath);
|
||||
}
|
||||
|
||||
|
|
@ -1100,7 +1091,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.True(context.IsBound);
|
||||
Assert.NotNull(pathData);
|
||||
Assert.Equal(new PathString("/hello/1234"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
|
|
@ -1132,7 +1122,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.True(context.IsBound);
|
||||
Assert.NotNull(pathData);
|
||||
Assert.Equal(new PathString("/hello/1234"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
|
|
@ -1141,92 +1130,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
target.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetVirtualPath_Sends_ProvidedValues()
|
||||
{
|
||||
// Arrange
|
||||
VirtualPathContext childContext = null;
|
||||
var target = new Mock<IRouter>(MockBehavior.Strict);
|
||||
target
|
||||
.Setup(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(c => { childContext = c; c.IsBound = true; })
|
||||
.Returns<string>(null);
|
||||
|
||||
var route = CreateRoute(target.Object, "{controller}/{action}");
|
||||
var context = CreateVirtualPathContext(
|
||||
new { action = "Store" },
|
||||
new { Controller = "Home", action = "Blog" });
|
||||
|
||||
var expectedValues = new RouteValueDictionary(new { controller = "Home", action = "Store" });
|
||||
|
||||
// Act
|
||||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new PathString("/Home/Store"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
|
||||
Assert.Equal(expectedValues, childContext.ProvidedValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetVirtualPath_Sends_ProvidedValues_IncludingDefaults()
|
||||
{
|
||||
// Arrange
|
||||
VirtualPathContext childContext = null;
|
||||
var target = new Mock<IRouter>(MockBehavior.Strict);
|
||||
target
|
||||
.Setup(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(c => { childContext = c; c.IsBound = true; })
|
||||
.Returns<string>(null);
|
||||
|
||||
var route = CreateRoute(target.Object, "Admin/{controller}/{action}", new { area = "Admin" });
|
||||
var context = CreateVirtualPathContext(
|
||||
new { action = "Store" }, new { Controller = "Home", action = "Blog" });
|
||||
|
||||
var expectedValues = new RouteValueDictionary(
|
||||
new { controller = "Home", action = "Store", area = "Admin" });
|
||||
|
||||
// Act
|
||||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new PathString("/Admin/Home/Store"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
|
||||
Assert.Equal(expectedValues, childContext.ProvidedValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetVirtualPath_Sends_ProvidedValues_ButNotQueryStringValues()
|
||||
{
|
||||
// Arrange
|
||||
VirtualPathContext childContext = null;
|
||||
var target = new Mock<IRouter>(MockBehavior.Strict);
|
||||
target
|
||||
.Setup(r => r.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(c => { childContext = c; c.IsBound = true; })
|
||||
.Returns<string>(null);
|
||||
|
||||
var route = CreateRoute(target.Object, "{controller}/{action}");
|
||||
var context = CreateVirtualPathContext(
|
||||
new { action = "Store", id = 5 }, new { Controller = "Home", action = "Blog" });
|
||||
|
||||
var expectedValues = new RouteValueDictionary(new { controller = "Home", action = "Store" });
|
||||
|
||||
// Act
|
||||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new PathString("/Home/Store?id=5"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
|
||||
Assert.Equal(expectedValues, childContext.ProvidedValues);
|
||||
}
|
||||
|
||||
// Any ambient values from the current request should be visible to constraint, even
|
||||
// if they have nothing to do with the route generating a link
|
||||
[Fact]
|
||||
|
|
@ -1930,7 +1833,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
var target = new Mock<IRouter>(MockBehavior.Strict);
|
||||
target
|
||||
.Setup(e => e.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(c => c.IsBound = handleRequest)
|
||||
.Returns<VirtualPathContext>(rc => null);
|
||||
|
||||
target
|
||||
|
|
|
|||
|
|
@ -376,22 +376,13 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
public void TreeRouter_GenerateLink(string firstTemplate, string secondTemplate, string expectedPath)
|
||||
{
|
||||
// Arrange
|
||||
var expectedGroup = CreateRouteGroup(0, firstTemplate);
|
||||
|
||||
string selectedGroup = null;
|
||||
Action<VirtualPathContext> callback = ctx =>
|
||||
{
|
||||
selectedGroup = (string)ctx.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
};
|
||||
|
||||
var values = new Dictionary<string, object>
|
||||
{
|
||||
{"url", "dingo" },
|
||||
{"id", 5 }
|
||||
};
|
||||
|
||||
var route = CreateAttributeRoute(callback, firstTemplate, secondTemplate);
|
||||
var route = CreateAttributeRoute(firstTemplate, secondTemplate);
|
||||
var context = CreateVirtualPathContext(
|
||||
values: values,
|
||||
ambientValues: null);
|
||||
|
|
@ -404,7 +395,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString(expectedPath), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
Assert.Equal(expectedGroup, selectedGroup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -414,16 +404,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
var firstTemplate = "template";
|
||||
var secondTemplate = "template/{parameter:int=1003}";
|
||||
|
||||
var expectedGroup = CreateRouteGroup(0, secondTemplate);
|
||||
|
||||
string selectedGroup = null;
|
||||
Action<VirtualPathContext> callback = ctx =>
|
||||
{
|
||||
selectedGroup = (string)ctx.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
};
|
||||
|
||||
var route = CreateAttributeRoute(callback, firstTemplate, secondTemplate);
|
||||
var route = CreateAttributeRoute(firstTemplate, secondTemplate);
|
||||
var context = CreateVirtualPathContext(
|
||||
values: null,
|
||||
ambientValues: null);
|
||||
|
|
@ -437,10 +418,8 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString($"/template"), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
// Even though the path was /template, the group generated from was /template/{paramter:int=1003}
|
||||
Assert.Equal(expectedGroup, selectedGroup);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData("template/{parameter:int=5}", "template", "/template/5")]
|
||||
[InlineData("template/{parameter}", "template", "/template/5")]
|
||||
|
|
@ -450,16 +429,8 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
string secondTemplate,
|
||||
string expectedPath)
|
||||
{
|
||||
var expectedGroup = CreateRouteGroup(0, firstTemplate);
|
||||
|
||||
string selectedGroup = null;
|
||||
Action<VirtualPathContext> callback = ctx =>
|
||||
{
|
||||
selectedGroup = (string)ctx.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
};
|
||||
|
||||
var route = CreateAttributeRoute(callback, firstTemplate, secondTemplate);
|
||||
// Arrange
|
||||
var route = CreateAttributeRoute(firstTemplate, secondTemplate);
|
||||
var parameter = 5;
|
||||
var id = 1234;
|
||||
var values = new Dictionary<string, object>
|
||||
|
|
@ -479,7 +450,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString(expectedPath), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
Assert.Equal(expectedGroup, selectedGroup);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -492,16 +462,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
string expectedPath)
|
||||
{
|
||||
// Arrange
|
||||
var expectedGroup = CreateRouteGroup(0, secondTemplate);
|
||||
|
||||
string selectedGroup = null;
|
||||
Action<VirtualPathContext> callback = ctx =>
|
||||
{
|
||||
selectedGroup = (string)ctx.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
};
|
||||
|
||||
var route = CreateAttributeRoute(callback, firstTemplate, secondTemplate);
|
||||
var route = CreateAttributeRoute(firstTemplate, secondTemplate);
|
||||
var parameter = 5;
|
||||
var id = 1234;
|
||||
var values = new Dictionary<string, object>
|
||||
|
|
@ -510,7 +471,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
{ nameof(id), id }
|
||||
};
|
||||
var context = CreateVirtualPathContext(
|
||||
values: null,
|
||||
values: null,
|
||||
ambientValues: values);
|
||||
|
||||
// Act
|
||||
|
|
@ -521,7 +482,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString(expectedPath), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
Assert.Equal(expectedGroup, selectedGroup);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -538,18 +498,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
public void TreeRouter_GenerateLink_RespectsPrecedence(string firstTemplate, string secondTemplate)
|
||||
{
|
||||
// Arrange
|
||||
var expectedGroup = CreateRouteGroup(0, firstTemplate);
|
||||
|
||||
string selectedGroup = null;
|
||||
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(n => n.GetVirtualPath(It.IsAny<VirtualPathContext>())).Callback<VirtualPathContext>(ctx =>
|
||||
{
|
||||
selectedGroup = (string)ctx.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
})
|
||||
.Returns((VirtualPathData)null);
|
||||
|
||||
var matchingRoutes = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
|
||||
var firstEntry = CreateGenerationEntry(firstTemplate, requiredValues: null);
|
||||
|
|
@ -559,7 +507,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
// try to generate a link, the route with a higher precedence gets tried first.
|
||||
var linkGenerationEntries = new[] { secondEntry, firstEntry };
|
||||
|
||||
var route = CreateAttributeRoute(next.Object, matchingRoutes, linkGenerationEntries);
|
||||
var route = CreateAttributeRoute(matchingRoutes, linkGenerationEntries);
|
||||
|
||||
var context = CreateVirtualPathContext(values: null, ambientValues: new { parameter = 5 });
|
||||
|
||||
|
|
@ -571,8 +519,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString("/template/5"), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
|
||||
Assert.Equal(expectedGroup, selectedGroup);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -591,25 +537,13 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
object parameter)
|
||||
{
|
||||
// Arrange
|
||||
var expectedGroup = CreateRouteGroup(0, template);
|
||||
|
||||
string selectedGroup = null;
|
||||
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(n => n.GetVirtualPath(It.IsAny<VirtualPathContext>())).Callback<VirtualPathContext>(ctx =>
|
||||
{
|
||||
selectedGroup = (string)ctx.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
})
|
||||
.Returns((VirtualPathData)null);
|
||||
|
||||
var matchingRoutes = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
|
||||
var entry = CreateGenerationEntry(template, requiredValues: null);
|
||||
|
||||
var linkGenerationEntries = new[] { entry };
|
||||
|
||||
var route = CreateAttributeRoute(next.Object, matchingRoutes, linkGenerationEntries);
|
||||
var route = CreateAttributeRoute(matchingRoutes, linkGenerationEntries);
|
||||
|
||||
VirtualPathContext context;
|
||||
if (parameter != null)
|
||||
|
|
@ -652,17 +586,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
public void TreeRouter_GenerateLink_RespectsOrderOverPrecedence(string firstTemplate, string secondTemplate)
|
||||
{
|
||||
// Arrange
|
||||
var selectedGroup = CreateRouteGroup(0, secondTemplate);
|
||||
|
||||
string firstRouteGroupSelected = null;
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(n => n.GetVirtualPath(It.IsAny<VirtualPathContext>())).Callback<VirtualPathContext>(ctx =>
|
||||
{
|
||||
firstRouteGroupSelected = (string)ctx.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
})
|
||||
.Returns((VirtualPathData)null);
|
||||
|
||||
var matchingRoutes = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
|
||||
var firstRoute = CreateGenerationEntry(firstTemplate, requiredValues: null, order: 1);
|
||||
|
|
@ -673,7 +596,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
// relative order gets tried first.
|
||||
var linkGenerationEntries = new[] { firstRoute, secondRoute };
|
||||
|
||||
var route = CreateAttributeRoute(next.Object, matchingRoutes, linkGenerationEntries);
|
||||
var route = CreateAttributeRoute(matchingRoutes, linkGenerationEntries);
|
||||
|
||||
var context = CreateVirtualPathContext(null, ambientValues: new { parameter = 5 });
|
||||
|
||||
|
|
@ -685,8 +608,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString("/template/5"), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
|
||||
Assert.Equal(selectedGroup, firstRouteGroupSelected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -698,17 +619,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
public void TreeRouter_GenerateLink_RespectsOrder(string firstTemplate, string secondTemplate)
|
||||
{
|
||||
// Arrange
|
||||
var expectedGroup = CreateRouteGroup(0, secondTemplate);
|
||||
|
||||
var next = new Mock<IRouter>();
|
||||
string selectedGroup = null;
|
||||
next.Setup(n => n.GetVirtualPath(It.IsAny<VirtualPathContext>())).Callback<VirtualPathContext>(ctx =>
|
||||
{
|
||||
selectedGroup = (string)ctx.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
})
|
||||
.Returns((VirtualPathData)null);
|
||||
|
||||
var matchingRoutes = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
|
||||
var firstRoute = CreateGenerationEntry(firstTemplate, requiredValues: null, order: 1);
|
||||
|
|
@ -718,7 +628,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
// we try to generate a link, the route with the higher relative order gets tried first.
|
||||
var linkGenerationEntries = new[] { firstRoute, secondRoute };
|
||||
|
||||
var route = CreateAttributeRoute(next.Object, matchingRoutes, linkGenerationEntries);
|
||||
var route = CreateAttributeRoute(matchingRoutes, linkGenerationEntries);
|
||||
|
||||
var context = CreateVirtualPathContext(values: null, ambientValues: new { first = 5, second = 5 });
|
||||
|
||||
|
|
@ -730,8 +640,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString("/template/5"), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
|
||||
Assert.Equal(expectedGroup, selectedGroup);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -743,17 +651,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
public void TreeRouter_GenerateLink_EnsuresStableOrder(string firstTemplate, string secondTemplate)
|
||||
{
|
||||
// Arrange
|
||||
var expectedGroup = CreateRouteGroup(0, firstTemplate);
|
||||
|
||||
var next = new Mock<IRouter>();
|
||||
string selectedGroup = null;
|
||||
next.Setup(n => n.GetVirtualPath(It.IsAny<VirtualPathContext>())).Callback<VirtualPathContext>(ctx =>
|
||||
{
|
||||
selectedGroup = (string)ctx.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
})
|
||||
.Returns((VirtualPathData)null);
|
||||
|
||||
var matchingRoutes = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
|
||||
var firstRoute = CreateGenerationEntry(firstTemplate, requiredValues: null, order: 0);
|
||||
|
|
@ -763,7 +660,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
// we try to generate a link, the route with the higher template order gets tried first.
|
||||
var linkGenerationEntries = new[] { secondRoute, firstRoute };
|
||||
|
||||
var route = CreateAttributeRoute(next.Object, matchingRoutes, linkGenerationEntries);
|
||||
var route = CreateAttributeRoute(matchingRoutes, linkGenerationEntries);
|
||||
|
||||
var context = CreateVirtualPathContext(values: null, ambientValues: new { first = 5, second = 5 });
|
||||
|
||||
|
|
@ -775,8 +672,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString("/first/5"), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
|
||||
Assert.Equal(expectedGroup, selectedGroup);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> NamedEntriesWithDifferentTemplates
|
||||
|
|
@ -880,20 +775,9 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
var expectedLink = new PathString(
|
||||
namedEntries.First().Template.Parameters.Any() ? "/template/5" : "/template");
|
||||
|
||||
var expectedGroup = "0&" + namedEntries.First().Template.TemplateText;
|
||||
string selectedGroup = null;
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(s => s.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(vpc =>
|
||||
{
|
||||
vpc.IsBound = true;
|
||||
selectedGroup = (string)vpc.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
})
|
||||
.Returns((VirtualPathData)null);
|
||||
|
||||
var matchingEntries = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
|
||||
var route = CreateAttributeRoute(next.Object, matchingEntries, namedEntries);
|
||||
var route = CreateAttributeRoute(matchingEntries, namedEntries);
|
||||
|
||||
var ambientValues = namedEntries.First().Template.Parameters.Any() ? new { parameter = 5 } : null;
|
||||
|
||||
|
|
@ -907,24 +791,12 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(expectedLink, result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
|
||||
Assert.Equal(expectedGroup, selectedGroup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TreeRouter_GenerateLink_WithName()
|
||||
{
|
||||
// Arrange
|
||||
string selectedGroup = null;
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(s => s.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(vpc =>
|
||||
{
|
||||
vpc.IsBound = true;
|
||||
selectedGroup = (string)vpc.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
})
|
||||
.Returns((VirtualPathData)null);
|
||||
|
||||
var namedEntry = CreateGenerationEntry("named", requiredValues: null, order: 1, name: "NamedRoute");
|
||||
var unnamedEntry = CreateGenerationEntry("unnamed", requiredValues: null, order: 0);
|
||||
|
||||
|
|
@ -934,7 +806,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
|
||||
var matchingEntries = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
|
||||
var route = CreateAttributeRoute(next.Object, matchingEntries, linkGenerationEntries);
|
||||
var route = CreateAttributeRoute(matchingEntries, linkGenerationEntries);
|
||||
|
||||
var context = CreateVirtualPathContext(values: null, ambientValues: null, name: "NamedRoute");
|
||||
|
||||
|
|
@ -946,23 +818,12 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString("/named"), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
|
||||
Assert.Equal("1&named", selectedGroup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TreeRouter_DoesNotGenerateLink_IfThereIsNoRouteForAGivenName()
|
||||
{
|
||||
// Arrange
|
||||
string selectedGroup = null;
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(s => s.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(vpc =>
|
||||
{
|
||||
vpc.IsBound = true;
|
||||
selectedGroup = (string)vpc.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
});
|
||||
|
||||
var namedEntry = CreateGenerationEntry("named", requiredValues: null, order: 1, name: "NamedRoute");
|
||||
|
||||
// Add an unnamed entry to ensure we don't fall back to generating a link for an unnamed route.
|
||||
|
|
@ -974,7 +835,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
|
||||
var matchingEntries = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
|
||||
var route = CreateAttributeRoute(next.Object, matchingEntries, linkGenerationEntries);
|
||||
var route = CreateAttributeRoute(matchingEntries, linkGenerationEntries);
|
||||
|
||||
var context = CreateVirtualPathContext(values: null, ambientValues: null, name: "NonExistingNamedRoute");
|
||||
|
||||
|
|
@ -994,15 +855,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
public void TreeRouter_DoesNotGenerateLink_IfValuesDoNotMatchNamedEntry(string template, string value)
|
||||
{
|
||||
// Arrange
|
||||
string selectedGroup = null;
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(s => s.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(vpc =>
|
||||
{
|
||||
vpc.IsBound = true;
|
||||
selectedGroup = (string)vpc.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
});
|
||||
|
||||
var namedEntry = CreateGenerationEntry(template, requiredValues: null, order: 1, name: "NamedRoute");
|
||||
|
||||
// Add an unnamed entry to ensure we don't fall back to generating a link for an unnamed route.
|
||||
|
|
@ -1014,7 +866,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
|
||||
var matchingEntries = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
|
||||
var route = CreateAttributeRoute(next.Object, matchingEntries, linkGenerationEntries);
|
||||
var route = CreateAttributeRoute(matchingEntries, linkGenerationEntries);
|
||||
|
||||
var ambientValues = value == null ? null : new { parameter = value };
|
||||
|
||||
|
|
@ -1035,14 +887,9 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
public void TreeRouter_GeneratesLink_IfValuesMatchNamedEntry(string template, string value)
|
||||
{
|
||||
// Arrange
|
||||
string selectedGroup = null;
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(s => s.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Callback<VirtualPathContext>(vpc =>
|
||||
{
|
||||
vpc.IsBound = true;
|
||||
selectedGroup = (string)vpc.ProvidedValues[TreeRouter.RouteGroupKey];
|
||||
})
|
||||
next
|
||||
.Setup(s => s.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Returns((VirtualPathData)null);
|
||||
|
||||
var namedEntry = CreateGenerationEntry(template, requiredValues: null, order: 1, name: "NamedRoute");
|
||||
|
|
@ -1070,11 +917,9 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString("/template/5"), result.VirtualPath);
|
||||
Assert.Same(route, result.Router);
|
||||
Assert.Empty(result.DataTokens);
|
||||
|
||||
Assert.Equal(string.Format("1&{0}", template), selectedGroup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void TreeRouter_GenerateLink_NoRequiredValues()
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -1174,14 +1019,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
"api/{area}/dosomething/{controller}/{action}",
|
||||
new { action = "Index", controller = "Store", area = "AwesomeCo" });
|
||||
|
||||
var expectedValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "area", "AwesomeCo" },
|
||||
{ "controller", "Store" },
|
||||
{ "action", "Index" },
|
||||
{ TreeRouter.RouteGroupKey, entry.RouteGroup },
|
||||
};
|
||||
|
||||
var next = new StubRouter();
|
||||
var route = CreateAttributeRoute(next, entry);
|
||||
|
||||
|
|
@ -1197,8 +1034,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString("/api/AwesomeCo/dosomething/Store/Index"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
|
||||
Assert.Equal(expectedValues, next.GenerationContext.ProvidedValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1226,13 +1061,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
// Arrange
|
||||
var entry = CreateGenerationEntry("api/Store/{action}/{id:int}", new { action = "Index", controller = "Store" });
|
||||
|
||||
var expectedValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "action", "Index" },
|
||||
{ "id", 5 },
|
||||
{ TreeRouter.RouteGroupKey, entry.RouteGroup },
|
||||
};
|
||||
|
||||
var next = new StubRouter();
|
||||
var route = CreateAttributeRoute(next, entry);
|
||||
|
||||
|
|
@ -1246,8 +1074,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Equal(new PathString("/api/Store/Index/5"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
|
||||
Assert.Equal(expectedValues, next.GenerationContext.ProvidedValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1257,12 +1083,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
var entry = CreateGenerationEntry("api/Store/{action}/{id:int}", new { action = "Index", controller = "Store" });
|
||||
var route = CreateAttributeRoute(entry);
|
||||
|
||||
var expectedValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "id", "5" },
|
||||
{ TreeRouter.RouteGroupKey, entry.RouteGroup },
|
||||
};
|
||||
|
||||
var next = new StubRouter();
|
||||
var context = CreateVirtualPathContext(new { action = "Index", controller = "Store", id = "heyyyy" });
|
||||
|
||||
|
|
@ -1311,29 +1131,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Empty(pathData.DataTokens);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TreeRouter_GenerateLink_ForwardsRouteGroup()
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateGenerationEntry("api/Store", new { action = "Index", controller = "Store" });
|
||||
|
||||
var expectedValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ TreeRouter.RouteGroupKey, entry.RouteGroup },
|
||||
};
|
||||
|
||||
var next = new StubRouter();
|
||||
var route = CreateAttributeRoute(next, entry);
|
||||
|
||||
var context = CreateVirtualPathContext(new { action = "Index", controller = "Store" });
|
||||
|
||||
// Act
|
||||
var path = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedValues, next.GenerationContext.ProvidedValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TreeRouter_GenerateLink_RejectedByFirstRoute()
|
||||
{
|
||||
|
|
@ -1355,41 +1152,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Assert.Empty(pathData.DataTokens);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TreeRouter_GenerateLink_RejectedByHandler()
|
||||
{
|
||||
// Arrange
|
||||
var entry1 = CreateGenerationEntry("api/Store", new { action = "Edit", controller = "Store" });
|
||||
var entry2 = CreateGenerationEntry("api2/{controller}", new { action = "Edit", controller = "Store" });
|
||||
|
||||
var next = new StubRouter();
|
||||
|
||||
var callCount = 0;
|
||||
next.GenerationDelegate = (VirtualPathContext c) =>
|
||||
{
|
||||
// Reject entry 1.
|
||||
callCount++;
|
||||
return !c.ProvidedValues.Contains(new KeyValuePair<string, object>(
|
||||
TreeRouter.RouteGroupKey,
|
||||
entry1.RouteGroup));
|
||||
};
|
||||
|
||||
var route = CreateAttributeRoute(next, entry1, entry2);
|
||||
|
||||
var context = CreateVirtualPathContext(new { action = "Edit", controller = "Store" });
|
||||
|
||||
// Act
|
||||
var pathData = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(pathData);
|
||||
Assert.Equal(new PathString("/api2/Store"), pathData.VirtualPath);
|
||||
Assert.Same(route, pathData.Router);
|
||||
Assert.Empty(pathData.DataTokens);
|
||||
|
||||
Assert.Equal(2, callCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TreeRouter_GenerateLink_ToArea()
|
||||
{
|
||||
|
|
@ -1509,7 +1271,7 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
// values
|
||||
new object[]
|
||||
{
|
||||
"Test/{val1}/{val2}.{val3?}",
|
||||
"Test/{val1}/{val2}.{val3?}",
|
||||
new {val1 = "someval1", val2 = "someval2", val3 = "someval3a"},
|
||||
new {val3 = "someval3v"},
|
||||
"/Test/someval1/someval2.someval3v",
|
||||
|
|
@ -1527,18 +1289,18 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
null,
|
||||
new {val1 = "someval1", val2 = "someval2" },
|
||||
"/Test/someval1/someval2",
|
||||
},
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
"Test/{val1}.{val2}.{val3}.{val4?}",
|
||||
new {val1 = "someval1", val2 = "someval2" },
|
||||
new {val1 = "someval1", val2 = "someval2" },
|
||||
new {val4 = "someval4", val3 = "someval3" },
|
||||
"/Test/someval1.someval2.someval3.someval4",
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
"Test/{val1}.{val2}.{val3}.{val4?}",
|
||||
new {val1 = "someval1", val2 = "someval2" },
|
||||
new {val1 = "someval1", val2 = "someval2" },
|
||||
new {val3 = "someval3" },
|
||||
"/Test/someval1.someval2.someval3",
|
||||
},
|
||||
|
|
@ -1931,6 +1693,13 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
Enumerable.Empty<TreeRouteLinkGenerationEntry>());
|
||||
}
|
||||
|
||||
private static TreeRouter CreateAttributeRoute(
|
||||
IEnumerable<TreeRouteMatchingEntry> matchingEntries,
|
||||
IEnumerable<TreeRouteLinkGenerationEntry> generationEntries)
|
||||
{
|
||||
return CreateAttributeRoute(new StubRouter(), matchingEntries, generationEntries);
|
||||
}
|
||||
|
||||
private static TreeRouter CreateAttributeRoute(
|
||||
IRouter next,
|
||||
IEnumerable<TreeRouteMatchingEntry> matchingEntries,
|
||||
|
|
@ -1952,13 +1721,13 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
}
|
||||
|
||||
private static TreeRouter CreateAttributeRoute(
|
||||
Action<VirtualPathContext> virtualPathCallback,
|
||||
string firstTemplate,
|
||||
string secondTemplate)
|
||||
{
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(n => n.GetVirtualPath(It.IsAny<VirtualPathContext>())).Callback<VirtualPathContext>(virtualPathCallback)
|
||||
.Returns((VirtualPathData)null);
|
||||
next
|
||||
.Setup(n => n.GetVirtualPath(It.IsAny<VirtualPathContext>()))
|
||||
.Returns((VirtualPathData)null);
|
||||
|
||||
var matchingRoutes = Enumerable.Empty<TreeRouteMatchingEntry>();
|
||||
var firstEntry = CreateGenerationEntry(firstTemplate, requiredValues: null);
|
||||
|
|
@ -2014,8 +1783,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
{
|
||||
public VirtualPathContext GenerationContext { get; set; }
|
||||
|
||||
public Func<VirtualPathContext, bool> GenerationDelegate { get; set; }
|
||||
|
||||
public RouteContext MatchingContext { get; set; }
|
||||
|
||||
public Func<RouteContext, bool> MatchingDelegate { get; set; }
|
||||
|
|
@ -2023,16 +1790,6 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
public VirtualPathData GetVirtualPath(VirtualPathContext context)
|
||||
{
|
||||
GenerationContext = context;
|
||||
|
||||
if (GenerationDelegate == null)
|
||||
{
|
||||
context.IsBound = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.IsBound = GenerationDelegate(context);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue