React to #154 (Routing - adding data token to GetVirtualPath)

This commit is contained in:
ianhong 2015-03-13 14:51:59 -07:00
parent 0f1292abf6
commit 27bdec40a6
8 changed files with 180 additions and 84 deletions

View File

@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Mvc
{ {
private ILogger _logger; private ILogger _logger;
public string GetVirtualPath([NotNull] VirtualPathContext context) public VirtualPathData GetVirtualPath([NotNull] VirtualPathContext context)
{ {
// The contract of this method is to check that the values coming in from the route are valid; // The contract of this method is to check that the values coming in from the route are valid;
// that they match an existing action, setting IsBound = true if the values are OK. // that they match an existing action, setting IsBound = true if the values are OK.

View File

@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc.Routing
} }
/// <inheritdoc /> /// <inheritdoc />
public string GetVirtualPath(VirtualPathContext context) public VirtualPathData GetVirtualPath(VirtualPathContext context)
{ {
var route = GetInnerRoute(); var route = GetInnerRoute();
return route.GetVirtualPath(context); return route.GetVirtualPath(context);

View File

@ -94,7 +94,7 @@ namespace Microsoft.AspNet.Mvc.Routing
} }
/// <summary> /// <summary>
/// Gets the version of this route. This corresponds to the value of /// Gets the version of this route. This corresponds to the value of
/// <see cref="ActionDescriptorsCollection.Version"/> when this route was created. /// <see cref="ActionDescriptorsCollection.Version"/> when this route was created.
/// </summary> /// </summary>
public int Version { get; } public int Version { get; }
@ -142,7 +142,7 @@ namespace Microsoft.AspNet.Mvc.Routing
} }
/// <inheritdoc /> /// <inheritdoc />
public string GetVirtualPath([NotNull] VirtualPathContext context) public VirtualPathData GetVirtualPath([NotNull] VirtualPathContext context)
{ {
// If it's a named route we will try to generate a link directly and // If it's a named route we will try to generate a link directly and
// if we can't, we will not try to generate it using an unnamed route. // if we can't, we will not try to generate it using an unnamed route.
@ -157,7 +157,7 @@ namespace Microsoft.AspNet.Mvc.Routing
foreach (var match in matches) foreach (var match in matches)
{ {
var path = GenerateLink(context, match.Entry); var path = GenerateVirtualPath(context, match.Entry);
if (path != null) if (path != null)
{ {
context.IsBound = true; context.IsBound = true;
@ -168,12 +168,12 @@ namespace Microsoft.AspNet.Mvc.Routing
return null; return null;
} }
private string GetVirtualPathForNamedRoute(VirtualPathContext context) private VirtualPathData GetVirtualPathForNamedRoute(VirtualPathContext context)
{ {
AttributeRouteLinkGenerationEntry entry; AttributeRouteLinkGenerationEntry entry;
if (_namedEntries.TryGetValue(context.RouteName, out entry)) if (_namedEntries.TryGetValue(context.RouteName, out entry))
{ {
var path = GenerateLink(context, entry); var path = GenerateVirtualPath(context, entry);
if (path != null) if (path != null)
{ {
context.IsBound = true; context.IsBound = true;
@ -183,7 +183,7 @@ namespace Microsoft.AspNet.Mvc.Routing
return null; return null;
} }
private string GenerateLink(VirtualPathContext context, AttributeRouteLinkGenerationEntry entry) private VirtualPathData GenerateVirtualPath(VirtualPathContext context, AttributeRouteLinkGenerationEntry entry)
{ {
// In attribute the context includes the values that are used to select this entry - typically // In attribute the context includes the values that are used to select this entry - typically
// these will be the standard 'action', 'controller' and maybe 'area' tokens. However, we don't // these will be the standard 'action', 'controller' and maybe 'area' tokens. However, we don't
@ -247,12 +247,12 @@ namespace Microsoft.AspNet.Mvc.Routing
ProvidedValues = providedValues, ProvidedValues = providedValues,
}; };
var path = _next.GetVirtualPath(childContext); var pathData = _next.GetVirtualPath(childContext);
if (path != null) if (pathData != null)
{ {
// If path is non-null then the target router short-circuited, we don't expect this // If path is non-null then the target router short-circuited, we don't expect this
// in typical MVC scenarios. // in typical MVC scenarios.
return path; return pathData;
} }
else if (!childContext.IsBound) else if (!childContext.IsBound)
{ {
@ -260,8 +260,13 @@ namespace Microsoft.AspNet.Mvc.Routing
return null; return null;
} }
path = entry.Binder.BindValues(bindingResult.AcceptedValues); var path = entry.Binder.BindValues(bindingResult.AcceptedValues);
return path; if (path == null)
{
return null;
}
return new VirtualPathData(this, path);
} }
private bool ContextHasSameValue(VirtualPathContext context, string key, object value) private bool ContextHasSameValue(VirtualPathContext context, string key, object value)

View File

@ -99,12 +99,16 @@ namespace Microsoft.AspNet.Mvc
protected virtual string GeneratePathFromRoute(string routeName, IDictionary<string, object> values) protected virtual string GeneratePathFromRoute(string routeName, IDictionary<string, object> values)
{ {
var context = new VirtualPathContext(_httpContext, _ambientValues, values, routeName); var context = new VirtualPathContext(_httpContext, _ambientValues, values, routeName);
var path = _router.GetVirtualPath(context); var pathData = _router.GetVirtualPath(context);
if (path == null) if (pathData == null)
{ {
return null; return null;
} }
// VirtualPathData.VirtualPath returns string.Empty for null.
Debug.Assert(pathData.VirtualPath != null);
var path = pathData.VirtualPath;
// See Routing Issue#31 // See Routing Issue#31
if (path.Length > 0 && path[0] != '/') if (path.Length > 0 && path[0] != '/')
{ {

View File

@ -529,7 +529,7 @@ namespace Microsoft.AspNet.Mvc
handler handler
.Setup(router => router.GetVirtualPath(It.IsAny<VirtualPathContext>())) .Setup(router => router.GetVirtualPath(It.IsAny<VirtualPathContext>()))
.Callback<VirtualPathContext>(context => context.IsBound = isBound) .Callback<VirtualPathContext>(context => context.IsBound = isBound)
.Returns((string)null); .Returns((VirtualPathData)null);
builder.DefaultHandler = handler.Object; builder.DefaultHandler = handler.Object;
return builder; return builder;

View File

@ -202,8 +202,9 @@ namespace Microsoft.AspNet.Mvc.Routing
[InlineData("template/{parameter:int}", "/template/5", true)] [InlineData("template/{parameter:int}", "/template/5", true)]
[InlineData("template/{parameter:int?}", "/template/5", true)] [InlineData("template/{parameter:int?}", "/template/5", true)]
[InlineData("template/{parameter:int?}", "/template", true)] [InlineData("template/{parameter:int?}", "/template", true)]
[InlineData("template/{parameter:int?}", "/template/qwer", false)] [InlineData("template/{parameter:int?}", "/template/qwer", false)]
public async Task AttributeRoute_WithOptionalInlineConstraint(string template, string request, bool expectedResult) public async Task AttributeRoute_WithOptionalInlineConstraint(
string template, string request, bool expectedResult)
{ {
// Arrange // Arrange
var expectedRouteGroup = string.Format("{0}&&{1}", 0, template); var expectedRouteGroup = string.Format("{0}&&{1}", 0, template);
@ -245,7 +246,7 @@ namespace Microsoft.AspNet.Mvc.Routing
} }
} }
[Theory] [Theory]
[InlineData("moo/{p1}.{p2?}", "/moo/foo.bar", "foo", "bar", null)] [InlineData("moo/{p1}.{p2?}", "/moo/foo.bar", "foo", "bar", null)]
[InlineData("moo/{p1?}", "/moo/foo", "foo", null, null)] [InlineData("moo/{p1?}", "/moo/foo", "foo", null, null)]
[InlineData("moo/{p1?}", "/moo", null, null, null)] [InlineData("moo/{p1?}", "/moo", null, null, null)]
@ -255,7 +256,7 @@ namespace Microsoft.AspNet.Mvc.Routing
[InlineData("moo/{p1}.{p2}", "/moo/foo.bar", "foo", "bar", null)] [InlineData("moo/{p1}.{p2}", "/moo/foo.bar", "foo", "bar", null)]
[InlineData("moo/foo.{p1}.{p2?}", "/moo/foo.moo.bar", "moo", "bar", null)] [InlineData("moo/foo.{p1}.{p2?}", "/moo/foo.moo.bar", "moo", "bar", null)]
[InlineData("moo/foo.{p1}.{p2?}", "/moo/foo.moo", "moo", null, null)] [InlineData("moo/foo.{p1}.{p2?}", "/moo/foo.moo", "moo", null, null)]
[InlineData("moo/.{p2?}", "/moo/.foo", null, "foo", null)] [InlineData("moo/.{p2?}", "/moo/.foo", null, "foo", null)]
[InlineData("moo/{p1}.{p2?}", "/moo/....", "..", ".", null)] [InlineData("moo/{p1}.{p2?}", "/moo/....", "..", ".", null)]
[InlineData("moo/{p1}.{p2?}", "/moo/.bar", ".bar", null, null)] [InlineData("moo/{p1}.{p2?}", "/moo/.bar", ".bar", null, null)]
[InlineData("moo/{p1}.{p2}.{p3?}", "/moo/foo.moo.bar", "foo", "moo", "bar")] [InlineData("moo/{p1}.{p2}.{p3?}", "/moo/foo.moo.bar", "foo", "moo", "bar")]
@ -265,8 +266,8 @@ namespace Microsoft.AspNet.Mvc.Routing
[InlineData("{p1}.{p2?}/{p3}", "/foo/bar", "foo", null, "bar")] [InlineData("{p1}.{p2?}/{p3}", "/foo/bar", "foo", null, "bar")]
[InlineData("{p1}.{p2?}/{p3}", "/.foo/bar", ".foo", null, "bar")] [InlineData("{p1}.{p2?}/{p3}", "/.foo/bar", ".foo", null, "bar")]
public async Task AttributeRoute_WithOptionalCompositeParameter_Valid( public async Task AttributeRoute_WithOptionalCompositeParameter_Valid(
string template, string template,
string request, string request,
string p1, string p1,
string p2, string p2,
string p3) string p3)
@ -296,7 +297,7 @@ namespace Microsoft.AspNet.Mvc.Routing
// Act // Act
await route.RouteAsync(context); await route.RouteAsync(context);
// Assert // Assert
Assert.True(context.IsHandled); Assert.True(context.IsHandled);
if (p1 != null) if (p1 != null)
{ {
@ -355,8 +356,8 @@ namespace Microsoft.AspNet.Mvc.Routing
// Act // Act
await route.RouteAsync(context); await route.RouteAsync(context);
// Assert // Assert
Assert.False(context.IsHandled); Assert.False(context.IsHandled);
} }
[Theory] [Theory]
@ -383,7 +384,7 @@ namespace Microsoft.AspNet.Mvc.Routing
selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey]; selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey];
ctx.IsBound = true; ctx.IsBound = true;
}) })
.Returns((string)null); .Returns((VirtualPathData)null);
var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>(); var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>();
@ -399,11 +400,14 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(values: null, ambientValues: new { parameter = 5 }); var context = CreateVirtualPathContext(values: null, ambientValues: new { parameter = 5 });
// Act // Act
string result = route.GetVirtualPath(context); var result = route.GetVirtualPath(context);
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal("template/5", result); Assert.Equal("template/5", result.VirtualPath);
Assert.Same(route, result.Router);
Assert.Empty(result.DataTokens);
Assert.Equal(expectedGroup, selectedGroup); Assert.Equal(expectedGroup, selectedGroup);
} }
@ -417,7 +421,8 @@ namespace Microsoft.AspNet.Mvc.Routing
[InlineData("template/{parameter:int:range(1,20)?}", "template", null)] [InlineData("template/{parameter:int:range(1,20)?}", "template", null)]
[InlineData("template/{parameter:int:range(1,20)?}", "template/5", 5)] [InlineData("template/{parameter:int:range(1,20)?}", "template/5", 5)]
[InlineData("template/{parameter:int:range(1,20)?}", null, 21)] [InlineData("template/{parameter:int:range(1,20)?}", null, 21)]
public void AttributeRoute_GenerateLink_OptionalInlineParameter(string template, string expectedResult, object parameter) public void AttributeRoute_GenerateLink_OptionalInlineParameter
(string template, string expectedPath, object parameter)
{ {
// Arrange // Arrange
var expectedGroup = CreateRouteGroup(0, template); var expectedGroup = CreateRouteGroup(0, template);
@ -430,7 +435,7 @@ namespace Microsoft.AspNet.Mvc.Routing
selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey]; selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey];
ctx.IsBound = true; ctx.IsBound = true;
}) })
.Returns((string)null); .Returns((VirtualPathData)null);
var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>(); var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>();
@ -451,10 +456,20 @@ namespace Microsoft.AspNet.Mvc.Routing
} }
// Act // Act
string result = route.GetVirtualPath(context); var result = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal(expectedResult, result); if (expectedPath == null)
{
Assert.Null(result);
}
else
{
Assert.NotNull(result);
Assert.Equal(expectedPath, result.VirtualPath);
Assert.Same(route, result.Router);
Assert.Empty(result.DataTokens);
}
} }
[Theory] [Theory]
@ -480,7 +495,7 @@ namespace Microsoft.AspNet.Mvc.Routing
firstRouteGroupSelected = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey]; firstRouteGroupSelected = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey];
ctx.IsBound = true; ctx.IsBound = true;
}) })
.Returns((string)null); .Returns((VirtualPathData)null);
var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>(); var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>();
@ -497,11 +512,14 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(null, ambientValues: new { parameter = 5 }); var context = CreateVirtualPathContext(null, ambientValues: new { parameter = 5 });
// Act // Act
string result = route.GetVirtualPath(context); var result = route.GetVirtualPath(context);
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal("template/5", result); Assert.Equal("template/5", result.VirtualPath);
Assert.Same(route, result.Router);
Assert.Empty(result.DataTokens);
Assert.Equal(selectedGroup, firstRouteGroupSelected); Assert.Equal(selectedGroup, firstRouteGroupSelected);
} }
@ -523,7 +541,7 @@ namespace Microsoft.AspNet.Mvc.Routing
selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey]; selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey];
ctx.IsBound = true; ctx.IsBound = true;
}) })
.Returns((string)null); .Returns((VirtualPathData)null);
var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>(); var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>();
@ -539,11 +557,14 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(values: null, ambientValues: new { first = 5, second = 5 }); var context = CreateVirtualPathContext(values: null, ambientValues: new { first = 5, second = 5 });
// Act // Act
string result = route.GetVirtualPath(context); var result = route.GetVirtualPath(context);
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal("template/5", result); Assert.Equal("template/5", result.VirtualPath);
Assert.Same(route, result.Router);
Assert.Empty(result.DataTokens);
Assert.Equal(expectedGroup, selectedGroup); Assert.Equal(expectedGroup, selectedGroup);
} }
@ -565,7 +586,7 @@ namespace Microsoft.AspNet.Mvc.Routing
selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey]; selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey];
ctx.IsBound = true; ctx.IsBound = true;
}) })
.Returns((string)null); .Returns((VirtualPathData)null);
var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>(); var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>();
@ -581,11 +602,14 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(values: null, ambientValues: new { first = 5, second = 5 }); var context = CreateVirtualPathContext(values: null, ambientValues: new { first = 5, second = 5 });
// Act // Act
string result = route.GetVirtualPath(context); var result = route.GetVirtualPath(context);
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal("first/5", result); Assert.Equal("first/5", result.VirtualPath);
Assert.Same(route, result.Router);
Assert.Empty(result.DataTokens);
Assert.Equal(expectedGroup, selectedGroup); Assert.Equal(expectedGroup, selectedGroup);
} }
@ -696,7 +720,8 @@ namespace Microsoft.AspNet.Mvc.Routing
{ {
vpc.IsBound = true; vpc.IsBound = true;
selectedGroup = (string)vpc.ProvidedValues[AttributeRouting.RouteGroupKey]; selectedGroup = (string)vpc.ProvidedValues[AttributeRouting.RouteGroupKey];
}); })
.Returns((VirtualPathData)null);
var matchingEntries = Enumerable.Empty<AttributeRouteMatchingEntry>(); var matchingEntries = Enumerable.Empty<AttributeRouteMatchingEntry>();
@ -711,8 +736,11 @@ namespace Microsoft.AspNet.Mvc.Routing
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal(expectedLink, result.VirtualPath);
Assert.Same(route, result.Router);
Assert.Empty(result.DataTokens);
Assert.Equal(expectedGroup, selectedGroup); Assert.Equal(expectedGroup, selectedGroup);
Assert.Equal(expectedLink, result);
} }
[Fact] [Fact]
@ -726,7 +754,8 @@ namespace Microsoft.AspNet.Mvc.Routing
{ {
vpc.IsBound = true; vpc.IsBound = true;
selectedGroup = (string)vpc.ProvidedValues[AttributeRouting.RouteGroupKey]; selectedGroup = (string)vpc.ProvidedValues[AttributeRouting.RouteGroupKey];
}); })
.Returns((VirtualPathData)null);
var namedEntry = CreateGenerationEntry("named", requiredValues: null, order: 1, name: "NamedRoute"); var namedEntry = CreateGenerationEntry("named", requiredValues: null, order: 1, name: "NamedRoute");
var unnamedEntry = CreateGenerationEntry("unnamed", requiredValues: null, order: 0); var unnamedEntry = CreateGenerationEntry("unnamed", requiredValues: null, order: 0);
@ -746,8 +775,11 @@ namespace Microsoft.AspNet.Mvc.Routing
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal("named", result.VirtualPath);
Assert.Same(route, result.Router);
Assert.Empty(result.DataTokens);
Assert.Equal("1&named", selectedGroup); Assert.Equal("1&named", selectedGroup);
Assert.Equal("named", result);
} }
[Fact] [Fact]
@ -842,7 +874,8 @@ namespace Microsoft.AspNet.Mvc.Routing
{ {
vpc.IsBound = true; vpc.IsBound = true;
selectedGroup = (string)vpc.ProvidedValues[AttributeRouting.RouteGroupKey]; selectedGroup = (string)vpc.ProvidedValues[AttributeRouting.RouteGroupKey];
}); })
.Returns((VirtualPathData)null);
var namedEntry = CreateGenerationEntry(template, requiredValues: null, order: 1, name: "NamedRoute"); var namedEntry = CreateGenerationEntry(template, requiredValues: null, order: 1, name: "NamedRoute");
@ -866,8 +899,11 @@ namespace Microsoft.AspNet.Mvc.Routing
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal("template/5", result.VirtualPath);
Assert.Same(route, result.Router);
Assert.Empty(result.DataTokens);
Assert.Equal(string.Format("1&{0}", template), selectedGroup); Assert.Equal(string.Format("1&{0}", template), selectedGroup);
Assert.Equal("template/5", result);
} }
[Fact] [Fact]
@ -942,10 +978,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { }); var context = CreateVirtualPathContext(new { });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api/Store", path); Assert.NotNull(pathData);
Assert.Equal("api/Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -958,10 +997,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { action = "Index", controller = "Store" }); var context = CreateVirtualPathContext(new { action = "Index", controller = "Store" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api/Store", path); Assert.NotNull(pathData);
Assert.Equal("api/Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -990,10 +1032,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { }, new { action = "Index", controller = "Store" }); var context = CreateVirtualPathContext(new { }, new { action = "Index", controller = "Store" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api/Store", path); Assert.NotNull(pathData);
Assert.Equal("api/Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1006,10 +1051,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { action = "Index", controller = "Store" }); var context = CreateVirtualPathContext(new { action = "Index", controller = "Store" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api/Store/Index", path); Assert.NotNull(pathData);
Assert.Equal("api/Store/Index", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1036,10 +1084,14 @@ namespace Microsoft.AspNet.Mvc.Routing
new { area = "AwesomeCo" }); new { area = "AwesomeCo" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api/AwesomeCo/dosomething/Store/Index", path); Assert.NotNull(pathData);
Assert.Equal("api/AwesomeCo/dosomething/Store/Index", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
Assert.Equal(expectedValues, next.GenerationContext.ProvidedValues); Assert.Equal(expectedValues, next.GenerationContext.ProvidedValues);
} }
@ -1053,10 +1105,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { action = "Index", controller = "Store" }); var context = CreateVirtualPathContext(new { action = "Index", controller = "Store" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api/Store", path); Assert.NotNull(pathData);
Assert.Equal("api/Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1078,10 +1133,14 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { action = "Index", controller = "Store", id = 5 }); var context = CreateVirtualPathContext(new { action = "Index", controller = "Store", id = 5 });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api/Store/Index/5", path); Assert.NotNull(pathData);
Assert.Equal("api/Store/Index/5", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
Assert.Equal(expectedValues, next.GenerationContext.ProvidedValues); Assert.Equal(expectedValues, next.GenerationContext.ProvidedValues);
} }
@ -1118,10 +1177,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { action = "Index" }, new { controller = "Store" }); var context = CreateVirtualPathContext(new { action = "Index" }, new { controller = "Store" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api/Store", path); Assert.NotNull(pathData);
Assert.Equal("api/Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1134,10 +1196,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { action = "Index", id = 5 }, new { controller = "Store" }); var context = CreateVirtualPathContext(new { action = "Index", id = 5 }, new { controller = "Store" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api/Store?id=5", path); Assert.NotNull(pathData);
Assert.Equal("api/Store?id=5", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1175,10 +1240,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { action = "Index", controller = "Blog" }); var context = CreateVirtualPathContext(new { action = "Index", controller = "Blog" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api2/Blog", path); Assert.NotNull(pathData);
Assert.Equal("api2/Blog", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1205,10 +1273,14 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { action = "Edit", controller = "Store" }); var context = CreateVirtualPathContext(new { action = "Edit", controller = "Store" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("api2/Store", path); Assert.NotNull(pathData);
Assert.Equal("api2/Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
Assert.Equal(2, callCount); Assert.Equal(2, callCount);
} }
@ -1229,10 +1301,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { area = "Help", action = "Edit", controller = "Store" }); var context = CreateVirtualPathContext(new { area = "Help", action = "Edit", controller = "Store" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("Help/Store", path); Assert.NotNull(pathData);
Assert.Equal("Help/Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1252,10 +1327,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(new { area = "Help", action = "Edit", controller = "Store" }); var context = CreateVirtualPathContext(new { area = "Help", action = "Edit", controller = "Store" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("Help/Store", path); Assert.NotNull(pathData);
Assert.Equal("Help/Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1277,10 +1355,13 @@ namespace Microsoft.AspNet.Mvc.Routing
ambientValues: new { area = "Help" }); ambientValues: new { area = "Help" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("Help/Store", path); Assert.NotNull(pathData);
Assert.Equal("Help/Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1302,10 +1383,13 @@ namespace Microsoft.AspNet.Mvc.Routing
ambientValues: new { area = "Blog" }); ambientValues: new { area = "Blog" });
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal("Store", path); Assert.NotNull(pathData);
Assert.Equal("Store", pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
public static IEnumerable<object[]> OptionalParamValues public static IEnumerable<object[]> OptionalParamValues
@ -1392,10 +1476,13 @@ namespace Microsoft.AspNet.Mvc.Routing
var context = CreateVirtualPathContext(values, ambientValues); var context = CreateVirtualPathContext(values, ambientValues);
// Act // Act
var path = route.GetVirtualPath(context); var pathData = route.GetVirtualPath(context);
// Assert // Assert
Assert.Equal(expected, path); Assert.NotNull(pathData);
Assert.Equal(expected, pathData.VirtualPath);
Assert.Same(route, pathData.Router);
Assert.Empty(pathData.DataTokens);
} }
[Fact] [Fact]
@ -1725,7 +1812,7 @@ namespace Microsoft.AspNet.Mvc.Routing
public Func<RouteContext, bool> MatchingDelegate { get; set; } public Func<RouteContext, bool> MatchingDelegate { get; set; }
public string GetVirtualPath(VirtualPathContext context) public VirtualPathData GetVirtualPath(VirtualPathContext context)
{ {
GenerationContext = context; GenerationContext = context;

View File

@ -923,7 +923,7 @@ namespace Microsoft.AspNet.Mvc
private static IRouter GetRouter( private static IRouter GetRouter(
IServiceProvider services, IServiceProvider services,
string mockRouteName, string mockRouteName,
string mockTemplateValue) string mockTemplateValue)
{ {
@ -949,7 +949,7 @@ namespace Microsoft.AspNet.Mvc
mockHttpRoute mockHttpRoute
.Setup(mock => mock.GetVirtualPath(It.Is<VirtualPathContext>(c => string.Equals(c.RouteName, mockRouteName)))) .Setup(mock => mock.GetVirtualPath(It.Is<VirtualPathContext>(c => string.Equals(c.RouteName, mockRouteName))))
.Callback<VirtualPathContext>(c => c.IsBound = true) .Callback<VirtualPathContext>(c => c.IsBound = true)
.Returns(mockTemplateValue); .Returns(new VirtualPathData(mockHttpRoute.Object, mockTemplateValue));
routeBuilder.Routes.Add(mockHttpRoute.Object); routeBuilder.Routes.Add(mockHttpRoute.Object);
return routeBuilder.Build(); return routeBuilder.Build();

View File

@ -24,7 +24,7 @@ namespace CustomRouteWebSite
_next = next; _next = next;
} }
public string GetVirtualPath(VirtualPathContext context) public VirtualPathData GetVirtualPath(VirtualPathContext context)
{ {
// We just want to act as a pass-through for link generation // We just want to act as a pass-through for link generation
return _next.GetVirtualPath(context); return _next.GetVirtualPath(context);