621 lines
20 KiB
C#
621 lines
20 KiB
C#
// 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;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Microsoft.AspNetCore.Routing.Constraints;
|
|
using Microsoft.AspNetCore.Routing.EndpointConstraints;
|
|
using Microsoft.AspNetCore.Routing.Patterns;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNetCore.Routing.Matchers
|
|
{
|
|
public class DfaMatcherBuilderTest
|
|
{
|
|
[Fact]
|
|
public void BuildDfaTree_SingleEndpoint_Empty()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint = CreateEndpoint("/");
|
|
builder.AddEndpoint(endpoint);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Same(endpoint, Assert.Single(root.Matches).Endpoint);
|
|
Assert.Null(root.Parameters);
|
|
Assert.Empty(root.Literals);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildDfaTree_SingleEndpoint_Literals()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint = CreateEndpoint("a/b/c");
|
|
builder.AddEndpoint(endpoint);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Empty(root.Matches);
|
|
Assert.Null(root.Parameters);
|
|
|
|
var next = Assert.Single(root.Literals);
|
|
Assert.Equal("a", next.Key);
|
|
|
|
var a = next.Value;
|
|
Assert.Empty(a.Matches);
|
|
Assert.Null(a.Parameters);
|
|
|
|
next = Assert.Single(a.Literals);
|
|
Assert.Equal("b", next.Key);
|
|
|
|
var b = next.Value;
|
|
Assert.Empty(b.Matches);
|
|
Assert.Null(b.Parameters);
|
|
|
|
next = Assert.Single(b.Literals);
|
|
Assert.Equal("c", next.Key);
|
|
|
|
var c = next.Value;
|
|
Assert.Same(endpoint, Assert.Single(c.Matches).Endpoint);
|
|
Assert.Null(c.Parameters);
|
|
Assert.Empty(c.Literals);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildDfaTree_SingleEndpoint_Parameters()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint = CreateEndpoint("{a}/{b}/{c}");
|
|
builder.AddEndpoint(endpoint);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Empty(root.Matches);
|
|
Assert.Empty(root.Literals);
|
|
|
|
var a = root.Parameters;
|
|
Assert.Empty(a.Matches);
|
|
Assert.Empty(a.Literals);
|
|
|
|
var b = a.Parameters;
|
|
Assert.Empty(b.Matches);
|
|
Assert.Empty(b.Literals);
|
|
|
|
var c = b.Parameters;
|
|
Assert.Same(endpoint, Assert.Single(c.Matches).Endpoint);
|
|
Assert.Null(c.Parameters);
|
|
Assert.Empty(c.Literals);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildDfaTree_SingleEndpoint_CatchAll()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint = CreateEndpoint("{a}/{*b}");
|
|
builder.AddEndpoint(endpoint);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Empty(root.Matches);
|
|
Assert.Empty(root.Literals);
|
|
|
|
var a = root.Parameters;
|
|
|
|
// The catch all can match a path like '/a'
|
|
Assert.Same(endpoint, Assert.Single(a.Matches).Endpoint);
|
|
Assert.Empty(a.Literals);
|
|
Assert.Null(a.Parameters);
|
|
|
|
// Catch-all nodes include an extra transition that loops to process
|
|
// extra segments.
|
|
var catchAll = a.CatchAll;
|
|
Assert.Same(endpoint, Assert.Single(catchAll.Matches).Endpoint);
|
|
Assert.Empty(catchAll.Literals);
|
|
Assert.Same(catchAll, catchAll.Parameters);
|
|
Assert.Same(catchAll, catchAll.CatchAll);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildDfaTree_SingleEndpoint_CatchAllAtRoot()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint = CreateEndpoint("{*a}");
|
|
builder.AddEndpoint(endpoint);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Same(endpoint, Assert.Single(root.Matches).Endpoint);
|
|
Assert.Empty(root.Literals);
|
|
|
|
// Catch-all nodes include an extra transition that loops to process
|
|
// extra segments.
|
|
var catchAll = root.CatchAll;
|
|
Assert.Same(endpoint, Assert.Single(catchAll.Matches).Endpoint);
|
|
Assert.Empty(catchAll.Literals);
|
|
Assert.Same(catchAll, catchAll.Parameters);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildDfaTree_MultipleEndpoint_LiteralAndLiteral()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint1 = CreateEndpoint("a/b1/c");
|
|
builder.AddEndpoint(endpoint1);
|
|
|
|
var endpoint2 = CreateEndpoint("a/b2/c");
|
|
builder.AddEndpoint(endpoint2);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Empty(root.Matches);
|
|
Assert.Null(root.Parameters);
|
|
|
|
var next = Assert.Single(root.Literals);
|
|
Assert.Equal("a", next.Key);
|
|
|
|
var a = next.Value;
|
|
Assert.Empty(a.Matches);
|
|
|
|
Assert.Equal(2, a.Literals.Count);
|
|
|
|
var b1 = a.Literals["b1"];
|
|
Assert.Empty(b1.Matches);
|
|
Assert.Null(b1.Parameters);
|
|
|
|
next = Assert.Single(b1.Literals);
|
|
Assert.Equal("c", next.Key);
|
|
|
|
var c1 = next.Value;
|
|
Assert.Same(endpoint1, Assert.Single(c1.Matches).Endpoint);
|
|
Assert.Null(c1.Parameters);
|
|
Assert.Empty(c1.Literals);
|
|
|
|
var b2 = a.Literals["b2"];
|
|
Assert.Empty(b2.Matches);
|
|
Assert.Null(b2.Parameters);
|
|
|
|
next = Assert.Single(b2.Literals);
|
|
Assert.Equal("c", next.Key);
|
|
|
|
var c2 = next.Value;
|
|
Assert.Same(endpoint2, Assert.Single(c2.Matches).Endpoint);
|
|
Assert.Null(c2.Parameters);
|
|
Assert.Empty(c2.Literals);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildDfaTree_MultipleEndpoint_LiteralAndParameter()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint1 = CreateEndpoint("a/b/c");
|
|
builder.AddEndpoint(endpoint1);
|
|
|
|
var endpoint2 = CreateEndpoint("a/{b}/c");
|
|
builder.AddEndpoint(endpoint2);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Empty(root.Matches);
|
|
Assert.Null(root.Parameters);
|
|
|
|
var next = Assert.Single(root.Literals);
|
|
Assert.Equal("a", next.Key);
|
|
|
|
var a = next.Value;
|
|
Assert.Empty(a.Matches);
|
|
|
|
next = Assert.Single(a.Literals);
|
|
Assert.Equal("b", next.Key);
|
|
|
|
var b = next.Value;
|
|
Assert.Empty(b.Matches);
|
|
Assert.Null(b.Parameters);
|
|
|
|
next = Assert.Single(b.Literals);
|
|
Assert.Equal("c", next.Key);
|
|
|
|
var c1 = next.Value;
|
|
Assert.Collection(
|
|
c1.Matches,
|
|
e => Assert.Same(endpoint1, e.Endpoint),
|
|
e => Assert.Same(endpoint2, e.Endpoint));
|
|
Assert.Null(c1.Parameters);
|
|
Assert.Empty(c1.Literals);
|
|
|
|
var b2 = a.Parameters;
|
|
Assert.Empty(b2.Matches);
|
|
Assert.Null(b2.Parameters);
|
|
|
|
next = Assert.Single(b2.Literals);
|
|
Assert.Equal("c", next.Key);
|
|
|
|
var c2 = next.Value;
|
|
Assert.Same(endpoint2, Assert.Single(c2.Matches).Endpoint);
|
|
Assert.Null(c2.Parameters);
|
|
Assert.Empty(c2.Literals);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildDfaTree_MultipleEndpoint_ParameterAndParameter()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint1 = CreateEndpoint("a/{b1}/c");
|
|
builder.AddEndpoint(endpoint1);
|
|
|
|
var endpoint2 = CreateEndpoint("a/{b2}/c");
|
|
builder.AddEndpoint(endpoint2);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Empty(root.Matches);
|
|
Assert.Null(root.Parameters);
|
|
|
|
var next = Assert.Single(root.Literals);
|
|
Assert.Equal("a", next.Key);
|
|
|
|
var a = next.Value;
|
|
Assert.Empty(a.Matches);
|
|
Assert.Empty(a.Literals);
|
|
|
|
var b = a.Parameters;
|
|
Assert.Empty(b.Matches);
|
|
Assert.Null(b.Parameters);
|
|
|
|
next = Assert.Single(b.Literals);
|
|
Assert.Equal("c", next.Key);
|
|
|
|
var c = next.Value;
|
|
Assert.Collection(
|
|
c.Matches,
|
|
e => Assert.Same(endpoint1, e.Endpoint),
|
|
e => Assert.Same(endpoint2, e.Endpoint));
|
|
Assert.Null(c.Parameters);
|
|
Assert.Empty(c.Literals);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildDfaTree_MultipleEndpoint_LiteralAndCatchAll()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint1 = CreateEndpoint("a/b/c");
|
|
builder.AddEndpoint(endpoint1);
|
|
|
|
var endpoint2 = CreateEndpoint("a/{*b}");
|
|
builder.AddEndpoint(endpoint2);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Empty(root.Matches);
|
|
Assert.Null(root.Parameters);
|
|
|
|
var next = Assert.Single(root.Literals);
|
|
Assert.Equal("a", next.Key);
|
|
|
|
var a = next.Value;
|
|
Assert.Same(endpoint2, Assert.Single(a.Matches).Endpoint);
|
|
|
|
next = Assert.Single(a.Literals);
|
|
Assert.Equal("b", next.Key);
|
|
|
|
var b1 = next.Value;
|
|
Assert.Same(endpoint2, Assert.Single(a.Matches).Endpoint);
|
|
Assert.Null(b1.Parameters);
|
|
|
|
next = Assert.Single(b1.Literals);
|
|
Assert.Equal("c", next.Key);
|
|
|
|
var c1 = next.Value;
|
|
Assert.Collection(
|
|
c1.Matches,
|
|
e => Assert.Same(endpoint1, e.Endpoint),
|
|
e => Assert.Same(endpoint2, e.Endpoint));
|
|
Assert.Null(c1.Parameters);
|
|
Assert.Empty(c1.Literals);
|
|
|
|
var catchAll = a.CatchAll;
|
|
Assert.Same(endpoint2, Assert.Single(catchAll.Matches).Endpoint);
|
|
Assert.Same(catchAll, catchAll.Parameters);
|
|
Assert.Same(catchAll, catchAll.CatchAll);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildDfaTree_MultipleEndpoint_ParameterAndCatchAll()
|
|
{
|
|
// Arrange
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
var endpoint1 = CreateEndpoint("a/{b}/c");
|
|
builder.AddEndpoint(endpoint1);
|
|
|
|
var endpoint2 = CreateEndpoint("a/{*b}");
|
|
builder.AddEndpoint(endpoint2);
|
|
|
|
// Act
|
|
var root = builder.BuildDfaTree();
|
|
|
|
// Assert
|
|
Assert.Empty(root.Matches);
|
|
Assert.Null(root.Parameters);
|
|
|
|
var next = Assert.Single(root.Literals);
|
|
Assert.Equal("a", next.Key);
|
|
|
|
var a = next.Value;
|
|
Assert.Same(endpoint2, Assert.Single(a.Matches).Endpoint);
|
|
Assert.Empty(a.Literals);
|
|
|
|
var b1 = a.Parameters;
|
|
Assert.Same(endpoint2, Assert.Single(a.Matches).Endpoint);
|
|
Assert.Null(b1.Parameters);
|
|
|
|
next = Assert.Single(b1.Literals);
|
|
Assert.Equal("c", next.Key);
|
|
|
|
var c1 = next.Value;
|
|
Assert.Collection(
|
|
c1.Matches,
|
|
e => Assert.Same(endpoint1, e.Endpoint),
|
|
e => Assert.Same(endpoint2, e.Endpoint));
|
|
Assert.Null(c1.Parameters);
|
|
Assert.Empty(c1.Literals);
|
|
|
|
var catchAll = a.CatchAll;
|
|
Assert.Same(endpoint2, Assert.Single(catchAll.Matches).Endpoint);
|
|
Assert.Same(catchAll, catchAll.Parameters);
|
|
Assert.Same(catchAll, catchAll.CatchAll);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateCandidate_JustLiterals()
|
|
{
|
|
// Arrange
|
|
var endpoint = CreateEndpoint("/a/b/c");
|
|
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
// Act
|
|
var candidate = builder.CreateCandidate(new MatcherBuilderEntry(endpoint));
|
|
|
|
// Assert
|
|
Assert.Equal(Candidate.CandidateFlags.None, candidate.Flags);
|
|
Assert.Empty(candidate.Slots);
|
|
Assert.Empty(candidate.Captures);
|
|
Assert.Equal(default, candidate.CatchAll);
|
|
Assert.Empty(candidate.ComplexSegments);
|
|
Assert.Empty(candidate.MatchProcessors);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateCandidate_Parameters()
|
|
{
|
|
// Arrange
|
|
var endpoint = CreateEndpoint("/{a}/{b}/{c}");
|
|
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
// Act
|
|
var candidate = builder.CreateCandidate(new MatcherBuilderEntry(endpoint));
|
|
|
|
// Assert
|
|
Assert.Equal(Candidate.CandidateFlags.HasCaptures, candidate.Flags);
|
|
Assert.Equal(3, candidate.Slots.Length);
|
|
Assert.Collection(
|
|
candidate.Captures,
|
|
c => Assert.Equal(("a", 0, 0), c),
|
|
c => Assert.Equal(("b", 1, 1), c),
|
|
c => Assert.Equal(("c", 2, 2), c));
|
|
Assert.Equal(default, candidate.CatchAll);
|
|
Assert.Empty(candidate.ComplexSegments);
|
|
Assert.Empty(candidate.MatchProcessors);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateCandidate_Parameters_WithDefaults()
|
|
{
|
|
// Arrange
|
|
var endpoint = CreateEndpoint("/{a=aa}/{b=bb}/{c=cc}");
|
|
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
// Act
|
|
var candidate = builder.CreateCandidate(new MatcherBuilderEntry(endpoint));
|
|
|
|
// Assert
|
|
Assert.Equal(
|
|
Candidate.CandidateFlags.HasDefaults | Candidate.CandidateFlags.HasCaptures,
|
|
candidate.Flags);
|
|
Assert.Collection(
|
|
candidate.Slots,
|
|
s => Assert.Equal(new KeyValuePair<string, object>("a", "aa"), s),
|
|
s => Assert.Equal(new KeyValuePair<string, object>("b", "bb"), s),
|
|
s => Assert.Equal(new KeyValuePair<string, object>("c", "cc"), s));
|
|
Assert.Collection(
|
|
candidate.Captures,
|
|
c => Assert.Equal(("a", 0, 0), c),
|
|
c => Assert.Equal(("b", 1, 1), c),
|
|
c => Assert.Equal(("c", 2, 2), c));
|
|
Assert.Equal(default, candidate.CatchAll);
|
|
Assert.Empty(candidate.ComplexSegments);
|
|
Assert.Empty(candidate.MatchProcessors);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateCandidate_Parameters_CatchAll()
|
|
{
|
|
// Arrange
|
|
var endpoint = CreateEndpoint("/{a}/{b}/{*c=cc}");
|
|
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
// Act
|
|
var candidate = builder.CreateCandidate(new MatcherBuilderEntry(endpoint));
|
|
|
|
// Assert
|
|
Assert.Equal(
|
|
Candidate.CandidateFlags.HasDefaults |
|
|
Candidate.CandidateFlags.HasCaptures |
|
|
Candidate.CandidateFlags.HasCatchAll,
|
|
candidate.Flags);
|
|
Assert.Collection(
|
|
candidate.Slots,
|
|
s => Assert.Equal(new KeyValuePair<string, object>("c", "cc"), s),
|
|
s => Assert.Equal(new KeyValuePair<string, object>(null, null), s),
|
|
s => Assert.Equal(new KeyValuePair<string, object>(null, null), s));
|
|
Assert.Collection(
|
|
candidate.Captures,
|
|
c => Assert.Equal(("a", 0, 1), c),
|
|
c => Assert.Equal(("b", 1, 2), c));
|
|
Assert.Equal(("c", 2, 0), candidate.CatchAll);
|
|
Assert.Empty(candidate.ComplexSegments);
|
|
Assert.Empty(candidate.MatchProcessors);
|
|
}
|
|
|
|
// Defaults are processed first, which affects the slot ordering.
|
|
[Fact]
|
|
public void CreateCandidate_Parameters_OutOfLineDefaults()
|
|
{
|
|
// Arrange
|
|
var endpoint = CreateEndpoint("/{a}/{b}/{c=cc}", new { a = "aa", d = "dd", });
|
|
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
// Act
|
|
var candidate = builder.CreateCandidate(new MatcherBuilderEntry(endpoint));
|
|
|
|
// Assert
|
|
Assert.Equal(
|
|
Candidate.CandidateFlags.HasDefaults | Candidate.CandidateFlags.HasCaptures,
|
|
candidate.Flags);
|
|
Assert.Collection(
|
|
candidate.Slots,
|
|
s => Assert.Equal(new KeyValuePair<string, object>("a", "aa"), s),
|
|
s => Assert.Equal(new KeyValuePair<string, object>("d", "dd"), s),
|
|
s => Assert.Equal(new KeyValuePair<string, object>("c", "cc"), s),
|
|
s => Assert.Equal(new KeyValuePair<string, object>(null, null), s));
|
|
Assert.Collection(
|
|
candidate.Captures,
|
|
c => Assert.Equal(("a", 0, 0), c),
|
|
c => Assert.Equal(("b", 1, 3), c),
|
|
c => Assert.Equal(("c", 2, 2), c));
|
|
Assert.Equal(default, candidate.CatchAll);
|
|
Assert.Empty(candidate.ComplexSegments);
|
|
Assert.Empty(candidate.MatchProcessors);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateCandidate_Parameters_ComplexSegments()
|
|
{
|
|
// Arrange
|
|
var endpoint = CreateEndpoint("/{a}-{b=bb}/{c}");
|
|
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
// Act
|
|
var candidate = builder.CreateCandidate(new MatcherBuilderEntry(endpoint));
|
|
|
|
// Assert
|
|
Assert.Equal(
|
|
Candidate.CandidateFlags.HasDefaults |
|
|
Candidate.CandidateFlags.HasCaptures |
|
|
Candidate.CandidateFlags.HasComplexSegments,
|
|
candidate.Flags);
|
|
Assert.Collection(
|
|
candidate.Slots,
|
|
s => Assert.Equal(new KeyValuePair<string, object>("b", "bb"), s),
|
|
s => Assert.Equal(new KeyValuePair<string, object>(null, null), s));
|
|
Assert.Collection(
|
|
candidate.Captures,
|
|
c => Assert.Equal(("c", 1, 1), c));
|
|
Assert.Equal(default, candidate.CatchAll);
|
|
Assert.Collection(
|
|
candidate.ComplexSegments,
|
|
s => Assert.Equal(0, s.segmentIndex));
|
|
Assert.Empty(candidate.MatchProcessors);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateCandidate_MatchProcessors()
|
|
{
|
|
// Arrange
|
|
var endpoint = CreateEndpoint("/a/b/c", constraints: new { a = new IntRouteConstraint(), });
|
|
|
|
var builder = CreateDfaMatcherBuilder();
|
|
|
|
// Act
|
|
var candidate = builder.CreateCandidate(new MatcherBuilderEntry(endpoint));
|
|
|
|
// Assert
|
|
Assert.Equal( Candidate.CandidateFlags.HasMatchProcessors, candidate.Flags);
|
|
Assert.Empty(candidate.Slots);
|
|
Assert.Empty(candidate.Captures);
|
|
Assert.Equal(default, candidate.CatchAll);
|
|
Assert.Empty(candidate.ComplexSegments);
|
|
Assert.Single(candidate.MatchProcessors);
|
|
}
|
|
|
|
private static DfaMatcherBuilder CreateDfaMatcherBuilder()
|
|
{
|
|
var dataSource = new CompositeEndpointDataSource(Array.Empty<EndpointDataSource>());
|
|
return new DfaMatcherBuilder(
|
|
Mock.Of<MatchProcessorFactory>(),
|
|
new EndpointSelector(
|
|
dataSource,
|
|
new EndpointConstraintCache(dataSource, Array.Empty<IEndpointConstraintProvider>()),
|
|
NullLoggerFactory.Instance));
|
|
}
|
|
|
|
private MatcherEndpoint CreateEndpoint(
|
|
string template,
|
|
object defaults = null,
|
|
object constraints = null)
|
|
{
|
|
return new MatcherEndpoint(
|
|
MatcherEndpoint.EmptyInvoker,
|
|
RoutePatternFactory.Parse(template, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints)),
|
|
new RouteValueDictionary(),
|
|
0,
|
|
new EndpointMetadataCollection(Array.Empty<object>()),
|
|
"test");
|
|
}
|
|
}
|
|
}
|