From 08a0a7fadbd60bba625a8c244f2230eca49f5abd Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Wed, 22 Aug 2018 15:24:34 +1200 Subject: [PATCH] Remove MatchProcessor, add IParameterPolicy (#734) --- .../EndpointRoutingBenchmarkBase.cs | 2 +- .../EndsWithStringMatchProcessor.cs | 61 ---- .../EndsWithStringRouteConstraint.cs | 33 ++ .../UseEndpointRoutingStartup.cs | 4 +- .../IParameterPolicy.cs | 12 + .../IRouteConstraint.cs | 2 +- .../DefaultLinkGenerator.cs | 13 +- ...ry.cs => DefaultParameterPolicyFactory.cs} | 69 ++-- .../RoutingServiceCollectionExtensions.cs | 2 +- .../Matching/Candidate.cs | 14 +- .../Matching/DfaMatcher.cs | 14 +- .../Matching/DfaMatcherBuilder.cs | 25 +- .../Matching/MatchProcessor.cs | 18 - .../Matching/MatchProcessorFactory.cs | 46 --- .../Matching/OptionalMatchProcessor.cs | 44 --- .../Matching/RouteConstraintMatchProcessor.cs | 61 ---- .../ParameterPolicyFactory.cs | 60 ++++ .../Patterns/RouteParameterParser.cs | 34 +- .../Patterns/RoutePattern.cs | 12 +- .../RoutePatternConstraintReference.cs | 51 --- .../Patterns/RoutePatternFactory.cs | 230 +++++++------ .../Patterns/RoutePatternParameterPart.cs | 16 +- .../RoutePatternParameterPolicyReference.cs | 41 +++ .../Properties/Resources.Designer.cs | 6 +- .../Resources.resx | 2 +- .../Template/InlineConstraint.cs | 2 +- .../Template/RoutePrecedence.cs | 4 +- .../Template/TemplatePart.cs | 4 +- .../CompositeEndpointDataSourceTest.cs | 2 +- .../DefaultLinkGeneratorTest.cs | 2 +- .../Matching/CandidateSetTest.cs | 2 +- .../DefaultMatchProcessorFactoryTest.cs | 320 ------------------ .../DefaultParameterPolicyFactoryTest.cs | 272 +++++++++++++++ .../Matching/DfaMatcherBuilderTest.cs | 47 ++- .../Matching/DfaMatcherTest.cs | 2 +- .../RouteConstraintMatchProcessorTest.cs | 62 ---- .../InlineRouteParameterParserTest.cs | 124 +++---- .../Patterns/RoutePatternFactoryTest.cs | 36 +- .../Patterns/RoutePatternParserTest.cs | 10 +- .../RouteValueBasedEndpointFinderTest.cs | 2 +- 40 files changed, 769 insertions(+), 994 deletions(-) delete mode 100644 samples/RoutingSample.Web/EndsWithStringMatchProcessor.cs create mode 100644 samples/RoutingSample.Web/EndsWithStringRouteConstraint.cs create mode 100644 src/Microsoft.AspNetCore.Routing.Abstractions/IParameterPolicy.cs rename src/Microsoft.AspNetCore.Routing/{Matching/DefaultMatchProcessorFactory.cs => DefaultParameterPolicyFactory.cs} (54%) delete mode 100644 src/Microsoft.AspNetCore.Routing/Matching/MatchProcessor.cs delete mode 100644 src/Microsoft.AspNetCore.Routing/Matching/MatchProcessorFactory.cs delete mode 100644 src/Microsoft.AspNetCore.Routing/Matching/OptionalMatchProcessor.cs delete mode 100644 src/Microsoft.AspNetCore.Routing/Matching/RouteConstraintMatchProcessor.cs create mode 100644 src/Microsoft.AspNetCore.Routing/ParameterPolicyFactory.cs delete mode 100644 src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternConstraintReference.cs create mode 100644 src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParameterPolicyReference.cs delete mode 100644 test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultMatchProcessorFactoryTest.cs create mode 100644 test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultParameterPolicyFactoryTest.cs delete mode 100644 test/Microsoft.AspNetCore.Routing.Tests/Matching/RouteConstraintMatchProcessorTest.cs diff --git a/benchmarks/Microsoft.AspNetCore.Routing.Performance/EndpointRoutingBenchmarkBase.cs b/benchmarks/Microsoft.AspNetCore.Routing.Performance/EndpointRoutingBenchmarkBase.cs index 440c6b3860..57e79d7109 100644 --- a/benchmarks/Microsoft.AspNetCore.Routing.Performance/EndpointRoutingBenchmarkBase.cs +++ b/benchmarks/Microsoft.AspNetCore.Routing.Performance/EndpointRoutingBenchmarkBase.cs @@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.Routing new RouteTemplate(RoutePatternFactory.Parse( endpoint.RoutePattern.RawText, defaults: endpoint.RoutePattern.Defaults, - constraints: null)), + parameterPolicies: null)), requiredLinkValues: new RouteValueDictionary(requiredValues), routeName: null, order: 0); diff --git a/samples/RoutingSample.Web/EndsWithStringMatchProcessor.cs b/samples/RoutingSample.Web/EndsWithStringMatchProcessor.cs deleted file mode 100644 index f0201f79d9..0000000000 --- a/samples/RoutingSample.Web/EndsWithStringMatchProcessor.cs +++ /dev/null @@ -1,61 +0,0 @@ -// 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.Globalization; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; -using Microsoft.AspNetCore.Routing.Matching; -using Microsoft.Extensions.Logging; - -namespace RoutingSample.Web -{ - internal class EndsWithStringMatchProcessor : MatchProcessor - { - private readonly ILogger _logger; - - public EndsWithStringMatchProcessor(ILogger logger) - { - _logger = logger; - } - - public string ParameterName { get; private set; } - - public string ConstraintArgument { get; private set; } - - public override void Initialize(string parameterName, string constraintArgument) - { - ParameterName = parameterName; - ConstraintArgument = constraintArgument; - } - - public override bool ProcessInbound(HttpContext httpContext, RouteValueDictionary values) - { - return Process(values); - } - - public override bool ProcessOutbound(HttpContext httpContext, RouteValueDictionary values) - { - return Process(values); - } - - private bool Process(RouteValueDictionary values) - { - if (!values.TryGetValue(ParameterName, out var value) || value == null) - { - return false; - } - - var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); - var endsWith = valueString.EndsWith(ConstraintArgument, StringComparison.OrdinalIgnoreCase); - - if (!endsWith) - { - _logger.LogDebug( - $"Parameter '{ParameterName}' with value '{valueString}' does not end with '{ConstraintArgument}'."); - } - - return endsWith; - } - } -} diff --git a/samples/RoutingSample.Web/EndsWithStringRouteConstraint.cs b/samples/RoutingSample.Web/EndsWithStringRouteConstraint.cs new file mode 100644 index 0000000000..2d1ebecb64 --- /dev/null +++ b/samples/RoutingSample.Web/EndsWithStringRouteConstraint.cs @@ -0,0 +1,33 @@ +// 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.Globalization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace RoutingSample.Web +{ + internal class EndsWithStringRouteConstraint : IRouteConstraint + { + private readonly string _endsWith; + + public EndsWithStringRouteConstraint(string endsWith) + { + _endsWith = endsWith; + } + + public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) + { + var value = values[routeKey]; + if (value == null) + { + return false; + } + + var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); + var endsWith = valueString.EndsWith(_endsWith, StringComparison.OrdinalIgnoreCase); + return endsWith; + } + } +} diff --git a/samples/RoutingSample.Web/UseEndpointRoutingStartup.cs b/samples/RoutingSample.Web/UseEndpointRoutingStartup.cs index fb9fb36161..f3606d5a9f 100644 --- a/samples/RoutingSample.Web/UseEndpointRoutingStartup.cs +++ b/samples/RoutingSample.Web/UseEndpointRoutingStartup.cs @@ -23,11 +23,11 @@ namespace RoutingSample.Web public void ConfigureServices(IServiceCollection services) { - services.AddTransient(); + services.AddTransient(); services.AddRouting(options => { - options.ConstraintMap.Add("endsWith", typeof(EndsWithStringMatchProcessor)); + options.ConstraintMap.Add("endsWith", typeof(EndsWithStringRouteConstraint)); }); var endpointDataSource = new DefaultEndpointDataSource(new[] diff --git a/src/Microsoft.AspNetCore.Routing.Abstractions/IParameterPolicy.cs b/src/Microsoft.AspNetCore.Routing.Abstractions/IParameterPolicy.cs new file mode 100644 index 0000000000..75af7b2830 --- /dev/null +++ b/src/Microsoft.AspNetCore.Routing.Abstractions/IParameterPolicy.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.AspNetCore.Routing +{ + /// + /// A marker interface for types that are associated with route parameters. + /// + public interface IParameterPolicy + { + } +} diff --git a/src/Microsoft.AspNetCore.Routing.Abstractions/IRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing.Abstractions/IRouteConstraint.cs index 00eb916510..5b82823e89 100644 --- a/src/Microsoft.AspNetCore.Routing.Abstractions/IRouteConstraint.cs +++ b/src/Microsoft.AspNetCore.Routing.Abstractions/IRouteConstraint.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Routing /// Defines the contract that a class must implement in order to check whether a URL parameter /// value is valid for a constraint. /// - public interface IRouteConstraint + public interface IRouteConstraint : IParameterPolicy { /// /// Determines whether the URL parameter contains a valid value for this constraint. diff --git a/src/Microsoft.AspNetCore.Routing/DefaultLinkGenerator.cs b/src/Microsoft.AspNetCore.Routing/DefaultLinkGenerator.cs index de52bf1a2b..fe38826aa7 100644 --- a/src/Microsoft.AspNetCore.Routing/DefaultLinkGenerator.cs +++ b/src/Microsoft.AspNetCore.Routing/DefaultLinkGenerator.cs @@ -19,20 +19,20 @@ namespace Microsoft.AspNetCore.Routing internal class DefaultLinkGenerator : LinkGenerator { private readonly static char[] UrlQueryDelimiters = new char[] { '?', '#' }; - private readonly MatchProcessorFactory _matchProcessorFactory; + private readonly ParameterPolicyFactory _parameterPolicyFactory; private readonly ObjectPool _uriBuildingContextPool; private readonly ILogger _logger; private readonly IServiceProvider _serviceProvider; private readonly RouteOptions _options; public DefaultLinkGenerator( - MatchProcessorFactory matchProcessorFactory, + ParameterPolicyFactory parameterPolicyFactory, ObjectPool uriBuildingContextPool, IOptions routeOptions, ILogger logger, IServiceProvider serviceProvider) { - _matchProcessorFactory = matchProcessorFactory; + _parameterPolicyFactory = parameterPolicyFactory; _uriBuildingContextPool = uriBuildingContextPool; _options = routeOptions.Value; _logger = logger; @@ -240,15 +240,16 @@ namespace Microsoft.AspNetCore.Routing throw new ArgumentNullException(nameof(routeValues)); } - foreach (var kvp in endpoint.RoutePattern.Constraints) + foreach (var kvp in endpoint.RoutePattern.ParameterPolicies) { var parameter = endpoint.RoutePattern.GetParameter(kvp.Key); // may be null, that's ok var constraintReferences = kvp.Value; for (var i = 0; i < constraintReferences.Count; i++) { var constraintReference = constraintReferences[i]; - var matchProcessor = _matchProcessorFactory.Create(parameter, constraintReference); - if (!matchProcessor.ProcessOutbound(httpContext, routeValues)) + var parameterPolicy = _parameterPolicyFactory.Create(parameter, constraintReference); + if (parameterPolicy is IRouteConstraint routeConstraint + && !routeConstraint.Match(httpContext, NullRouter.Instance, kvp.Key, routeValues, RouteDirection.UrlGeneration)) { return false; } diff --git a/src/Microsoft.AspNetCore.Routing/Matching/DefaultMatchProcessorFactory.cs b/src/Microsoft.AspNetCore.Routing/DefaultParameterPolicyFactory.cs similarity index 54% rename from src/Microsoft.AspNetCore.Routing/Matching/DefaultMatchProcessorFactory.cs rename to src/Microsoft.AspNetCore.Routing/DefaultParameterPolicyFactory.cs index 26e374a580..a85f3d826b 100644 --- a/src/Microsoft.AspNetCore.Routing/Matching/DefaultMatchProcessorFactory.cs +++ b/src/Microsoft.AspNetCore.Routing/DefaultParameterPolicyFactory.cs @@ -2,17 +2,19 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Routing.Constraints; +using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -namespace Microsoft.AspNetCore.Routing.Matching +namespace Microsoft.AspNetCore.Routing { - internal class DefaultMatchProcessorFactory : MatchProcessorFactory + internal class DefaultParameterPolicyFactory : ParameterPolicyFactory { private readonly RouteOptions _options; private readonly IServiceProvider _serviceProvider; - public DefaultMatchProcessorFactory( + public DefaultParameterPolicyFactory( IOptions options, IServiceProvider serviceProvider) { @@ -20,31 +22,26 @@ namespace Microsoft.AspNetCore.Routing.Matching _serviceProvider = serviceProvider; } - public override MatchProcessor Create(string parameterName, IRouteConstraint value, bool optional) + public override IParameterPolicy Create(RoutePatternParameterPart parameter, IParameterPolicy parameterPolicy) { - if (value == null) + if (parameterPolicy == null) { - throw new ArgumentNullException(nameof(value)); + throw new ArgumentNullException(nameof(parameterPolicy)); } - return InitializeMatchProcessor(parameterName, optional, value, argument: null); - } - - public override MatchProcessor Create(string parameterName, MatchProcessor value, bool optional) - { - if (value == null) + if (parameterPolicy is IRouteConstraint routeConstraint) { - throw new ArgumentNullException(nameof(value)); + return InitializeRouteConstraint(parameter?.IsOptional ?? false, routeConstraint, argument: null); } - return InitializeMatchProcessor(parameterName, optional, value, argument: null); + return parameterPolicy; } - public override MatchProcessor Create(string parameterName, string value, bool optional) + public override IParameterPolicy Create(RoutePatternParameterPart parameter, string inlineText) { - if (value == null) + if (inlineText == null) { - throw new ArgumentNullException(nameof(value)); + throw new ArgumentNullException(nameof(inlineText)); } // Example: @@ -54,7 +51,7 @@ namespace Microsoft.AspNetCore.Routing.Matching // value: regex(\d+) // name: regex // argument: \d+ - (var name, var argument) = Parse(value); + (var name, var argument) = Parse(inlineText); if (!_options.ConstraintMap.TryGetValue(name, out var type)) { @@ -64,49 +61,37 @@ namespace Microsoft.AspNetCore.Routing.Matching nameof(RouteOptions.ConstraintMap))); } - if (typeof(MatchProcessor).IsAssignableFrom(type)) - { - var matchProcessor = (MatchProcessor)_serviceProvider.GetRequiredService(type); - return InitializeMatchProcessor(parameterName, optional, matchProcessor, argument); - } - if (typeof(IRouteConstraint).IsAssignableFrom(type)) { var constraint = DefaultInlineConstraintResolver.CreateConstraint(type, argument); - return InitializeMatchProcessor(parameterName, optional, constraint, argument); + return InitializeRouteConstraint(parameter?.IsOptional ?? false, constraint, argument); + } + + if (typeof(IParameterPolicy).IsAssignableFrom(type)) + { + var parameterPolicy = (IParameterPolicy)_serviceProvider.GetRequiredService(type); + return parameterPolicy; } var message = Resources.FormatRoutePattern_InvalidStringConstraintReference( type, name, typeof(IRouteConstraint), - typeof(MatchProcessor)); + typeof(IParameterPolicy)); throw new InvalidOperationException(message); } - private MatchProcessor InitializeMatchProcessor( - string parameterName, + private IParameterPolicy InitializeRouteConstraint( bool optional, - IRouteConstraint constraint, - string argument) - { - var matchProcessor = (MatchProcessor)new RouteConstraintMatchProcessor(parameterName, constraint); - return InitializeMatchProcessor(parameterName, optional, matchProcessor, argument); - } - - private MatchProcessor InitializeMatchProcessor( - string parameterName, - bool optional, - MatchProcessor matchProcessor, + IRouteConstraint routeConstraint, string argument) { if (optional) { - matchProcessor = new OptionalMatchProcessor(matchProcessor); + routeConstraint = new OptionalRouteConstraint(routeConstraint); } - matchProcessor.Initialize(parameterName, argument); - return matchProcessor; + return routeConstraint; } private (string name, string argument) Parse(string text) diff --git a/src/Microsoft.AspNetCore.Routing/DependencyInjection/RoutingServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Routing/DependencyInjection/RoutingServiceCollectionExtensions.cs index 366f2d30fa..d2ab2f127b 100644 --- a/src/Microsoft.AspNetCore.Routing/DependencyInjection/RoutingServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNetCore.Routing/DependencyInjection/RoutingServiceCollectionExtensions.cs @@ -62,7 +62,7 @@ namespace Microsoft.Extensions.DependencyInjection // // Default matcher implementation // - services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddTransient(); services.TryAddSingleton(); diff --git a/src/Microsoft.AspNetCore.Routing/Matching/Candidate.cs b/src/Microsoft.AspNetCore.Routing/Matching/Candidate.cs index 939ac369ca..27f9b138cf 100644 --- a/src/Microsoft.AspNetCore.Routing/Matching/Candidate.cs +++ b/src/Microsoft.AspNetCore.Routing/Matching/Candidate.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Routing.Matching // RouteValueDictionary. public readonly (RoutePatternPathSegment pathSegment, int segmentIndex)[] ComplexSegments; - public readonly MatchProcessor[] MatchProcessors; + public readonly KeyValuePair[] Constraints; // Score is a sequential integer value that in determines the priority of an Endpoint. // Scores are computed within the context of candidate set, and are meaningless when @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Routing.Matching Captures = Array.Empty<(string parameterName, int segmentIndex, int slotIndex)>(); CatchAll = default; ComplexSegments = Array.Empty<(RoutePatternPathSegment pathSegment, int segmentIndex)>(); - MatchProcessors = Array.Empty(); + Constraints = Array.Empty>(); Score = 0; Flags = CandidateFlags.None; @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Routing.Matching (string parameterName, int segmentIndex, int slotIndex)[] captures, (string parameterName, int segmentIndex, int slotIndex) catchAll, (RoutePatternPathSegment pathSegment, int segmentIndex)[] complexSegments, - MatchProcessor[] matchProcessors) + KeyValuePair[] constraints) { Endpoint = endpoint; Score = score; @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Routing.Matching Captures = captures; CatchAll = catchAll; ComplexSegments = complexSegments; - MatchProcessors = matchProcessors; + Constraints = constraints; Flags = CandidateFlags.None; for (var i = 0; i < slots.Length; i++) @@ -103,9 +103,9 @@ namespace Microsoft.AspNetCore.Routing.Matching Flags |= CandidateFlags.HasComplexSegments; } - if (matchProcessors.Length > 0) + if (constraints.Length > 0) { - Flags |= CandidateFlags.HasMatchProcessors; + Flags |= CandidateFlags.HasConstraints; } } @@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Routing.Matching HasCatchAll = 4, HasSlots = HasDefaults | HasCaptures | HasCatchAll, HasComplexSegments = 8, - HasMatchProcessors = 16, + HasConstraints = 16, } } } diff --git a/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcher.cs b/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcher.cs index 427f26b566..ce8d6b4c1e 100644 --- a/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcher.cs +++ b/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcher.cs @@ -123,9 +123,9 @@ namespace Microsoft.AspNetCore.Routing.Matching isMatch &= ProcessComplexSegments(candidate.ComplexSegments, path, segments, values); } - if ((flags & Candidate.CandidateFlags.HasMatchProcessors) != 0) + if ((flags & Candidate.CandidateFlags.HasConstraints) != 0) { - isMatch &= ProcessMatchProcessors(candidate.MatchProcessors, httpContext, values); + isMatch &= ProcessConstraints(candidate.Constraints, httpContext, values); } state.IsValidCandidate = isMatch; @@ -215,15 +215,15 @@ namespace Microsoft.AspNetCore.Routing.Matching return true; } - private bool ProcessMatchProcessors( - MatchProcessor[] matchProcessors, + private bool ProcessConstraints( + KeyValuePair[] constraints, HttpContext httpContext, RouteValueDictionary values) { - for (var i = 0; i < matchProcessors.Length; i++) + for (var i = 0; i < constraints.Length; i++) { - var matchProcessor = matchProcessors[i]; - if (!matchProcessor.ProcessInbound(httpContext, values)) + var constraint = constraints[i]; + if (!constraint.Value.Match(httpContext, NullRouter.Instance, constraint.Key, values, RouteDirection.IncomingRequest)) { return false; } diff --git a/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcherBuilder.cs b/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcherBuilder.cs index 778ecdbaa5..c58d2547ff 100644 --- a/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcherBuilder.cs +++ b/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcherBuilder.cs @@ -12,18 +12,18 @@ namespace Microsoft.AspNetCore.Routing.Matching { private readonly List _endpoints = new List(); - private readonly MatchProcessorFactory _matchProcessorFactory; + private readonly ParameterPolicyFactory _parameterPolicyFactory; private readonly EndpointSelector _selector; private readonly MatcherPolicy[] _policies; private readonly INodeBuilderPolicy[] _nodeBuilders; private readonly MatcherEndpointComparer _comparer; public DfaMatcherBuilder( - MatchProcessorFactory matchProcessorFactory, + ParameterPolicyFactory parameterPolicyFactory, EndpointSelector selector, IEnumerable policies) { - _matchProcessorFactory = matchProcessorFactory; + _parameterPolicyFactory = parameterPolicyFactory; _selector = selector; _policies = policies.OrderBy(p => p.Order).ToArray(); @@ -425,16 +425,19 @@ namespace Microsoft.AspNetCore.Routing.Matching complexSegments.Add((segment, i)); } - var matchProcessors = new List(); - foreach (var kvp in endpoint.RoutePattern.Constraints) + var constraints = new List>(); + foreach (var kvp in endpoint.RoutePattern.ParameterPolicies) { var parameter = endpoint.RoutePattern.GetParameter(kvp.Key); // may be null, that's ok - var constraintReferences = kvp.Value; - for (var i = 0; i < constraintReferences.Count; i++) + var parameterPolicyReferences = kvp.Value; + for (var i = 0; i < parameterPolicyReferences.Count; i++) { - var constraintReference = constraintReferences[i]; - var matchProcessor = _matchProcessorFactory.Create(parameter, constraintReference); - matchProcessors.Add(matchProcessor); + var reference = parameterPolicyReferences[i]; + var parameterPolicy = _parameterPolicyFactory.Create(parameter, reference); + if (parameterPolicy is IRouteConstraint routeConstraint) + { + constraints.Add(new KeyValuePair(kvp.Key, routeConstraint)); + } } } @@ -445,7 +448,7 @@ namespace Microsoft.AspNetCore.Routing.Matching captures.ToArray(), catchAll, complexSegments.ToArray(), - matchProcessors.ToArray()); + constraints.ToArray()); } private int[] GetGroupLengths(DfaNode node) diff --git a/src/Microsoft.AspNetCore.Routing/Matching/MatchProcessor.cs b/src/Microsoft.AspNetCore.Routing/Matching/MatchProcessor.cs deleted file mode 100644 index 847ea29793..0000000000 --- a/src/Microsoft.AspNetCore.Routing/Matching/MatchProcessor.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Routing.Matching -{ - public abstract class MatchProcessor - { - public virtual void Initialize(string parameterName, string constraintArgument) - { - } - - public abstract bool ProcessInbound(HttpContext httpContext, RouteValueDictionary values); - - public abstract bool ProcessOutbound(HttpContext httpContext, RouteValueDictionary values); - } -} diff --git a/src/Microsoft.AspNetCore.Routing/Matching/MatchProcessorFactory.cs b/src/Microsoft.AspNetCore.Routing/Matching/MatchProcessorFactory.cs deleted file mode 100644 index 5669d75f06..0000000000 --- a/src/Microsoft.AspNetCore.Routing/Matching/MatchProcessorFactory.cs +++ /dev/null @@ -1,46 +0,0 @@ -// 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.Diagnostics; -using Microsoft.AspNetCore.Routing.Patterns; - -namespace Microsoft.AspNetCore.Routing.Matching -{ - internal abstract class MatchProcessorFactory - { - public abstract MatchProcessor Create(string parameterName, string value, bool optional); - - public abstract MatchProcessor Create(string parameterName, IRouteConstraint value, bool optional); - - public abstract MatchProcessor Create(string parameterName, MatchProcessor value, bool optional); - - public MatchProcessor Create(RoutePatternParameterPart parameter, RoutePatternConstraintReference reference) - { - if (reference == null) - { - throw new ArgumentNullException(nameof(reference)); - } - - Debug.Assert(reference.MatchProcessor != null || reference.Constraint != null || reference.Content != null); - - if (reference.MatchProcessor != null) - { - return Create(parameter?.Name, reference.MatchProcessor, parameter?.IsOptional ?? false); - } - - if (reference.Constraint != null) - { - return Create(parameter?.Name, reference.Constraint, parameter?.IsOptional ?? false); - } - - if (reference.Content != null) - { - return Create(parameter?.Name, reference.Content, parameter?.IsOptional ?? false); - } - - // Unreachable - throw new NotSupportedException(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Routing/Matching/OptionalMatchProcessor.cs b/src/Microsoft.AspNetCore.Routing/Matching/OptionalMatchProcessor.cs deleted file mode 100644 index c40df6ec8e..0000000000 --- a/src/Microsoft.AspNetCore.Routing/Matching/OptionalMatchProcessor.cs +++ /dev/null @@ -1,44 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Routing.Matching -{ - internal class OptionalMatchProcessor : MatchProcessor - { - private readonly MatchProcessor _innerMatchProcessor; - - public OptionalMatchProcessor(MatchProcessor innerMatchProcessor) - { - _innerMatchProcessor = innerMatchProcessor; - } - - public string ParameterName { get; private set; } - - public override void Initialize(string parameterName, string constraintArgument) - { - ParameterName = parameterName; - _innerMatchProcessor.Initialize(parameterName, constraintArgument); - } - - public override bool ProcessInbound(HttpContext httpContext, RouteValueDictionary values) - { - return Process(httpContext, values); - } - - public override bool ProcessOutbound(HttpContext httpContext, RouteValueDictionary values) - { - return Process(httpContext, values); - } - - private bool Process(HttpContext httpContext, RouteValueDictionary values) - { - if (values.TryGetValue(ParameterName, out var value)) - { - return _innerMatchProcessor.ProcessInbound(httpContext, values); - } - return true; - } - } -} diff --git a/src/Microsoft.AspNetCore.Routing/Matching/RouteConstraintMatchProcessor.cs b/src/Microsoft.AspNetCore.Routing/Matching/RouteConstraintMatchProcessor.cs deleted file mode 100644 index ad1ddaf7ae..0000000000 --- a/src/Microsoft.AspNetCore.Routing/Matching/RouteConstraintMatchProcessor.cs +++ /dev/null @@ -1,61 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Routing.Matching -{ - internal class RouteConstraintMatchProcessor : MatchProcessor - { - public RouteConstraintMatchProcessor(string parameterName, IRouteConstraint constraint) - { - ParameterName = parameterName; - Constraint = constraint; - } - - public string ParameterName { get; } - - public IRouteConstraint Constraint { get; } - - public override bool ProcessInbound(HttpContext httpContext, RouteValueDictionary values) - { - if (httpContext == null) - { - throw new ArgumentNullException(nameof(httpContext)); - } - - if (values == null) - { - throw new ArgumentNullException(nameof(values)); - } - - return Constraint.Match( - httpContext, - NullRouter.Instance, - ParameterName, - values, - RouteDirection.IncomingRequest); - } - - public override bool ProcessOutbound(HttpContext httpContext, RouteValueDictionary values) - { - if (httpContext == null) - { - throw new ArgumentNullException(nameof(httpContext)); - } - - if (values == null) - { - throw new ArgumentNullException(nameof(values)); - } - - return Constraint.Match( - httpContext, - NullRouter.Instance, - ParameterName, - values, - RouteDirection.UrlGeneration); - } - } -} diff --git a/src/Microsoft.AspNetCore.Routing/ParameterPolicyFactory.cs b/src/Microsoft.AspNetCore.Routing/ParameterPolicyFactory.cs new file mode 100644 index 0000000000..cd875fc907 --- /dev/null +++ b/src/Microsoft.AspNetCore.Routing/ParameterPolicyFactory.cs @@ -0,0 +1,60 @@ +// 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.Diagnostics; +using Microsoft.AspNetCore.Routing.Patterns; + +namespace Microsoft.AspNetCore.Routing +{ + /// + /// Defines an abstraction for resolving inline parameter policies as instances of . + /// + public abstract class ParameterPolicyFactory + { + /// + /// Creates a parameter policy. + /// + /// The parameter the parameter policy is being created for. + /// The inline text to resolve. + /// The for the parameter. + public abstract IParameterPolicy Create(RoutePatternParameterPart parameter, string inlineText); + + /// + /// Creates a parameter policy. + /// + /// The parameter the parameter policy is being created for. + /// An existing parameter policy. + /// The for the parameter. + public abstract IParameterPolicy Create(RoutePatternParameterPart parameter, IParameterPolicy parameterPolicy); + + /// + /// Creates a parameter policy. + /// + /// The parameter the parameter policy is being created for. + /// The reference to resolve. + /// The for the parameter. + public IParameterPolicy Create(RoutePatternParameterPart parameter, RoutePatternParameterPolicyReference reference) + { + if (reference == null) + { + throw new ArgumentNullException(nameof(reference)); + } + + Debug.Assert(reference.ParameterPolicy != null || reference.Content != null); + + if (reference.ParameterPolicy != null) + { + return Create(parameter, reference.ParameterPolicy); + } + + if (reference.Content != null) + { + return Create(parameter, reference.Content); + } + + // Unreachable + throw new NotSupportedException(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RouteParameterParser.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RouteParameterParser.cs index 8c0132bc06..49860dcb0f 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RouteParameterParser.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RouteParameterParser.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns if (parameter.Length == 0) { - return new RoutePatternParameterPart(string.Empty, null, RoutePatternParameterKind.Standard, Array.Empty()); + return new RoutePatternParameterPart(string.Empty, null, RoutePatternParameterKind.Standard, Array.Empty()); } var startIndex = 0; @@ -91,17 +91,17 @@ namespace Microsoft.AspNetCore.Routing.Patterns parameterName, defaultValue, parameterKind, - parseResults.Constraints.ToArray(), + parseResults.ParameterPolicies.ToArray(), encodeSlashes); } - private static ConstraintParseResults ParseConstraints( + private static ParameterPolicyParseResults ParseConstraints( string text, string parameterName, int currentIndex, int endIndex) { - var constraints = new List(); + var constraints = new List(); var state = ParseState.Start; var startIndex = currentIndex; do @@ -134,7 +134,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns case null: state = ParseState.End; var constraintText = text.Substring(startIndex, currentIndex - startIndex); - constraints.Add(RoutePatternFactory.Constraint(constraintText)); + constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText)); break; case ')': // Only consume a ')' token if @@ -148,18 +148,18 @@ namespace Microsoft.AspNetCore.Routing.Patterns case null: state = ParseState.End; constraintText = text.Substring(startIndex, currentIndex - startIndex + 1); - constraints.Add(RoutePatternFactory.Constraint(constraintText)); + constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText)); break; case ':': state = ParseState.Start; constraintText = text.Substring(startIndex, currentIndex - startIndex + 1); - constraints.Add(RoutePatternFactory.Constraint(constraintText)); + constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText)); startIndex = currentIndex + 1; break; case '=': state = ParseState.End; constraintText = text.Substring(startIndex, currentIndex - startIndex + 1); - constraints.Add(RoutePatternFactory.Constraint(constraintText)); + constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText)); break; } break; @@ -174,7 +174,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns if (indexOfClosingParantheses == -1) { constraintText = text.Substring(startIndex, currentIndex - startIndex); - constraints.Add(RoutePatternFactory.Constraint(constraintText)); + constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText)); if (currentChar == ':') { @@ -203,14 +203,14 @@ namespace Microsoft.AspNetCore.Routing.Patterns var constraintText = text.Substring(startIndex, currentIndex - startIndex); if (constraintText.Length > 0) { - constraints.Add(RoutePatternFactory.Constraint(constraintText)); + constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText)); } break; case ':': constraintText = text.Substring(startIndex, currentIndex - startIndex); if (constraintText.Length > 0) { - constraints.Add(RoutePatternFactory.Constraint(constraintText)); + constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText)); } startIndex = currentIndex + 1; break; @@ -222,7 +222,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns constraintText = text.Substring(startIndex, currentIndex - startIndex); if (constraintText.Length > 0) { - constraints.Add(RoutePatternFactory.Constraint(constraintText)); + constraints.Add(RoutePatternFactory.ParameterPolicy(constraintText)); } currentIndex--; break; @@ -234,7 +234,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns } while (state != ParseState.End); - return new ConstraintParseResults(currentIndex, constraints); + return new ParameterPolicyParseResults(currentIndex, constraints); } private enum ParseState @@ -245,16 +245,16 @@ namespace Microsoft.AspNetCore.Routing.Patterns End } - private readonly struct ConstraintParseResults + private readonly struct ParameterPolicyParseResults { public readonly int CurrentIndex; - public readonly IReadOnlyList Constraints; + public readonly IReadOnlyList ParameterPolicies; - public ConstraintParseResults(int currentIndex, IReadOnlyList constraints) + public ParameterPolicyParseResults(int currentIndex, IReadOnlyList parameterPolicies) { CurrentIndex = currentIndex; - Constraints = constraints; + ParameterPolicies = parameterPolicies; } } } diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs index 80c2dfd801..1f1bf7ee0a 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs @@ -22,18 +22,18 @@ namespace Microsoft.AspNetCore.Routing.Patterns internal RoutePattern( string rawText, IReadOnlyDictionary defaults, - IReadOnlyDictionary> constraints, + IReadOnlyDictionary> parameterPolicies, IReadOnlyList parameters, IReadOnlyList pathSegments) { Debug.Assert(defaults != null); - Debug.Assert(constraints != null); + Debug.Assert(parameterPolicies != null); Debug.Assert(parameters != null); Debug.Assert(pathSegments != null); RawText = rawText; Defaults = defaults; - Constraints = constraints; + ParameterPolicies = parameterPolicies; Parameters = parameters; PathSegments = pathSegments; @@ -48,10 +48,10 @@ namespace Microsoft.AspNetCore.Routing.Patterns public IReadOnlyDictionary Defaults { get; } /// - /// Gets the set of constraint references for the route pattern. - /// The keys of are the route parameter names. + /// Gets the set of parameter policy references for the route pattern. + /// The keys of are the route parameter names. /// - public IReadOnlyDictionary> Constraints { get; } + public IReadOnlyDictionary> ParameterPolicies { get; } /// /// Gets the precedence value of the route pattern for URL matching. diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternConstraintReference.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternConstraintReference.cs deleted file mode 100644 index 3e832ead65..0000000000 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternConstraintReference.cs +++ /dev/null @@ -1,51 +0,0 @@ -// 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.Diagnostics; -using Microsoft.AspNetCore.Routing.Matching; - -namespace Microsoft.AspNetCore.Routing.Patterns -{ - /// - /// The parsed representation of a constraint in a parameter. Instances - /// of are immutable. - /// - [DebuggerDisplay("{DebuggerToString()}")] - public sealed class RoutePatternConstraintReference - { - internal RoutePatternConstraintReference(string content) - { - Content = content; - } - - internal RoutePatternConstraintReference(IRouteConstraint constraint) - { - Constraint = constraint; - } - - internal RoutePatternConstraintReference(MatchProcessor matchProcessor) - { - MatchProcessor = matchProcessor; - } - - /// - /// Gets the constraint text. - /// - public string Content { get; } - - /// - /// Gets a pre-existing that was used to construct this reference. - /// - public IRouteConstraint Constraint { get; } - - /// - /// Gets a pre-existing that was used to construct this reference. - /// - public MatchProcessor MatchProcessor { get; } - - private string DebuggerToString() - { - return Content; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs index f34007481e..f3309cf1b6 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns /// /// Creates a from its string representation along - /// with provided default values and constraints. + /// with provided default values and parameter policies. /// /// The route pattern string to parse. /// @@ -41,13 +41,13 @@ namespace Microsoft.AspNetCore.Routing.Patterns /// The provided object will be converted to key-value pairs using /// and then merged into the parsed route pattern. /// - /// - /// Additional constraints to associated with the route pattern. May be null. + /// + /// Additional parameter policies to associated with the route pattern. May be null. /// The provided object will be converted to key-value pairs using /// and then merged into the parsed route pattern. /// /// The . - public static RoutePattern Parse(string pattern, object defaults, object constraints) + public static RoutePattern Parse(string pattern, object defaults, object parameterPolicies) { if (pattern == null) { @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns } var original = RoutePatternParser.Parse(pattern); - return Pattern(original.RawText, defaults, constraints, original.PathSegments); + return Pattern(original.RawText, defaults, parameterPolicies, original.PathSegments); } /// @@ -91,15 +91,15 @@ namespace Microsoft.AspNetCore.Routing.Patterns /// /// Creates a from a collection of segments along - /// with provided default values and constraints. + /// with provided default values and parameter policies. /// /// /// Additional default values to associated with the route pattern. May be null. /// The provided object will be converted to key-value pairs using /// and then merged into the route pattern. /// - /// - /// Additional constraints to associated with the route pattern. May be null. + /// + /// Additional parameter policies to associated with the route pattern. May be null. /// The provided object will be converted to key-value pairs using /// and then merged into the route pattern. /// @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns /// The . public static RoutePattern Pattern( object defaults, - object constraints, + object parameterPolicies, IEnumerable segments) { if (segments == null) @@ -115,12 +115,12 @@ namespace Microsoft.AspNetCore.Routing.Patterns throw new ArgumentNullException(nameof(segments)); } - return PatternCore(null, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), segments); + return PatternCore(null, new RouteValueDictionary(defaults), new RouteValueDictionary(parameterPolicies), segments); } /// /// Creates a from a collection of segments along - /// with provided default values and constraints. + /// with provided default values and parameter policies. /// /// The raw text to associate with the route pattern. /// @@ -128,8 +128,8 @@ namespace Microsoft.AspNetCore.Routing.Patterns /// The provided object will be converted to key-value pairs using /// and then merged into the route pattern. /// - /// - /// Additional constraints to associated with the route pattern. May be null. + /// + /// Additional parameter policies to associated with the route pattern. May be null. /// The provided object will be converted to key-value pairs using /// and then merged into the route pattern. /// @@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns public static RoutePattern Pattern( string rawText, object defaults, - object constraints, + object parameterPolicies, IEnumerable segments) { if (segments == null) @@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns throw new ArgumentNullException(nameof(segments)); } - return PatternCore(rawText, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), segments); + return PatternCore(rawText, new RouteValueDictionary(defaults), new RouteValueDictionary(parameterPolicies), segments); } /// @@ -182,15 +182,15 @@ namespace Microsoft.AspNetCore.Routing.Patterns /// /// Creates a from a collection of segments along - /// with provided default values and constraints. + /// with provided default values and parameter policies. /// /// /// Additional default values to associated with the route pattern. May be null. /// The provided object will be converted to key-value pairs using /// and then merged into the route pattern. /// - /// - /// Additional constraints to associated with the route pattern. May be null. + /// + /// Additional parameter policies to associated with the route pattern. May be null. /// The provided object will be converted to key-value pairs using /// and then merged into the route pattern. /// @@ -198,7 +198,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns /// The . public static RoutePattern Pattern( object defaults, - object constraints, + object parameterPolicies, params RoutePatternPathSegment[] segments) { if (segments == null) @@ -206,12 +206,12 @@ namespace Microsoft.AspNetCore.Routing.Patterns throw new ArgumentNullException(nameof(segments)); } - return PatternCore(null, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), segments); + return PatternCore(null, new RouteValueDictionary(defaults), new RouteValueDictionary(parameterPolicies), segments); } /// /// Creates a from a collection of segments along - /// with provided default values and constraints. + /// with provided default values and parameter policies. /// /// The raw text to associate with the route pattern. /// @@ -219,8 +219,8 @@ namespace Microsoft.AspNetCore.Routing.Patterns /// The provided object will be converted to key-value pairs using /// and then merged into the route pattern. /// - /// - /// Additional constraints to associated with the route pattern. May be null. + /// + /// Additional parameter policies to associated with the route pattern. May be null. /// The provided object will be converted to key-value pairs using /// and then merged into the route pattern. /// @@ -229,7 +229,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns public static RoutePattern Pattern( string rawText, object defaults, - object constraints, + object parameterPolicies, params RoutePatternPathSegment[] segments) { if (segments == null) @@ -237,21 +237,21 @@ namespace Microsoft.AspNetCore.Routing.Patterns throw new ArgumentNullException(nameof(segments)); } - return PatternCore(rawText, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), segments); + return PatternCore(rawText, new RouteValueDictionary(defaults), new RouteValueDictionary(parameterPolicies), segments); } private static RoutePattern PatternCore( string rawText, IDictionary defaults, - IDictionary constraints, + IDictionary parameterPolicies, IEnumerable segments) { - // We want to merge the segment data with the 'out of line' defaults and constraints. + // We want to merge the segment data with the 'out of line' defaults and parameter policies. // // This means that for parameters that have 'out of line' defaults we will modify - // the parameter to contain the default (same story for constraints). + // the parameter to contain the default (same story for parameter policies). // - // We also maintain a collection of defaults and constraints that will also + // We also maintain a collection of defaults and parameter policies that will also // contain the values that don't match a parameter. // // It's important that these two views of the data are consistent. We don't want @@ -266,14 +266,16 @@ namespace Microsoft.AspNetCore.Routing.Patterns } } - var updatedConstraints = new Dictionary>(StringComparer.OrdinalIgnoreCase); - if (constraints != null) + var updatedParameterPolicies = new Dictionary>(StringComparer.OrdinalIgnoreCase); + if (parameterPolicies != null) { - foreach (var kvp in constraints) + foreach (var kvp in parameterPolicies) { - updatedConstraints.Add(kvp.Key, new List() + updatedParameterPolicies.Add(kvp.Key, new List() { - Constraint(kvp.Value), + kvp.Value is IParameterPolicy parameterPolicy + ? ParameterPolicy(parameterPolicy) + : Constraint(kvp.Value), // Constraint will convert string values into regex constraints }); } } @@ -297,7 +299,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns return new RoutePattern( rawText, updatedDefaults, - updatedConstraints.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList)kvp.Value.ToArray()), + updatedParameterPolicies.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList)kvp.Value.ToArray()), parameters, updatedSegments); @@ -361,20 +363,20 @@ namespace Microsoft.AspNetCore.Routing.Patterns updatedDefaults.Add(parameter.Name, parameter.Default); } - if (!updatedConstraints.TryGetValue(parameter.Name, out var parameterConstraints) && - parameter.Constraints.Count > 0) + if (!updatedParameterPolicies.TryGetValue(parameter.Name, out var parameterConstraints) && + parameter.ParameterPolicies.Count > 0) { - parameterConstraints = new List(); - updatedConstraints.Add(parameter.Name, parameterConstraints); + parameterConstraints = new List(); + updatedParameterPolicies.Add(parameter.Name, parameterConstraints); } - if (parameter.Constraints.Count > 0) + if (parameter.ParameterPolicies.Count > 0) { - parameterConstraints.AddRange(parameter.Constraints); + parameterConstraints.AddRange(parameter.ParameterPolicies); } if (Equals(parameter.Default, @default) - && parameter.Constraints.Count == 0 + && parameter.ParameterPolicies.Count == 0 && (parameterConstraints?.Count ?? 0) == 0) { // Part has not changed @@ -385,11 +387,10 @@ namespace Microsoft.AspNetCore.Routing.Patterns parameter.Name, @default, parameter.ParameterKind, - (IEnumerable)parameterConstraints ?? Array.Empty(), + (IEnumerable)parameterConstraints ?? Array.Empty(), parameter.EncodeSlashes); } } - /// /// Creates a from the provided collection /// of parts. @@ -495,7 +496,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns parameterName: parameterName, @default: null, parameterKind: RoutePatternParameterKind.Standard, - constraints: Array.Empty()); + parameterPolicies: Array.Empty()); } /// @@ -521,7 +522,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns parameterName: parameterName, @default: @default, parameterKind: RoutePatternParameterKind.Standard, - constraints: Array.Empty()); + parameterPolicies: Array.Empty()); } /// @@ -556,23 +557,23 @@ namespace Microsoft.AspNetCore.Routing.Patterns parameterName: parameterName, @default: @default, parameterKind: parameterKind, - constraints: Array.Empty()); + parameterPolicies: Array.Empty()); } /// /// Creates a from the provided parameter name - /// and default value, parameter kind, and constraints. + /// and default value, parameter kind, and parameter policies. /// /// The parameter name. /// The parameter default value. May be null. /// The parameter kind. - /// The constraints to associated with the parameter. + /// The parameter policies to associated with the parameter. /// The . public static RoutePatternParameterPart ParameterPart( string parameterName, object @default, RoutePatternParameterKind parameterKind, - IEnumerable constraints) + IEnumerable parameterPolicies) { if (string.IsNullOrEmpty(parameterName)) { @@ -589,32 +590,32 @@ namespace Microsoft.AspNetCore.Routing.Patterns throw new ArgumentNullException(Resources.TemplateRoute_OptionalCannotHaveDefaultValue, nameof(parameterKind)); } - if (constraints == null) + if (parameterPolicies == null) { - throw new ArgumentNullException(nameof(constraints)); + throw new ArgumentNullException(nameof(parameterPolicies)); } return ParameterPartCore( parameterName: parameterName, @default: @default, parameterKind: parameterKind, - constraints: constraints); + parameterPolicies: parameterPolicies); } /// /// Creates a from the provided parameter name - /// and default value, parameter kind, and constraints. + /// and default value, parameter kind, and parameter policies. /// /// The parameter name. /// The parameter default value. May be null. /// The parameter kind. - /// The constraints to associated with the parameter. + /// The parameter policies to associated with the parameter. /// The . public static RoutePatternParameterPart ParameterPart( string parameterName, object @default, RoutePatternParameterKind parameterKind, - params RoutePatternConstraintReference[] constraints) + params RoutePatternParameterPolicyReference[] parameterPolicies) { if (string.IsNullOrEmpty(parameterName)) { @@ -631,141 +632,146 @@ namespace Microsoft.AspNetCore.Routing.Patterns throw new ArgumentNullException(Resources.TemplateRoute_OptionalCannotHaveDefaultValue, nameof(parameterKind)); } - if (constraints == null) + if (parameterPolicies == null) { - throw new ArgumentNullException(nameof(constraints)); + throw new ArgumentNullException(nameof(parameterPolicies)); } return ParameterPartCore( parameterName: parameterName, @default: @default, parameterKind: parameterKind, - constraints: constraints); + parameterPolicies: parameterPolicies); } private static RoutePatternParameterPart ParameterPartCore( string parameterName, object @default, RoutePatternParameterKind parameterKind, - IEnumerable constraints) + IEnumerable parameterPolicies) { - return ParameterPartCore(parameterName, @default, parameterKind, constraints, encodeSlashes: true); + return ParameterPartCore(parameterName, @default, parameterKind, parameterPolicies, encodeSlashes: true); } private static RoutePatternParameterPart ParameterPartCore( string parameterName, object @default, RoutePatternParameterKind parameterKind, - IEnumerable constraints, + IEnumerable parameterPolicies, bool encodeSlashes) { return new RoutePatternParameterPart( parameterName, @default, parameterKind, - constraints.ToArray(), + parameterPolicies.ToArray(), encodeSlashes); } /// - /// Creates a from the provided object. + /// Creates a from the provided contraint. /// /// - /// The constraint object, which must be of type , - /// , or . If the constraint object - /// is a it will be tranformed into an instance of - /// . + /// The constraint object, which must be of type + /// or . If the constraint object is a + /// then it will be tranformed into an instance of . /// - /// The . - public static RoutePatternConstraintReference Constraint(object constraint) + /// The . + public static RoutePatternParameterPolicyReference Constraint(object constraint) { // Similar to RouteConstraintBuilder - if (constraint is IRouteConstraint routeConstraint) + if (constraint is IRouteConstraint policy) { - return ConstraintCore(routeConstraint); - } - else if (constraint is MatchProcessor matchProcessor) - { - return ConstraintCore(matchProcessor); + return ParameterPolicyCore(policy); } else if (constraint is string content) { - return ConstraintCore(new RegexRouteConstraint("^(" + content + ")$")); + return ParameterPolicyCore(new RegexRouteConstraint("^(" + content + ")$")); } else { throw new InvalidOperationException(Resources.FormatRoutePattern_InvalidConstraintReference( constraint ?? "null", - typeof(IRouteConstraint), - typeof(MatchProcessor))); + typeof(IRouteConstraint))); } } /// - /// Creates a from the provided object. + /// Creates a from the provided constraint. /// /// /// The constraint object. /// - /// The . - public static RoutePatternConstraintReference Constraint(IRouteConstraint constraint) + /// The . + public static RoutePatternParameterPolicyReference Constraint(IRouteConstraint constraint) { if (constraint == null) { throw new ArgumentNullException(nameof(constraint)); } - return ConstraintCore(constraint); + return ParameterPolicyCore(constraint); } /// - /// Creates a from the provided object. - /// - /// - /// The match processor object. - /// - /// The . - public static RoutePatternConstraintReference Constraint(MatchProcessor matchProcessor) - { - if (matchProcessor == null) - { - throw new ArgumentNullException(nameof(matchProcessor)); - } - - return ConstraintCore(matchProcessor); - } - - /// - /// Creates a from the provided object. + /// Creates a from the provided constraint. /// /// - /// The constraint text, which will be tranformed into an instance of - /// . + /// The constraint text, which will be resolved by . /// - /// The . - public static RoutePatternConstraintReference Constraint(string constraint) + /// The . + public static RoutePatternParameterPolicyReference Constraint(string constraint) { if (string.IsNullOrEmpty(constraint)) { throw new ArgumentException(Resources.Argument_NullOrEmpty, nameof(constraint)); } - return ConstraintCore(constraint); + return ParameterPolicyCore(constraint); } - private static RoutePatternConstraintReference ConstraintCore(string constraint) + /// + /// Creates a from the provided object. + /// + /// + /// The parameter policy object. + /// + /// The . + public static RoutePatternParameterPolicyReference ParameterPolicy(IParameterPolicy parameterPolicy) { - return new RoutePatternConstraintReference(constraint); + if (parameterPolicy == null) + { + throw new ArgumentNullException(nameof(parameterPolicy)); + } + + return ParameterPolicyCore(parameterPolicy); } - private static RoutePatternConstraintReference ConstraintCore(IRouteConstraint constraint) + /// + /// Creates a from the provided object. + /// + /// + /// The parameter policy text, which will be resolved by . + /// + /// The . + public static RoutePatternParameterPolicyReference ParameterPolicy(string parameterPolicy) { - return new RoutePatternConstraintReference(constraint); + if (string.IsNullOrEmpty(parameterPolicy)) + { + throw new ArgumentException(Resources.Argument_NullOrEmpty, nameof(parameterPolicy)); + } + + return ParameterPolicyCore(parameterPolicy); } - private static RoutePatternConstraintReference ConstraintCore(MatchProcessor matchProcessor) + private static RoutePatternParameterPolicyReference ParameterPolicyCore(string parameterPolicy) { - return new RoutePatternConstraintReference(matchProcessor); + return new RoutePatternParameterPolicyReference(parameterPolicy); + } + + private static RoutePatternParameterPolicyReference ParameterPolicyCore(IParameterPolicy parameterPolicy) + { + return new RoutePatternParameterPolicyReference(parameterPolicy); } } } diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParameterPart.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParameterPart.cs index df060de9d9..dd6b275fa3 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParameterPart.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParameterPart.cs @@ -18,8 +18,8 @@ namespace Microsoft.AspNetCore.Routing.Patterns string parameterName, object @default, RoutePatternParameterKind parameterKind, - RoutePatternConstraintReference[] constraints) - : this(parameterName, @default, parameterKind, constraints, encodeSlashes: true) + RoutePatternParameterPolicyReference[] parameterPolicies) + : this(parameterName, @default, parameterKind, parameterPolicies, encodeSlashes: true) { } @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns string parameterName, object @default, RoutePatternParameterKind parameterKind, - RoutePatternConstraintReference[] constraints, + RoutePatternParameterPolicyReference[] parameterPolicies, bool encodeSlashes) : base(RoutePatternPartKind.Parameter) { @@ -36,14 +36,14 @@ namespace Microsoft.AspNetCore.Routing.Patterns Name = parameterName; Default = @default; ParameterKind = parameterKind; - Constraints = constraints; + ParameterPolicies = parameterPolicies; EncodeSlashes = encodeSlashes; } /// - /// Gets the list of constraints associated with this parameter. + /// Gets the list of parameter policies associated with this parameter. /// - public IReadOnlyList Constraints { get; } + public IReadOnlyList ParameterPolicies { get; } /// /// Gets the value indicating if slashes in current parameter's value should be encoded. @@ -89,10 +89,10 @@ namespace Microsoft.AspNetCore.Routing.Patterns builder.Append(Name); - foreach (var constraint in Constraints) + foreach (var constraint in ParameterPolicies) { builder.Append(":"); - builder.Append(constraint.Constraint); + builder.Append(constraint.ParameterPolicy); } if (Default != null) diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParameterPolicyReference.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParameterPolicyReference.cs new file mode 100644 index 0000000000..65f58087c1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParameterPolicyReference.cs @@ -0,0 +1,41 @@ +// 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.Diagnostics; +using Microsoft.AspNetCore.Routing.Matching; + +namespace Microsoft.AspNetCore.Routing.Patterns +{ + /// + /// The parsed representation of a policy in a parameter. Instances + /// of are immutable. + /// + [DebuggerDisplay("{DebuggerToString()}")] + public sealed class RoutePatternParameterPolicyReference + { + internal RoutePatternParameterPolicyReference(string content) + { + Content = content; + } + + internal RoutePatternParameterPolicyReference(IParameterPolicy parameterPolicy) + { + ParameterPolicy = parameterPolicy; + } + + /// + /// Gets the constraint text. + /// + public string Content { get; } + + /// + /// Gets a pre-existing that was used to construct this reference. + /// + public IParameterPolicy ParameterPolicy { get; } + + private string DebuggerToString() + { + return Content; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Routing/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Routing/Properties/Resources.Designer.cs index 9623f5c460..47c12ae404 100644 --- a/src/Microsoft.AspNetCore.Routing/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Routing/Properties/Resources.Designer.cs @@ -467,10 +467,10 @@ namespace Microsoft.AspNetCore.Routing } /// - /// Invalid constraint '{0}'. A constraint must be of type 'string', '{1}', or '{2}'. + /// Invalid constraint '{0}'. A constraint must be of type 'string' or '{1}'. /// - internal static string FormatRoutePattern_InvalidConstraintReference(object p0, object p1, object p2) - => string.Format(CultureInfo.CurrentCulture, GetString("RoutePattern_InvalidConstraintReference"), p0, p1, p2); + internal static string FormatRoutePattern_InvalidConstraintReference(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("RoutePattern_InvalidConstraintReference"), p0, p1); /// /// Invalid constraint '{0}' for parameter '{1}'. A constraint must be of type 'string', '{2}', or '{3}'. diff --git a/src/Microsoft.AspNetCore.Routing/Resources.resx b/src/Microsoft.AspNetCore.Routing/Resources.resx index b0a3772b2c..c192330770 100644 --- a/src/Microsoft.AspNetCore.Routing/Resources.resx +++ b/src/Microsoft.AspNetCore.Routing/Resources.resx @@ -214,7 +214,7 @@ The constraint entry '{0}' - '{1}' must have a string value or be of a type which implements '{2}'. - Invalid constraint '{0}'. A constraint must be of type 'string', '{1}', or '{2}'. + Invalid constraint '{0}'. A constraint must be of type 'string' or '{1}'. Invalid constraint '{0}' for parameter '{1}'. A constraint must be of type 'string', '{2}', or '{3}'. diff --git a/src/Microsoft.AspNetCore.Routing/Template/InlineConstraint.cs b/src/Microsoft.AspNetCore.Routing/Template/InlineConstraint.cs index 6b17cf88c5..4d58ce6181 100644 --- a/src/Microsoft.AspNetCore.Routing/Template/InlineConstraint.cs +++ b/src/Microsoft.AspNetCore.Routing/Template/InlineConstraint.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Routing.Template Constraint = constraint; } - public InlineConstraint(RoutePatternConstraintReference other) + public InlineConstraint(RoutePatternParameterPolicyReference other) { if (other == null) { diff --git a/src/Microsoft.AspNetCore.Routing/Template/RoutePrecedence.cs b/src/Microsoft.AspNetCore.Routing/Template/RoutePrecedence.cs index 672ceacfdc..4d7ba66b35 100644 --- a/src/Microsoft.AspNetCore.Routing/Template/RoutePrecedence.cs +++ b/src/Microsoft.AspNetCore.Routing/Template/RoutePrecedence.cs @@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.Routing.Template Debug.Assert(parameterPart != null); var digit = parameterPart.IsCatchAll ? 1 : 3; - if (parameterPart.Constraints.Count > 0) + if (parameterPart.ParameterPolicies.Count > 0) { digit++; } @@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.Routing.Template // If there is a route constraint for the parameter, reduce order by 1 // Constrained parameters end up with order 2, Constrained catch alls end up with order 4 - if (parameterPart.Constraints.Count > 0) + if (parameterPart.ParameterPolicies.Count > 0) { digit--; } diff --git a/src/Microsoft.AspNetCore.Routing/Template/TemplatePart.cs b/src/Microsoft.AspNetCore.Routing/Template/TemplatePart.cs index f42cbfa011..5d84969a9c 100644 --- a/src/Microsoft.AspNetCore.Routing/Template/TemplatePart.cs +++ b/src/Microsoft.AspNetCore.Routing/Template/TemplatePart.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Routing.Template IsCatchAll = parameter.IsCatchAll; IsOptional = parameter.IsOptional; DefaultValue = parameter.Default; - InlineConstraints = parameter.Constraints?.Select(p => new InlineConstraint(p)); + InlineConstraints = parameter.ParameterPolicies?.Select(p => new InlineConstraint(p)); } else if (other.IsSeparator && other is RoutePatternSeparatorPart separator) { @@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Routing.Template RoutePatternParameterKind.Optional : RoutePatternParameterKind.Standard; - var constraints = InlineConstraints.Select(c => new RoutePatternConstraintReference(c.Constraint)); + var constraints = InlineConstraints.Select(c => new RoutePatternParameterPolicyReference(c.Constraint)); return RoutePatternFactory.ParameterPart(Name, DefaultValue, kind, constraints); } } diff --git a/test/Microsoft.AspNetCore.Routing.Tests/CompositeEndpointDataSourceTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/CompositeEndpointDataSourceTest.cs index d04f0d96de..a01ee921de 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/CompositeEndpointDataSourceTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/CompositeEndpointDataSourceTest.cs @@ -154,7 +154,7 @@ namespace Microsoft.AspNetCore.Routing { return new MatcherEndpoint( MatcherEndpoint.EmptyInvoker, - RoutePatternFactory.Parse(template, defaults, constraints: null), + RoutePatternFactory.Parse(template, defaults, parameterPolicies: null), order, EndpointMetadataCollection.Empty, null); diff --git a/test/Microsoft.AspNetCore.Routing.Tests/DefaultLinkGeneratorTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/DefaultLinkGeneratorTest.cs index 1fe785ca8f..33f1807d64 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/DefaultLinkGeneratorTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/DefaultLinkGeneratorTest.cs @@ -1554,7 +1554,7 @@ namespace Microsoft.AspNetCore.Routing var serviceProvider = services.BuildServiceProvider(); return new DefaultLinkGenerator( - new DefaultMatchProcessorFactory(options, serviceProvider), + new DefaultParameterPolicyFactory(options, serviceProvider), new DefaultObjectPool(new UriBuilderContextPooledObjectPolicy()), options, NullLogger.Instance, diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matching/CandidateSetTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matching/CandidateSetTest.cs index ac78dcaf7b..1c5d751af5 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/Matching/CandidateSetTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/Matching/CandidateSetTest.cs @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Routing.Matching { var dataSource = new CompositeEndpointDataSource(Array.Empty()); return new DfaMatcherBuilder( - Mock.Of(), + Mock.Of(), Mock.Of(), policies); } diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultMatchProcessorFactoryTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultMatchProcessorFactoryTest.cs deleted file mode 100644 index acfd78d29f..0000000000 --- a/test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultMatchProcessorFactoryTest.cs +++ /dev/null @@ -1,320 +0,0 @@ -// 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.Globalization; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing.Constraints; -using Microsoft.AspNetCore.Routing.Patterns; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Xunit; - -namespace Microsoft.AspNetCore.Routing.Matching -{ - public class DefaultMatchProcessorFactoryTest - { - [Fact] - public void Create_ThrowsException_IfNoConstraintOrMatchProcessor_FoundInMap() - { - // Arrange - var factory = GetMatchProcessorFactory(); - - // Act - var exception = Assert.Throws( - () => factory.Create("id", @"notpresent(\d+)", optional: false)); - - // Assert - Assert.Equal( - $"The constraint reference 'notpresent' could not be resolved to a type. " + - $"Register the constraint type with '{typeof(RouteOptions)}.{nameof(RouteOptions.ConstraintMap)}'.", - exception.Message); - } - - [Fact] - public void Create_ThrowsException_OnInvalidType() - { - // Arrange - var options = new RouteOptions(); - options.ConstraintMap.Add("bad", typeof(string)); - - var services = new ServiceCollection(); - services.AddTransient(); - - var factory = GetMatchProcessorFactory(options, services); - - // Act - var exception = Assert.Throws( - () => factory.Create("id", @"bad", optional: false)); - - // Assert - Assert.Equal( - $"Invalid constraint type '{typeof(string)}' registered as 'bad'. " + - $"A constraint type must either implement '{typeof(IRouteConstraint)}', or inherit from '{typeof(MatchProcessor)}'.", - exception.Message); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromRoutePattern_String() - { - // Arrange - var factory = GetMatchProcessorFactory(); - - var parameter = RoutePatternFactory.ParameterPart( - "id", - @default: null, - parameterKind: RoutePatternParameterKind.Standard, - constraints: new[] { RoutePatternFactory.Constraint("int"), }); - - // Act - var matchProcessor = factory.Create(parameter, parameter.Constraints[0]); - - // Assert - Assert.IsType(Assert.IsType(matchProcessor).Constraint); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromRoutePattern_String_Optional() - { - // Arrange - var factory = GetMatchProcessorFactory(); - - var parameter = RoutePatternFactory.ParameterPart( - "id", - @default: null, - parameterKind: RoutePatternParameterKind.Optional, - constraints: new[] { RoutePatternFactory.Constraint("int"), }); - - // Act - var matchProcessor = factory.Create(parameter, parameter.Constraints[0]); - - // Assert - Assert.IsType(matchProcessor); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromRoutePattern_Constraint() - { - // Arrange - var factory = GetMatchProcessorFactory(); - - var parameter = RoutePatternFactory.ParameterPart( - "id", - @default: null, - parameterKind: RoutePatternParameterKind.Standard, - constraints: new[] { RoutePatternFactory.Constraint(new IntRouteConstraint()), }); - - // Act - var matchProcessor = factory.Create(parameter, parameter.Constraints[0]); - - // Assert - Assert.IsType(Assert.IsType(matchProcessor).Constraint); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromRoutePattern_Constraint_Optional() - { - // Arrange - var factory = GetMatchProcessorFactory(); - - var parameter = RoutePatternFactory.ParameterPart( - "id", - @default: null, - parameterKind: RoutePatternParameterKind.Optional, - constraints: new[] { RoutePatternFactory.Constraint(new IntRouteConstraint()), }); - - // Act - var matchProcessor = factory.Create(parameter, parameter.Constraints[0]); - - // Assert - Assert.IsType(matchProcessor); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromRoutePattern_MatchProcessor() - { - // Arrange - var factory = GetMatchProcessorFactory(); - - var parameter = RoutePatternFactory.ParameterPart( - "id", - @default: null, - parameterKind: RoutePatternParameterKind.Standard, - constraints: new[] { RoutePatternFactory.Constraint(new EndsWithStringMatchProcessor()), }); - - // Act - var matchProcessor = factory.Create(parameter, parameter.Constraints[0]); - - // Assert - Assert.IsType(matchProcessor); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromRoutePattern_MatchProcessor_Optional() - { - // Arrange - var factory = GetMatchProcessorFactory(); - - var parameter = RoutePatternFactory.ParameterPart( - "id", - @default: null, - parameterKind: RoutePatternParameterKind.Optional, - constraints: new[] { RoutePatternFactory.Constraint(new EndsWithStringMatchProcessor()), }); - - // Act - var matchProcessor = factory.Create(parameter, parameter.Constraints[0]); - - // Assert - Assert.IsType(matchProcessor); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromConstraintText_AndRouteConstraint() - { - // Arrange - var factory = GetMatchProcessorFactory(); - - // Act - var matchProcessor = factory.Create("id", "int", optional: false); - - // Assert - Assert.IsType(Assert.IsType(matchProcessor).Constraint); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromConstraintText_AndRouteConstraint_Optional() - { - // Arrange - var factory = GetMatchProcessorFactory(); - - // Act - var matchProcessor = factory.Create("id", "int", optional: true); - - // Assert - Assert.IsType(matchProcessor); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromConstraintText_AndMatchProcesor() - { - // Arrange - var options = new RouteOptions(); - options.ConstraintMap.Add("endsWith", typeof(EndsWithStringMatchProcessor)); - - var services = new ServiceCollection(); - services.AddTransient(); - - var factory = GetMatchProcessorFactory(options, services); - - // Act - var matchProcessor = factory.Create("id", "endsWith", optional: false); - - // Assert - Assert.IsType(matchProcessor); - } - - [Fact] - public void Create_CreatesMatchProcessor_FromConstraintText_AndMatchProcessor_Optional() - { - // Arrange - var options = new RouteOptions(); - options.ConstraintMap.Add("endsWith", typeof(EndsWithStringMatchProcessor)); - - var services = new ServiceCollection(); - services.AddTransient(); - - var factory = GetMatchProcessorFactory(options, services); - - // Act - var matchProcessor = factory.Create("id", "endsWith", optional: true); - - // Assert - Assert.IsType(matchProcessor); - } - - private DefaultMatchProcessorFactory GetMatchProcessorFactory( - RouteOptions options = null, - ServiceCollection services = null) - { - if (options == null) - { - options = new RouteOptions(); - } - - if (services == null) - { - services = new ServiceCollection(); - } - - return new DefaultMatchProcessorFactory( - Options.Create(options), - services.BuildServiceProvider()); - } - - private class TestRouteConstraint : IRouteConstraint - { - private TestRouteConstraint() { } - - public HttpContext HttpContext { get; private set; } - public IRouter Route { get; private set; } - public string RouteKey { get; private set; } - public RouteValueDictionary Values { get; private set; } - public RouteDirection RouteDirection { get; private set; } - - public static TestRouteConstraint Create() - { - return new TestRouteConstraint(); - } - - public bool Match( - HttpContext httpContext, - IRouter route, - string routeKey, - RouteValueDictionary values, - RouteDirection routeDirection) - { - HttpContext = httpContext; - Route = route; - RouteKey = routeKey; - Values = values; - RouteDirection = routeDirection; - return false; - } - } - - private class EndsWithStringMatchProcessor : MatchProcessor - { - public string ParameterName { get; private set; } - - public string ConstraintArgument { get; private set; } - - public override void Initialize(string parameterName, string constraintArgument) - { - ParameterName = parameterName; - ConstraintArgument = constraintArgument; - } - - public override bool ProcessInbound(HttpContext httpContext, RouteValueDictionary values) - { - return Process(values); - } - - public override bool ProcessOutbound(HttpContext httpContext, RouteValueDictionary values) - { - return Process(values); - } - - private bool Process(RouteValueDictionary values) - { - if (!values.TryGetValue(ParameterName, out var value) || value == null) - { - return false; - } - - var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); - var endsWith = valueString.EndsWith(ConstraintArgument, StringComparison.OrdinalIgnoreCase); - return endsWith; - } - } - } -} diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultParameterPolicyFactoryTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultParameterPolicyFactoryTest.cs new file mode 100644 index 0000000000..abfb7bde3a --- /dev/null +++ b/test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultParameterPolicyFactoryTest.cs @@ -0,0 +1,272 @@ +// 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.Globalization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing.Constraints; +using Microsoft.AspNetCore.Routing.Patterns; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Xunit; + +namespace Microsoft.AspNetCore.Routing.Matching +{ + public class DefaultParameterPolicyFactoryTest + { + [Fact] + public void Create_ThrowsException_IfNoConstraintOrParameterPolicy_FoundInMap() + { + // Arrange + var factory = GetParameterPolicyFactory(); + + // Act + var exception = Assert.Throws( + () => factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), @"notpresent(\d+)")); + + // Assert + Assert.Equal( + $"The constraint reference 'notpresent' could not be resolved to a type. " + + $"Register the constraint type with '{typeof(RouteOptions)}.{nameof(RouteOptions.ConstraintMap)}'.", + exception.Message); + } + + [Fact] + public void Create_ThrowsException_OnInvalidType() + { + // Arrange + var options = new RouteOptions(); + options.ConstraintMap.Add("bad", typeof(string)); + + var services = new ServiceCollection(); + + var factory = GetParameterPolicyFactory(options, services); + + // Act + var exception = Assert.Throws( + () => factory.Create(RoutePatternFactory.ParameterPart("id"), @"bad")); + + // Assert + Assert.Equal( + $"Invalid constraint type '{typeof(string)}' registered as 'bad'. " + + $"A constraint type must either implement '{typeof(IRouteConstraint)}', or inherit from '{typeof(IParameterPolicy)}'.", + exception.Message); + } + + [Fact] + public void Create_CreatesParameterPolicy_FromRoutePattern_String() + { + // Arrange + var factory = GetParameterPolicyFactory(); + + var parameter = RoutePatternFactory.ParameterPart( + "id", + @default: null, + parameterKind: RoutePatternParameterKind.Standard, + parameterPolicies: new[] { RoutePatternFactory.Constraint("int"), }); + + // Act + var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]); + + // Assert + Assert.IsType(parameterPolicy); + } + + [Fact] + public void Create_CreatesParameterPolicy_FromRoutePattern_String_Optional() + { + // Arrange + var factory = GetParameterPolicyFactory(); + + var parameter = RoutePatternFactory.ParameterPart( + "id", + @default: null, + parameterKind: RoutePatternParameterKind.Optional, + parameterPolicies: new[] { RoutePatternFactory.Constraint("int"), }); + + // Act + var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]); + + // Assert + var optionalConstraint = Assert.IsType(parameterPolicy); + Assert.IsType(optionalConstraint.InnerConstraint); + } + + [Fact] + public void Create_CreatesParameterPolicy_FromRoutePattern_Constraint() + { + // Arrange + var factory = GetParameterPolicyFactory(); + + var parameter = RoutePatternFactory.ParameterPart( + "id", + @default: null, + parameterKind: RoutePatternParameterKind.Standard, + parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new IntRouteConstraint()), }); + + // Act + var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]); + + // Assert + Assert.IsType(parameterPolicy); + } + + [Fact] + public void Create_CreatesParameterPolicy_FromRoutePattern_Constraint_Optional() + { + // Arrange + var factory = GetParameterPolicyFactory(); + + var parameter = RoutePatternFactory.ParameterPart( + "id", + @default: null, + parameterKind: RoutePatternParameterKind.Optional, + parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new IntRouteConstraint()), }); + + // Act + var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]); + + // Assert + var optionalConstraint = Assert.IsType(parameterPolicy); + Assert.IsType(optionalConstraint.InnerConstraint); + } + + [Fact] + public void Create_CreatesParameterPolicy_FromRoutePattern_ParameterPolicy() + { + // Arrange + var factory = GetParameterPolicyFactory(); + + var parameter = RoutePatternFactory.ParameterPart( + "id", + @default: null, + parameterKind: RoutePatternParameterKind.Standard, + parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new CustomParameterPolicy()), }); + + // Act + var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]); + + // Assert + Assert.IsType(parameterPolicy); + } + + private class CustomParameterPolicy : IParameterPolicy + { + } + + [Fact] + public void Create_CreatesParameterPolicy_FromConstraintText_AndRouteConstraint() + { + // Arrange + var factory = GetParameterPolicyFactory(); + + // Act + var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "int"); + + // Assert + Assert.IsType(parameterPolicy); + } + + [Fact] + public void Create_CreatesParameterPolicy_FromConstraintText_AndRouteConstraint_Optional() + { + // Arrange + var factory = GetParameterPolicyFactory(); + + // Act + var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "int"); + + // Assert + var optionalConstraint = Assert.IsType(parameterPolicy); + Assert.IsType(optionalConstraint.InnerConstraint); + } + + [Fact] + public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicy() + { + // Arrange + var options = new RouteOptions(); + options.ConstraintMap.Add("customParameterPolicy", typeof(CustomParameterPolicy)); + + var services = new ServiceCollection(); + services.AddTransient(); + + var factory = GetParameterPolicyFactory(options, services); + + // Act + var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "customParameterPolicy"); + + // Assert + Assert.IsType(parameterPolicy); + } + + [Fact] + public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicy_Optional() + { + // Arrange + var options = new RouteOptions(); + options.ConstraintMap.Add("customParameterPolicy", typeof(CustomParameterPolicy)); + + var services = new ServiceCollection(); + services.AddTransient(); + + var factory = GetParameterPolicyFactory(options, services); + + // Act + var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "customParameterPolicy"); + + // Assert + Assert.IsType(parameterPolicy); + } + + private DefaultParameterPolicyFactory GetParameterPolicyFactory( + RouteOptions options = null, + ServiceCollection services = null) + { + if (options == null) + { + options = new RouteOptions(); + } + + if (services == null) + { + services = new ServiceCollection(); + } + + return new DefaultParameterPolicyFactory( + Options.Create(options), + services.BuildServiceProvider()); + } + + private class TestRouteConstraint : IRouteConstraint + { + private TestRouteConstraint() { } + + public HttpContext HttpContext { get; private set; } + public IRouter Route { get; private set; } + public string RouteKey { get; private set; } + public RouteValueDictionary Values { get; private set; } + public RouteDirection RouteDirection { get; private set; } + + public static TestRouteConstraint Create() + { + return new TestRouteConstraint(); + } + + public bool Match( + HttpContext httpContext, + IRouter route, + string routeKey, + RouteValueDictionary values, + RouteDirection routeDirection) + { + HttpContext = httpContext; + Route = route; + RouteKey = routeKey; + Values = values; + RouteDirection = routeDirection; + return false; + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matching/DfaMatcherBuilderTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matching/DfaMatcherBuilderTest.cs index a8735c02fa..f9581a067b 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/Matching/DfaMatcherBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/Matching/DfaMatcherBuilderTest.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Routing.Constraints; using Microsoft.AspNetCore.Routing.Patterns; +using Microsoft.Extensions.Options; using Moq; using Xunit; @@ -641,7 +642,7 @@ namespace Microsoft.AspNetCore.Routing.Matching Assert.Empty(candidate.Captures); Assert.Equal(default, candidate.CatchAll); Assert.Empty(candidate.ComplexSegments); - Assert.Empty(candidate.MatchProcessors); + Assert.Empty(candidate.Constraints); } [Fact] @@ -665,7 +666,7 @@ namespace Microsoft.AspNetCore.Routing.Matching c => Assert.Equal(("c", 2, 2), c)); Assert.Equal(default, candidate.CatchAll); Assert.Empty(candidate.ComplexSegments); - Assert.Empty(candidate.MatchProcessors); + Assert.Empty(candidate.Constraints); } [Fact] @@ -695,7 +696,7 @@ namespace Microsoft.AspNetCore.Routing.Matching c => Assert.Equal(("c", 2, 2), c)); Assert.Equal(default, candidate.CatchAll); Assert.Empty(candidate.ComplexSegments); - Assert.Empty(candidate.MatchProcessors); + Assert.Empty(candidate.Constraints); } [Fact] @@ -726,7 +727,7 @@ namespace Microsoft.AspNetCore.Routing.Matching c => Assert.Equal(("b", 1, 2), c)); Assert.Equal(("c", 2, 0), candidate.CatchAll); Assert.Empty(candidate.ComplexSegments); - Assert.Empty(candidate.MatchProcessors); + Assert.Empty(candidate.Constraints); } // Defaults are processed first, which affects the slot ordering. @@ -758,7 +759,7 @@ namespace Microsoft.AspNetCore.Routing.Matching c => Assert.Equal(("c", 2, 2), c)); Assert.Equal(default, candidate.CatchAll); Assert.Empty(candidate.ComplexSegments); - Assert.Empty(candidate.MatchProcessors); + Assert.Empty(candidate.Constraints); } [Fact] @@ -789,11 +790,11 @@ namespace Microsoft.AspNetCore.Routing.Matching Assert.Collection( candidate.ComplexSegments, s => Assert.Equal(0, s.segmentIndex)); - Assert.Empty(candidate.MatchProcessors); + Assert.Empty(candidate.Constraints); } [Fact] - public void CreateCandidate_MatchProcessors() + public void CreateCandidate_RouteConstraints() { // Arrange var endpoint = CreateEndpoint("/a/b/c", constraints: new { a = new IntRouteConstraint(), }); @@ -804,14 +805,38 @@ namespace Microsoft.AspNetCore.Routing.Matching var candidate = builder.CreateCandidate(endpoint, score: 0); // Assert - Assert.Equal( Candidate.CandidateFlags.HasMatchProcessors, candidate.Flags); + Assert.Equal(Candidate.CandidateFlags.HasConstraints, candidate.Flags); Assert.Empty(candidate.Slots); Assert.Empty(candidate.Captures); Assert.Equal(default, candidate.CatchAll); Assert.Empty(candidate.ComplexSegments); - Assert.Single(candidate.MatchProcessors); + Assert.Single(candidate.Constraints); } - + + [Fact] + public void CreateCandidate_CustomParameterPolicy() + { + // Arrange + var endpoint = CreateEndpoint("/a/b/c", constraints: new { a = new CustomParameterPolicy(), }); + + var builder = CreateDfaMatcherBuilder(); + + // Act + var candidate = builder.CreateCandidate(endpoint, score: 0); + + // 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.Constraints); + } + + private class CustomParameterPolicy : IParameterPolicy + { + } + [Fact] public void CreateCandidates_CreatesScoresCorrectly() { @@ -846,7 +871,7 @@ namespace Microsoft.AspNetCore.Routing.Matching { var dataSource = new CompositeEndpointDataSource(Array.Empty()); return new DfaMatcherBuilder( - Mock.Of(), + new DefaultParameterPolicyFactory(Options.Create(new RouteOptions()), Mock.Of()), Mock.Of(), policies); } diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matching/DfaMatcherTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matching/DfaMatcherTest.cs index b77650deda..1fcd86f89c 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/Matching/DfaMatcherTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/Matching/DfaMatcherTest.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing.Matching { return new MatcherEndpoint( MatcherEndpoint.EmptyInvoker, - RoutePatternFactory.Parse(template, defaults, constraints: null), + RoutePatternFactory.Parse(template, defaults, parameterPolicies: null), order, metadata ?? EndpointMetadataCollection.Empty, template); diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matching/RouteConstraintMatchProcessorTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matching/RouteConstraintMatchProcessorTest.cs deleted file mode 100644 index 915b483234..0000000000 --- a/test/Microsoft.AspNetCore.Routing.Tests/Matching/RouteConstraintMatchProcessorTest.cs +++ /dev/null @@ -1,62 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; -using Moq; -using Xunit; - -namespace Microsoft.AspNetCore.Routing.Matching -{ - public class RouteConstraintMatchProcessorTest - { - [Fact] - public void MatchInbound_CallsRouteConstraint() - { - // Arrange - var constraint = new Mock(); - constraint - .Setup(c => c.Match( - It.IsAny(), - NullRouter.Instance, - "test", - It.IsAny(), - RouteDirection.IncomingRequest)) - .Returns(true) - .Verifiable(); - - var matchProcessor = new RouteConstraintMatchProcessor("test", constraint.Object); - - // Act - var result = matchProcessor.ProcessInbound(new DefaultHttpContext(), new RouteValueDictionary()); - - // Assert - Assert.True(result); - constraint.Verify(); - } - - [Fact] - public void MatchOutput_CallsRouteConstraint() - { - // Arrange - var constraint = new Mock(); - constraint - .Setup(c => c.Match( - It.IsAny(), - NullRouter.Instance, - "test", - It.IsAny(), - RouteDirection.UrlGeneration)) - .Returns(true) - .Verifiable(); - - var matchProcessor = new RouteConstraintMatchProcessor("test", constraint.Object); - - // Act - var result = matchProcessor.ProcessOutbound(new DefaultHttpContext(), new RouteValueDictionary()); - - // Assert - Assert.True(result); - constraint.Verify(); - } - } -} diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Patterns/InlineRouteParameterParserTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Patterns/InlineRouteParameterParserTest.cs index 0056b1c534..1a4b5dddb8 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/Patterns/InlineRouteParameterParserTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/Patterns/InlineRouteParameterParserTest.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal(parameterName, templatePart.Name); Assert.Null(templatePart.Default); - Assert.Empty(templatePart.Constraints); + Assert.Empty(templatePart.ParameterPolicies); } [Fact] @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); Assert.Equal("", templatePart.Default); - Assert.Empty(templatePart.Constraints); + Assert.Empty(templatePart.ParameterPolicies); } [Fact] @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); Assert.Null(templatePart.Default); - Assert.Empty(templatePart.Constraints); + Assert.Empty(templatePart.ParameterPolicies); } [Fact] @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); Assert.Equal("", templatePart.Default); - Assert.Empty(templatePart.Constraints); + Assert.Empty(templatePart.ParameterPolicies); } [Fact] @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); Assert.Equal(":", templatePart.Default); - Assert.Empty(templatePart.Constraints); + Assert.Empty(templatePart.ParameterPolicies); } [Fact] @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.Equal("111111", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("int", constraint.Content); } @@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.Equal("111111", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\d+)", constraint.Content); } @@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.True(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("int", constraint.Content); } @@ -124,7 +124,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("12", templatePart.Default); Assert.True(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("int", constraint.Content); } @@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("12?", templatePart.Default); Assert.True(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("int", constraint.Content); } @@ -153,7 +153,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.True(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\d+)", constraint.Content); } @@ -169,7 +169,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("abc", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\d+)", constraint.Content); } @@ -182,7 +182,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - Assert.Collection(templatePart.Constraints, + Assert.Collection(templatePart.ParameterPolicies, constraint => Assert.Equal(@"test(d+)", constraint.Content), constraint => Assert.Equal(@"test(w+)", constraint.Content)); } @@ -197,7 +197,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.Collection( - templatePart.Constraints, + templatePart.ParameterPolicies, constraint => Assert.Equal(@"test(d+)", constraint.Content), constraint => Assert.Equal(@"test(w+)", constraint.Content)); } @@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - Assert.Collection(templatePart.Constraints, + Assert.Collection(templatePart.ParameterPolicies, constraint => Assert.Equal(@"test(\d+)", constraint.Content), constraint => Assert.Equal(@"test(\w:+)", constraint.Content)); } @@ -227,7 +227,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("qwer", templatePart.Default); - Assert.Collection(templatePart.Constraints, + Assert.Collection(templatePart.ParameterPolicies, constraint => Assert.Equal(@"test(\d+)", constraint.Content), constraint => Assert.Equal(@"test(\w+)", constraint.Content)); } @@ -244,7 +244,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("=qwer", templatePart.Default); Assert.Collection( - templatePart.Constraints, + templatePart.ParameterPolicies, constraint => Assert.Equal(@"test(\d+)", constraint.Content), constraint => Assert.Equal(@"test(\w+)", constraint.Content)); } @@ -262,7 +262,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("comparison-operator", templatePart.Name); Assert.Equal(defaultValue, templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("length(6)", constraint.Content); } @@ -280,7 +280,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("hello", param1.Default); Assert.False(param1.IsOptional); - Assert.Collection(param1.Constraints, + Assert.Collection(param1.ParameterPolicies, constraint => Assert.Equal("int", constraint.Content), constraint => Assert.Equal("test(3)", constraint.Content) ); @@ -325,7 +325,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\})", constraint.Content); } @@ -340,7 +340,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("wer", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\})", constraint.Content); } @@ -353,7 +353,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\))", constraint.Content); } @@ -368,7 +368,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("fsd", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\))", constraint.Content); } @@ -381,7 +381,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(:)", constraint.Content); } @@ -396,7 +396,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("mnf", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(:)", constraint.Content); } @@ -409,7 +409,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(a:b:c)", constraint.Content); } @@ -424,7 +424,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("12", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("test", constraint.Content); } @@ -440,7 +440,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("12", templatePart.Default); Assert.Collection( - templatePart.Constraints, + templatePart.ParameterPolicies, constraint => Assert.Equal("test", constraint.Content)); } @@ -454,7 +454,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal(":param", templatePart.Name); Assert.Collection( - templatePart.Constraints, + templatePart.ParameterPolicies, constraint => Assert.Equal("test", constraint.Content)); } @@ -467,7 +467,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\w,\w)", constraint.Content); } @@ -480,7 +480,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("par,am", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\w)", constraint.Content); } @@ -495,7 +495,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("jsd", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\w,\w)", constraint.Content); } @@ -511,7 +511,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.True(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("int", constraint.Content); } @@ -525,7 +525,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.Null(templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("test(=)", constraint.Content); } @@ -550,7 +550,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.Null(templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("test(a==b)", constraint.Content); } @@ -564,7 +564,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.Equal("dvds", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("test(a==b)", constraint.Content); } @@ -622,7 +622,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.Equal("sds", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("test(=)", constraint.Content); } @@ -635,7 +635,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\{)", constraint.Content); } @@ -648,7 +648,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("par{am", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\sd)", constraint.Content); } @@ -663,7 +663,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("xvc", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\{)", constraint.Content); } @@ -676,7 +676,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("par(am", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\()", constraint.Content); } @@ -689,7 +689,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\()", constraint.Content); } @@ -702,7 +702,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal("test(#$%", constraint.Content); } @@ -715,7 +715,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal("param", templatePart.Name); - Assert.Collection(templatePart.Constraints, + Assert.Collection(templatePart.ParameterPolicies, constraint => Assert.Equal(@"test(#", constraint.Content), constraint => Assert.Equal(@"test1", constraint.Content)); } @@ -730,7 +730,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.Equal("default-value", templatePart.Default); - Assert.Collection(templatePart.Constraints, + Assert.Collection(templatePart.ParameterPolicies, constraint => Assert.Equal(@"test(abc:somevalue)", constraint.Content), constraint => Assert.Equal(@"name(test1", constraint.Content), constraint => Assert.Equal(@"differentname", constraint.Content)); @@ -746,7 +746,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("param", templatePart.Name); Assert.Equal("test1", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(constraintvalue", constraint.Content); } @@ -761,7 +761,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("djk", templatePart.Default); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\()", constraint.Content); } @@ -776,7 +776,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Null(templatePart.Default); Assert.False(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\?)", constraint.Content); } @@ -791,7 +791,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Null(templatePart.Default); Assert.True(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\?)", constraint.Content); } @@ -806,7 +806,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("sdf", templatePart.Default); Assert.False(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\?)", constraint.Content); } @@ -821,7 +821,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("sdf", templatePart.Default); Assert.True(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\?)", constraint.Content); } @@ -836,7 +836,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Null(templatePart.Default); Assert.False(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(\?)", constraint.Content); } @@ -851,7 +851,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Null(templatePart.Default); Assert.False(templatePart.IsOptional); - Assert.Collection(templatePart.Constraints, + Assert.Collection(templatePart.ParameterPolicies, constraint => Assert.Equal(@"test(#)", constraint.Content), constraint => Assert.Equal(@"$)", constraint.Content)); } @@ -867,7 +867,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Null(templatePart.Default); Assert.False(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"test(#:)$)", constraint.Content); } @@ -882,7 +882,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Null(templatePart.Default); Assert.False(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"regex(\\(\\(\\(\\()", constraint.Content); } @@ -897,7 +897,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Null(templatePart.Default); Assert.False(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"regex(^\d{{3}}-\d{{3}}-\d{{4}}$)", constraint.Content); } @@ -912,7 +912,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("123-456-7890", templatePart.Default); Assert.False(templatePart.IsOptional); - var constraint = Assert.Single(templatePart.Constraints); + var constraint = Assert.Single(templatePart.ParameterPolicies); Assert.Equal(@"regex(^\d{{3}}-\d{{3}}-\d{{4}}$)", constraint.Content); } @@ -934,7 +934,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal(expectedParameterName, templatePart.Name); - Assert.Empty(templatePart.Constraints); + Assert.Empty(templatePart.ParameterPolicies); Assert.Null(templatePart.Default); } @@ -979,7 +979,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("path", parameterPart.Name); Assert.True(parameterPart.IsCatchAll); Assert.Equal(RoutePatternParameterKind.CatchAll, parameterPart.ParameterKind); - var constraintReference = Assert.Single(parameterPart.Constraints); + var constraintReference = Assert.Single(parameterPart.ParameterPolicies); Assert.Equal(constraintContent, constraintReference.Content); Assert.True(parameterPart.EncodeSlashes); } @@ -997,7 +997,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("path", parameterPart.Name); Assert.True(parameterPart.IsCatchAll); Assert.Equal(RoutePatternParameterKind.CatchAll, parameterPart.ParameterKind); - var constraintReference = Assert.Single(parameterPart.Constraints); + var constraintReference = Assert.Single(parameterPart.ParameterPolicies); Assert.Equal(constraintContent, constraintReference.Content); Assert.NotNull(parameterPart.Default); Assert.Equal("a/b/c", parameterPart.Default.ToString()); @@ -1043,7 +1043,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("path", parameterPart.Name); Assert.True(parameterPart.IsCatchAll); Assert.False(parameterPart.EncodeSlashes); - var constraintReference = Assert.Single(parameterPart.Constraints); + var constraintReference = Assert.Single(parameterPart.ParameterPolicies); Assert.Equal(constraintContent, constraintReference.Content); } @@ -1060,7 +1060,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("path", parameterPart.Name); Assert.True(parameterPart.IsCatchAll); Assert.False(parameterPart.EncodeSlashes); - var constraintReference = Assert.Single(parameterPart.Constraints); + var constraintReference = Assert.Single(parameterPart.ParameterPolicies); Assert.Equal(constraintContent, constraintReference.Content); Assert.NotNull(parameterPart.Default); Assert.Equal("a/b/c", parameterPart.Default.ToString()); diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Patterns/RoutePatternFactoryTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Patterns/RoutePatternFactoryTest.cs index ad985e17a2..562d081d10 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/Patterns/RoutePatternFactoryTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/Patterns/RoutePatternFactoryTest.cs @@ -132,21 +132,21 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Collection( - actual.GetParameter("a").Constraints, - c => Assert.IsType(c.Constraint), + actual.GetParameter("a").ParameterPolicies, + c => Assert.IsType(c.ParameterPolicy), c => Assert.Equal("int", c.Content)); Assert.Collection( - actual.GetParameter("b").Constraints, - c => Assert.IsType(c.Constraint)); + actual.GetParameter("b").ParameterPolicies, + c => Assert.IsType(c.ParameterPolicy)); Assert.Collection( - actual.Constraints.OrderBy(kvp => kvp.Key), + actual.ParameterPolicies.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("a", kvp.Key); Assert.Collection( kvp.Value, - c => Assert.IsType(c.Constraint), + c => Assert.IsType(c.ParameterPolicy), c => Assert.Equal("int", c.Content)); }, kvp => @@ -154,7 +154,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns Assert.Equal("b", kvp.Key); Assert.Collection( kvp.Value, - c => Assert.IsType(c.Constraint)); + c => Assert.IsType(c.ParameterPolicy)); }); } @@ -177,30 +177,30 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Collection( - actual.Constraints.OrderBy(kvp => kvp.Key), + actual.ParameterPolicies.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); Assert.Collection( kvp.Value, - c => Assert.IsType(c.Constraint)); + c => Assert.IsType(c.ParameterPolicy)); }, kvp => { Assert.Equal("e", kvp.Key); Assert.Collection( kvp.Value, - c => Assert.IsType(c.Constraint)); + c => Assert.IsType(c.ParameterPolicy)); }); } [Fact] - public void Pattern_ExtraConstraints_MatchProcessor() + public void Pattern_ExtraConstraints_RouteConstraint() { // Arrange var template = "{a}/{b}/{c}"; var defaults = new { }; - var constraints = new { d = Mock.Of(), e = Mock.Of(), }; + var constraints = new { d = Mock.Of(), e = Mock.Of(), }; var original = RoutePatternFactory.Parse(template); @@ -213,20 +213,20 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Collection( - actual.Constraints.OrderBy(kvp => kvp.Key), + actual.ParameterPolicies.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); Assert.Collection( kvp.Value, - c => Assert.NotNull(c.MatchProcessor)); + c => Assert.NotNull(c.ParameterPolicy)); }, kvp => { Assert.Equal("e", kvp.Key); Assert.Collection( kvp.Value, - c => Assert.NotNull(c.MatchProcessor)); + c => Assert.NotNull(c.ParameterPolicy)); }); } @@ -249,11 +249,11 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Collection( - actual.Constraints.OrderBy(kvp => kvp.Key), + actual.ParameterPolicies.OrderBy(kvp => kvp.Key), kvp => { Assert.Equal("d", kvp.Key); - var regex = Assert.IsType(Assert.Single(kvp.Value).Constraint); + var regex = Assert.IsType(Assert.Single(kvp.Value).ParameterPolicy); Assert.Equal("^(foo)$", regex.Constraint.ToString()); }); } @@ -277,7 +277,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns // Assert Assert.Equal( - $"Invalid constraint '17'. A constraint must be of type 'string', '{typeof(IRouteConstraint)}', or '{typeof(MatchProcessor)}'.", + $"Invalid constraint '17'. A constraint must be of type 'string' or '{typeof(IRouteConstraint)}'.", ex.Message); } } diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Patterns/RoutePatternParserTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Patterns/RoutePatternParserTest.cs index 0dfc68d072..1a1f131091 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/Patterns/RoutePatternParserTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/Patterns/RoutePatternParserTest.cs @@ -641,7 +641,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns private class RoutePatternEqualityComparer : IEqualityComparer, - IEqualityComparer + IEqualityComparer { public bool Equals(RoutePattern x, RoutePattern y) { @@ -733,15 +733,15 @@ namespace Microsoft.AspNetCore.Routing.Patterns x.Name == y.Name && x.Default == y.Default && x.ParameterKind == y.ParameterKind && - Enumerable.SequenceEqual(x.Constraints, y.Constraints, this); + Enumerable.SequenceEqual(x.ParameterPolicies, y.ParameterPolicies, this); } - public bool Equals(RoutePatternConstraintReference x, RoutePatternConstraintReference y) + public bool Equals(RoutePatternParameterPolicyReference x, RoutePatternParameterPolicyReference y) { return x.Content == y.Content && - x.Constraint == y.Constraint; + x.ParameterPolicy == y.ParameterPolicy; } private bool Equals(RoutePatternSeparatorPart x, RoutePatternSeparatorPart y) @@ -754,7 +754,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns throw new NotImplementedException(); } - public int GetHashCode(RoutePatternConstraintReference obj) + public int GetHashCode(RoutePatternParameterPolicyReference obj) { throw new NotImplementedException(); } diff --git a/test/Microsoft.AspNetCore.Routing.Tests/RouteValueBasedEndpointFinderTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/RouteValueBasedEndpointFinderTest.cs index 25ce04bf82..60712a0fe7 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/RouteValueBasedEndpointFinderTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/RouteValueBasedEndpointFinderTest.cs @@ -251,7 +251,7 @@ namespace Microsoft.AspNetCore.Routing return new MatcherEndpoint( MatcherEndpoint.EmptyInvoker, - RoutePatternFactory.Parse(template, defaults, constraints: null), + RoutePatternFactory.Parse(template, defaults, parameterPolicies: null), order, metadataCollection, null);