Make TreeRouter restore RouteData snapshots consistently. Fixes #394.
This commit is contained in:
parent
a721565134
commit
8c58086030
|
|
@ -192,13 +192,14 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
{
|
{
|
||||||
var entry = item.Entry;
|
var entry = item.Entry;
|
||||||
var matcher = item.TemplateMatcher;
|
var matcher = item.TemplateMatcher;
|
||||||
if (!matcher.TryMatch(context.HttpContext.Request.Path, context.RouteData.Values))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (!matcher.TryMatch(context.HttpContext.Request.Path, context.RouteData.Values))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!RouteConstraintMatcher.Match(
|
if (!RouteConstraintMatcher.Match(
|
||||||
entry.Constraints,
|
entry.Constraints,
|
||||||
context.RouteData.Values,
|
context.RouteData.Values,
|
||||||
|
|
|
||||||
|
|
@ -1844,6 +1844,44 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
Assert.Equal(next.Object.GetType(), nestedRouters[0].GetType());
|
Assert.Equal(next.Object.GetType(), nestedRouters[0].GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TreeRouter_SnapshotsRouteData_ResetsBeforeMatchingEachRouteEntry()
|
||||||
|
{
|
||||||
|
// This test replicates a scenario raised as issue https://github.com/aspnet/Routing/issues/394
|
||||||
|
// The RouteValueDictionary entries populated while matching route entries should not be left
|
||||||
|
// in place if the route entry turns out not to match, because that would leak unwanted state
|
||||||
|
// to subsequent route entries and might cause "An element with the key ... already exists"
|
||||||
|
// exceptions.
|
||||||
|
|
||||||
|
// Arrange
|
||||||
|
RouteValueDictionary nestedValues = null;
|
||||||
|
var next = new Mock<IRouter>();
|
||||||
|
next
|
||||||
|
.Setup(r => r.RouteAsync(It.IsAny<RouteContext>()))
|
||||||
|
.Callback<RouteContext>(c =>
|
||||||
|
{
|
||||||
|
nestedValues = new RouteValueDictionary(c.RouteData.Values);
|
||||||
|
c.Handler = NullHandler;
|
||||||
|
})
|
||||||
|
.Returns(Task.CompletedTask);
|
||||||
|
|
||||||
|
var builder = CreateBuilder();
|
||||||
|
MapInboundEntry(builder, "cat_{category1}/prod1_{product}"); // Matches on first segment but not on second
|
||||||
|
MapInboundEntry(builder, "cat_{category2}/prod2_{product}", handler: next.Object);
|
||||||
|
var route = builder.Build();
|
||||||
|
|
||||||
|
var context = CreateRouteContext("/cat_examplecategory/prod2_exampleproduct");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await route.RouteAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(nestedValues);
|
||||||
|
Assert.Equal("examplecategory", nestedValues["category2"]);
|
||||||
|
Assert.Equal("exampleproduct", nestedValues["product"]);
|
||||||
|
Assert.DoesNotContain(nestedValues, kvp => kvp.Key == "category1");
|
||||||
|
}
|
||||||
|
|
||||||
private static RouteContext CreateRouteContext(string requestPath)
|
private static RouteContext CreateRouteContext(string requestPath)
|
||||||
{
|
{
|
||||||
var request = new Mock<HttpRequest>(MockBehavior.Strict);
|
var request = new Mock<HttpRequest>(MockBehavior.Strict);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue