Merge branch 'merge/release/2.2-to-master'
This commit is contained in:
commit
a15f213e43
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<EndsWithStringMatchProcessor> _logger;
|
||||
|
||||
public EndsWithStringMatchProcessor(ILogger<EndsWithStringMatchProcessor> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,11 +21,11 @@ namespace RoutingSample.Web
|
|||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<EndsWithStringMatchProcessor>();
|
||||
services.AddTransient<EndsWithStringRouteConstraint>();
|
||||
|
||||
services.AddRouting(options =>
|
||||
{
|
||||
options.ConstraintMap.Add("endsWith", typeof(EndsWithStringMatchProcessor));
|
||||
options.ConstraintMap.Add("endsWith", typeof(EndsWithStringRouteConstraint));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// A marker interface for types that are associated with route parameters.
|
||||
/// </summary>
|
||||
public interface IParameterPolicy
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
/// </summary>
|
||||
public interface IRouteConstraint
|
||||
public interface IRouteConstraint : IParameterPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the URL parameter contains a valid value for this constraint.
|
||||
|
|
|
|||
|
|
@ -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<UriBuildingContext> _uriBuildingContextPool;
|
||||
private readonly ILogger<DefaultLinkGenerator> _logger;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly RouteOptions _options;
|
||||
|
||||
public DefaultLinkGenerator(
|
||||
MatchProcessorFactory matchProcessorFactory,
|
||||
ParameterPolicyFactory parameterPolicyFactory,
|
||||
ObjectPool<UriBuildingContext> uriBuildingContextPool,
|
||||
IOptions<RouteOptions> routeOptions,
|
||||
ILogger<DefaultLinkGenerator> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<RouteOptions> 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)
|
||||
|
|
@ -68,7 +68,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
//
|
||||
// Default matcher implementation
|
||||
//
|
||||
services.TryAddSingleton<MatchProcessorFactory, DefaultMatchProcessorFactory>();
|
||||
services.TryAddSingleton<ParameterPolicyFactory, DefaultParameterPolicyFactory>();
|
||||
services.TryAddSingleton<MatcherFactory, DfaMatcherFactory>();
|
||||
services.TryAddTransient<DfaMatcherBuilder>();
|
||||
services.TryAddSingleton<DfaGraphWriter>();
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
// RouteValueDictionary.
|
||||
public readonly (RoutePatternPathSegment pathSegment, int segmentIndex)[] ComplexSegments;
|
||||
|
||||
public readonly MatchProcessor[] MatchProcessors;
|
||||
public readonly KeyValuePair<string, IRouteConstraint>[] 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<MatchProcessor>();
|
||||
Constraints = Array.Empty<KeyValuePair<string, IRouteConstraint>>();
|
||||
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<string, IRouteConstraint>[] 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string, IRouteConstraint>[] 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,18 +12,18 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
{
|
||||
private readonly List<MatcherEndpoint> _endpoints = new List<MatcherEndpoint>();
|
||||
|
||||
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<MatcherPolicy> 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<MatchProcessor>();
|
||||
foreach (var kvp in endpoint.RoutePattern.Constraints)
|
||||
var constraints = new List<KeyValuePair<string, IRouteConstraint>>();
|
||||
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<string, IRouteConstraint>(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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an abstraction for resolving inline parameter policies as instances of <see cref="IParameterPolicy"/>.
|
||||
/// </summary>
|
||||
public abstract class ParameterPolicyFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a parameter policy.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The parameter the parameter policy is being created for.</param>
|
||||
/// <param name="inlineText">The inline text to resolve.</param>
|
||||
/// <returns>The <see cref="IParameterPolicy"/> for the parameter.</returns>
|
||||
public abstract IParameterPolicy Create(RoutePatternParameterPart parameter, string inlineText);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a parameter policy.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The parameter the parameter policy is being created for.</param>
|
||||
/// <param name="parameterPolicy">An existing parameter policy.</param>
|
||||
/// <returns>The <see cref="IParameterPolicy"/> for the parameter.</returns>
|
||||
public abstract IParameterPolicy Create(RoutePatternParameterPart parameter, IParameterPolicy parameterPolicy);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a parameter policy.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The parameter the parameter policy is being created for.</param>
|
||||
/// <param name="reference">The reference to resolve.</param>
|
||||
/// <returns>The <see cref="IParameterPolicy"/> for the parameter.</returns>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
|
||||
if (parameter.Length == 0)
|
||||
{
|
||||
return new RoutePatternParameterPart(string.Empty, null, RoutePatternParameterKind.Standard, Array.Empty<RoutePatternConstraintReference>());
|
||||
return new RoutePatternParameterPart(string.Empty, null, RoutePatternParameterKind.Standard, Array.Empty<RoutePatternParameterPolicyReference>());
|
||||
}
|
||||
|
||||
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<RoutePatternConstraintReference>();
|
||||
var constraints = new List<RoutePatternParameterPolicyReference>();
|
||||
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<RoutePatternConstraintReference> Constraints;
|
||||
public readonly IReadOnlyList<RoutePatternParameterPolicyReference> ParameterPolicies;
|
||||
|
||||
public ConstraintParseResults(int currentIndex, IReadOnlyList<RoutePatternConstraintReference> constraints)
|
||||
public ParameterPolicyParseResults(int currentIndex, IReadOnlyList<RoutePatternParameterPolicyReference> parameterPolicies)
|
||||
{
|
||||
CurrentIndex = currentIndex;
|
||||
Constraints = constraints;
|
||||
ParameterPolicies = parameterPolicies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,18 +22,18 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
internal RoutePattern(
|
||||
string rawText,
|
||||
IReadOnlyDictionary<string, object> defaults,
|
||||
IReadOnlyDictionary<string, IReadOnlyList<RoutePatternConstraintReference>> constraints,
|
||||
IReadOnlyDictionary<string, IReadOnlyList<RoutePatternParameterPolicyReference>> parameterPolicies,
|
||||
IReadOnlyList<RoutePatternParameterPart> parameters,
|
||||
IReadOnlyList<RoutePatternPathSegment> 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<string, object> Defaults { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the set of constraint references for the route pattern.
|
||||
/// The keys of <see cref="Constraints"/> are the route parameter names.
|
||||
/// Gets the set of parameter policy references for the route pattern.
|
||||
/// The keys of <see cref="ParameterPolicies"/> are the route parameter names.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, IReadOnlyList<RoutePatternConstraintReference>> Constraints { get; }
|
||||
public IReadOnlyDictionary<string, IReadOnlyList<RoutePatternParameterPolicyReference>> ParameterPolicies { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the precedence value of the route pattern for URL matching.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// The parsed representation of a constraint in a <see cref="RoutePattern"/> parameter. Instances
|
||||
/// of <see cref="RoutePatternConstraintReference"/> are immutable.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{DebuggerToString()}")]
|
||||
public sealed class RoutePatternConstraintReference
|
||||
{
|
||||
internal RoutePatternConstraintReference(string content)
|
||||
{
|
||||
Content = content;
|
||||
}
|
||||
|
||||
internal RoutePatternConstraintReference(IRouteConstraint constraint)
|
||||
{
|
||||
Constraint = constraint;
|
||||
}
|
||||
|
||||
internal RoutePatternConstraintReference(MatchProcessor matchProcessor)
|
||||
{
|
||||
MatchProcessor = matchProcessor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the constraint text.
|
||||
/// </summary>
|
||||
public string Content { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a pre-existing <see cref="IRouteConstraint"/> that was used to construct this reference.
|
||||
/// </summary>
|
||||
public IRouteConstraint Constraint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a pre-existing <see cref="Matching.MatchProcessor"/> that was used to construct this reference.
|
||||
/// </summary>
|
||||
public MatchProcessor MatchProcessor { get; }
|
||||
|
||||
private string DebuggerToString()
|
||||
{
|
||||
return Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePattern"/> from its string representation along
|
||||
/// with provided default values and constraints.
|
||||
/// with provided default values and parameter policies.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The route pattern string to parse.</param>
|
||||
/// <param name="defaults">
|
||||
|
|
@ -41,13 +41,13 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the parsed route pattern.
|
||||
/// </param>
|
||||
/// <param name="constraints">
|
||||
/// Additional constraints to associated with the route pattern. May be null.
|
||||
/// <param name="parameterPolicies">
|
||||
/// Additional parameter policies to associated with the route pattern. May be null.
|
||||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the parsed route pattern.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="RoutePattern"/>.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -91,15 +91,15 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePattern"/> from a collection of segments along
|
||||
/// with provided default values and constraints.
|
||||
/// with provided default values and parameter policies.
|
||||
/// </summary>
|
||||
/// <param name="defaults">
|
||||
/// Additional default values to associated with the route pattern. May be null.
|
||||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the route pattern.
|
||||
/// </param>
|
||||
/// <param name="constraints">
|
||||
/// Additional constraints to associated with the route pattern. May be null.
|
||||
/// <param name="parameterPolicies">
|
||||
/// Additional parameter policies to associated with the route pattern. May be null.
|
||||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the route pattern.
|
||||
/// </param>
|
||||
|
|
@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
/// <returns>The <see cref="RoutePattern"/>.</returns>
|
||||
public static RoutePattern Pattern(
|
||||
object defaults,
|
||||
object constraints,
|
||||
object parameterPolicies,
|
||||
IEnumerable<RoutePatternPathSegment> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePattern"/> from a collection of segments along
|
||||
/// with provided default values and constraints.
|
||||
/// with provided default values and parameter policies.
|
||||
/// </summary>
|
||||
/// <param name="rawText">The raw text to associate with the route pattern.</param>
|
||||
/// <param name="defaults">
|
||||
|
|
@ -128,8 +128,8 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the route pattern.
|
||||
/// </param>
|
||||
/// <param name="constraints">
|
||||
/// Additional constraints to associated with the route pattern. May be null.
|
||||
/// <param name="parameterPolicies">
|
||||
/// Additional parameter policies to associated with the route pattern. May be null.
|
||||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the route pattern.
|
||||
/// </param>
|
||||
|
|
@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
public static RoutePattern Pattern(
|
||||
string rawText,
|
||||
object defaults,
|
||||
object constraints,
|
||||
object parameterPolicies,
|
||||
IEnumerable<RoutePatternPathSegment> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -182,15 +182,15 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePattern"/> from a collection of segments along
|
||||
/// with provided default values and constraints.
|
||||
/// with provided default values and parameter policies.
|
||||
/// </summary>
|
||||
/// <param name="defaults">
|
||||
/// Additional default values to associated with the route pattern. May be null.
|
||||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the route pattern.
|
||||
/// </param>
|
||||
/// <param name="constraints">
|
||||
/// Additional constraints to associated with the route pattern. May be null.
|
||||
/// <param name="parameterPolicies">
|
||||
/// Additional parameter policies to associated with the route pattern. May be null.
|
||||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the route pattern.
|
||||
/// </param>
|
||||
|
|
@ -198,7 +198,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
/// <returns>The <see cref="RoutePattern"/>.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePattern"/> from a collection of segments along
|
||||
/// with provided default values and constraints.
|
||||
/// with provided default values and parameter policies.
|
||||
/// </summary>
|
||||
/// <param name="rawText">The raw text to associate with the route pattern.</param>
|
||||
/// <param name="defaults">
|
||||
|
|
@ -219,8 +219,8 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the route pattern.
|
||||
/// </param>
|
||||
/// <param name="constraints">
|
||||
/// Additional constraints to associated with the route pattern. May be null.
|
||||
/// <param name="parameterPolicies">
|
||||
/// Additional parameter policies to associated with the route pattern. May be null.
|
||||
/// The provided object will be converted to key-value pairs using <see cref="RouteValueDictionary"/>
|
||||
/// and then merged into the route pattern.
|
||||
/// </param>
|
||||
|
|
@ -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<string, object> defaults,
|
||||
IDictionary<string, object> constraints,
|
||||
IDictionary<string, object> parameterPolicies,
|
||||
IEnumerable<RoutePatternPathSegment> 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<string, List<RoutePatternConstraintReference>>(StringComparer.OrdinalIgnoreCase);
|
||||
if (constraints != null)
|
||||
var updatedParameterPolicies = new Dictionary<string, List<RoutePatternParameterPolicyReference>>(StringComparer.OrdinalIgnoreCase);
|
||||
if (parameterPolicies != null)
|
||||
{
|
||||
foreach (var kvp in constraints)
|
||||
foreach (var kvp in parameterPolicies)
|
||||
{
|
||||
updatedConstraints.Add(kvp.Key, new List<RoutePatternConstraintReference>()
|
||||
updatedParameterPolicies.Add(kvp.Key, new List<RoutePatternParameterPolicyReference>()
|
||||
{
|
||||
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<RoutePatternConstraintReference>)kvp.Value.ToArray()),
|
||||
updatedParameterPolicies.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList<RoutePatternParameterPolicyReference>)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<RoutePatternConstraintReference>();
|
||||
updatedConstraints.Add(parameter.Name, parameterConstraints);
|
||||
parameterConstraints = new List<RoutePatternParameterPolicyReference>();
|
||||
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<RoutePatternConstraintReference>)parameterConstraints ?? Array.Empty<RoutePatternConstraintReference>(),
|
||||
(IEnumerable<RoutePatternParameterPolicyReference>)parameterConstraints ?? Array.Empty<RoutePatternParameterPolicyReference>(),
|
||||
parameter.EncodeSlashes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePatternPathSegment"/> 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<RoutePatternConstraintReference>());
|
||||
parameterPolicies: Array.Empty<RoutePatternParameterPolicyReference>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -521,7 +522,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
parameterName: parameterName,
|
||||
@default: @default,
|
||||
parameterKind: RoutePatternParameterKind.Standard,
|
||||
constraints: Array.Empty<RoutePatternConstraintReference>());
|
||||
parameterPolicies: Array.Empty<RoutePatternParameterPolicyReference>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -556,23 +557,23 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
parameterName: parameterName,
|
||||
@default: @default,
|
||||
parameterKind: parameterKind,
|
||||
constraints: Array.Empty<RoutePatternConstraintReference>());
|
||||
parameterPolicies: Array.Empty<RoutePatternParameterPolicyReference>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePatternParameterPart"/> from the provided parameter name
|
||||
/// and default value, parameter kind, and constraints.
|
||||
/// and default value, parameter kind, and parameter policies.
|
||||
/// </summary>
|
||||
/// <param name="parameterName">The parameter name.</param>
|
||||
/// <param name="default">The parameter default value. May be <c>null</c>.</param>
|
||||
/// <param name="parameterKind">The parameter kind.</param>
|
||||
/// <param name="constraints">The constraints to associated with the parameter.</param>
|
||||
/// <param name="parameterPolicies">The parameter policies to associated with the parameter.</param>
|
||||
/// <returns>The <see cref="RoutePatternParameterPart"/>.</returns>
|
||||
public static RoutePatternParameterPart ParameterPart(
|
||||
string parameterName,
|
||||
object @default,
|
||||
RoutePatternParameterKind parameterKind,
|
||||
IEnumerable<RoutePatternConstraintReference> constraints)
|
||||
IEnumerable<RoutePatternParameterPolicyReference> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePatternParameterPart"/> from the provided parameter name
|
||||
/// and default value, parameter kind, and constraints.
|
||||
/// and default value, parameter kind, and parameter policies.
|
||||
/// </summary>
|
||||
/// <param name="parameterName">The parameter name.</param>
|
||||
/// <param name="default">The parameter default value. May be <c>null</c>.</param>
|
||||
/// <param name="parameterKind">The parameter kind.</param>
|
||||
/// <param name="constraints">The constraints to associated with the parameter.</param>
|
||||
/// <param name="parameterPolicies">The parameter policies to associated with the parameter.</param>
|
||||
/// <returns>The <see cref="RoutePatternParameterPart"/>.</returns>
|
||||
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<RoutePatternConstraintReference> constraints)
|
||||
IEnumerable<RoutePatternParameterPolicyReference> 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<RoutePatternConstraintReference> constraints,
|
||||
IEnumerable<RoutePatternParameterPolicyReference> parameterPolicies,
|
||||
bool encodeSlashes)
|
||||
{
|
||||
return new RoutePatternParameterPart(
|
||||
parameterName,
|
||||
@default,
|
||||
parameterKind,
|
||||
constraints.ToArray(),
|
||||
parameterPolicies.ToArray(),
|
||||
encodeSlashes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePatternConstraintReference"/> from the provided object.
|
||||
/// Creates a <see cref="RoutePatternParameterPolicyReference"/> from the provided contraint.
|
||||
/// </summary>
|
||||
/// <param name="constraint">
|
||||
/// The constraint object, which must be of type <see cref="IRouteConstraint"/>,
|
||||
/// <see cref="MatcherPolicy"/>, or <see cref="String"/>. If the constraint object
|
||||
/// is a <see cref="String"/> it will be tranformed into an instance of
|
||||
/// <see cref="RegexRouteConstraint"/>.
|
||||
/// The constraint object, which must be of type <see cref="IRouteConstraint"/>
|
||||
/// or <see cref="string"/>. If the constraint object is a <see cref="string"/>
|
||||
/// then it will be tranformed into an instance of <see cref="RegexRouteConstraint"/>.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="RoutePatternConstraintReference"/>.</returns>
|
||||
public static RoutePatternConstraintReference Constraint(object constraint)
|
||||
/// <returns>The <see cref="RoutePatternParameterPolicyReference"/>.</returns>
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePatternConstraintReference"/> from the provided object.
|
||||
/// Creates a <see cref="RoutePatternParameterPolicyReference"/> from the provided constraint.
|
||||
/// </summary>
|
||||
/// <param name="constraint">
|
||||
/// The constraint object.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="RoutePatternConstraintReference"/>.</returns>
|
||||
public static RoutePatternConstraintReference Constraint(IRouteConstraint constraint)
|
||||
/// <returns>The <see cref="RoutePatternParameterPolicyReference"/>.</returns>
|
||||
public static RoutePatternParameterPolicyReference Constraint(IRouteConstraint constraint)
|
||||
{
|
||||
if (constraint == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(constraint));
|
||||
}
|
||||
|
||||
return ConstraintCore(constraint);
|
||||
return ParameterPolicyCore(constraint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePatternConstraintReference"/> from the provided object.
|
||||
/// </summary>
|
||||
/// <param name="matchProcessor">
|
||||
/// The match processor object.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="RoutePatternConstraintReference"/>.</returns>
|
||||
public static RoutePatternConstraintReference Constraint(MatchProcessor matchProcessor)
|
||||
{
|
||||
if (matchProcessor == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(matchProcessor));
|
||||
}
|
||||
|
||||
return ConstraintCore(matchProcessor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePatternConstraintReference"/> from the provided object.
|
||||
/// Creates a <see cref="RoutePatternParameterPolicyReference"/> from the provided constraint.
|
||||
/// </summary>
|
||||
/// <param name="constraint">
|
||||
/// The constraint text, which will be tranformed into an instance of
|
||||
/// <see cref="RegexRouteConstraint"/>.
|
||||
/// The constraint text, which will be resolved by <see cref="ParameterPolicyFactory"/>.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="RoutePatternConstraintReference"/>.</returns>
|
||||
public static RoutePatternConstraintReference Constraint(string constraint)
|
||||
/// <returns>The <see cref="RoutePatternParameterPolicyReference"/>.</returns>
|
||||
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)
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePatternParameterPolicyReference"/> from the provided object.
|
||||
/// </summary>
|
||||
/// <param name="parameterPolicy">
|
||||
/// The parameter policy object.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="RoutePatternParameterPolicyReference"/>.</returns>
|
||||
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)
|
||||
/// <summary>
|
||||
/// Creates a <see cref="RoutePatternParameterPolicyReference"/> from the provided object.
|
||||
/// </summary>
|
||||
/// <param name="parameterPolicy">
|
||||
/// The parameter policy text, which will be resolved by <see cref="ParameterPolicyFactory"/>.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="RoutePatternParameterPolicyReference"/>.</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of constraints associated with this parameter.
|
||||
/// Gets the list of parameter policies associated with this parameter.
|
||||
/// </summary>
|
||||
public IReadOnlyList<RoutePatternConstraintReference> Constraints { get; }
|
||||
public IReadOnlyList<RoutePatternParameterPolicyReference> ParameterPolicies { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// The parsed representation of a policy in a <see cref="RoutePattern"/> parameter. Instances
|
||||
/// of <see cref="RoutePatternParameterPolicyReference"/> are immutable.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{DebuggerToString()}")]
|
||||
public sealed class RoutePatternParameterPolicyReference
|
||||
{
|
||||
internal RoutePatternParameterPolicyReference(string content)
|
||||
{
|
||||
Content = content;
|
||||
}
|
||||
|
||||
internal RoutePatternParameterPolicyReference(IParameterPolicy parameterPolicy)
|
||||
{
|
||||
ParameterPolicy = parameterPolicy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the constraint text.
|
||||
/// </summary>
|
||||
public string Content { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a pre-existing <see cref="IParameterPolicy"/> that was used to construct this reference.
|
||||
/// </summary>
|
||||
public IParameterPolicy ParameterPolicy { get; }
|
||||
|
||||
private string DebuggerToString()
|
||||
{
|
||||
return Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -467,10 +467,10 @@ namespace Microsoft.AspNetCore.Routing
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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}'.
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Invalid constraint '{0}' for parameter '{1}'. A constraint must be of type 'string', '{2}', or '{3}'.
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@
|
|||
<value>The constraint entry '{0}' - '{1}' must have a string value or be of a type which implements '{2}'.</value>
|
||||
</data>
|
||||
<data name="RoutePattern_InvalidConstraintReference" xml:space="preserve">
|
||||
<value>Invalid constraint '{0}'. A constraint must be of type 'string', '{1}', or '{2}'.</value>
|
||||
<value>Invalid constraint '{0}'. A constraint must be of type 'string' or '{1}'.</value>
|
||||
</data>
|
||||
<data name="RoutePattern_InvalidParameterConstraintReference" xml:space="preserve">
|
||||
<value>Invalid constraint '{0}' for parameter '{1}'. A constraint must be of type 'string', '{2}', or '{3}'.</value>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Routing.Template
|
|||
Constraint = constraint;
|
||||
}
|
||||
|
||||
public InlineConstraint(RoutePatternConstraintReference other)
|
||||
public InlineConstraint(RoutePatternParameterPolicyReference other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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--;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy()),
|
||||
options,
|
||||
NullLogger<DefaultLinkGenerator>.Instance,
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
{
|
||||
var dataSource = new CompositeEndpointDataSource(Array.Empty<EndpointDataSource>());
|
||||
return new DfaMatcherBuilder(
|
||||
Mock.Of<MatchProcessorFactory>(),
|
||||
Mock.Of<ParameterPolicyFactory>(),
|
||||
Mock.Of<EndpointSelector>(),
|
||||
policies);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<InvalidOperationException>(
|
||||
() => 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<EndsWithStringMatchProcessor>();
|
||||
|
||||
var factory = GetMatchProcessorFactory(options, services);
|
||||
|
||||
// Act
|
||||
var exception = Assert.Throws<InvalidOperationException>(
|
||||
() => 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<IntRouteConstraint>(Assert.IsType<RouteConstraintMatchProcessor>(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<OptionalMatchProcessor>(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<IntRouteConstraint>(Assert.IsType<RouteConstraintMatchProcessor>(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<OptionalMatchProcessor>(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<EndsWithStringMatchProcessor>(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<OptionalMatchProcessor>(matchProcessor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_CreatesMatchProcessor_FromConstraintText_AndRouteConstraint()
|
||||
{
|
||||
// Arrange
|
||||
var factory = GetMatchProcessorFactory();
|
||||
|
||||
// Act
|
||||
var matchProcessor = factory.Create("id", "int", optional: false);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<IntRouteConstraint>(Assert.IsType<RouteConstraintMatchProcessor>(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<OptionalMatchProcessor>(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<EndsWithStringMatchProcessor>();
|
||||
|
||||
var factory = GetMatchProcessorFactory(options, services);
|
||||
|
||||
// Act
|
||||
var matchProcessor = factory.Create("id", "endsWith", optional: false);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<EndsWithStringMatchProcessor>(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<EndsWithStringMatchProcessor>();
|
||||
|
||||
var factory = GetMatchProcessorFactory(options, services);
|
||||
|
||||
// Act
|
||||
var matchProcessor = factory.Create("id", "endsWith", optional: true);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<OptionalMatchProcessor>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<InvalidOperationException>(
|
||||
() => 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<InvalidOperationException>(
|
||||
() => 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<IntRouteConstraint>(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<OptionalRouteConstraint>(parameterPolicy);
|
||||
Assert.IsType<IntRouteConstraint>(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<IntRouteConstraint>(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<OptionalRouteConstraint>(parameterPolicy);
|
||||
Assert.IsType<IntRouteConstraint>(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<CustomParameterPolicy>(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<IntRouteConstraint>(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<OptionalRouteConstraint>(parameterPolicy);
|
||||
Assert.IsType<IntRouteConstraint>(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<CustomParameterPolicy>();
|
||||
|
||||
var factory = GetParameterPolicyFactory(options, services);
|
||||
|
||||
// Act
|
||||
var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "customParameterPolicy");
|
||||
|
||||
// Assert
|
||||
Assert.IsType<CustomParameterPolicy>(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<CustomParameterPolicy>();
|
||||
|
||||
var factory = GetParameterPolicyFactory(options, services);
|
||||
|
||||
// Act
|
||||
var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "customParameterPolicy");
|
||||
|
||||
// Assert
|
||||
Assert.IsType<CustomParameterPolicy>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<EndpointDataSource>());
|
||||
return new DfaMatcherBuilder(
|
||||
Mock.Of<MatchProcessorFactory>(),
|
||||
new DefaultParameterPolicyFactory(Options.Create(new RouteOptions()), Mock.Of<IServiceProvider>()),
|
||||
Mock.Of<EndpointSelector>(),
|
||||
policies);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<IRouteConstraint>();
|
||||
constraint
|
||||
.Setup(c => c.Match(
|
||||
It.IsAny<HttpContext>(),
|
||||
NullRouter.Instance,
|
||||
"test",
|
||||
It.IsAny<RouteValueDictionary>(),
|
||||
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<IRouteConstraint>();
|
||||
constraint
|
||||
.Setup(c => c.Match(
|
||||
It.IsAny<HttpContext>(),
|
||||
NullRouter.Instance,
|
||||
"test",
|
||||
It.IsAny<RouteValueDictionary>(),
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -132,21 +132,21 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
actual.GetParameter("a").Constraints,
|
||||
c => Assert.IsType<RegexRouteConstraint>(c.Constraint),
|
||||
actual.GetParameter("a").ParameterPolicies,
|
||||
c => Assert.IsType<RegexRouteConstraint>(c.ParameterPolicy),
|
||||
c => Assert.Equal("int", c.Content));
|
||||
Assert.Collection(
|
||||
actual.GetParameter("b").Constraints,
|
||||
c => Assert.IsType<RegexRouteConstraint>(c.Constraint));
|
||||
actual.GetParameter("b").ParameterPolicies,
|
||||
c => Assert.IsType<RegexRouteConstraint>(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<RegexRouteConstraint>(c.Constraint),
|
||||
c => Assert.IsType<RegexRouteConstraint>(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<RegexRouteConstraint>(c.Constraint));
|
||||
c => Assert.IsType<RegexRouteConstraint>(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<RegexRouteConstraint>(c.Constraint));
|
||||
c => Assert.IsType<RegexRouteConstraint>(c.ParameterPolicy));
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("e", kvp.Key);
|
||||
Assert.Collection(
|
||||
kvp.Value,
|
||||
c => Assert.IsType<RegexRouteConstraint>(c.Constraint));
|
||||
c => Assert.IsType<RegexRouteConstraint>(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<MatchProcessor>(), e = Mock.Of<MatchProcessor>(), };
|
||||
var constraints = new { d = Mock.Of<IRouteConstraint>(), e = Mock.Of<IRouteConstraint>(), };
|
||||
|
||||
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<RegexRouteConstraint>(Assert.Single(kvp.Value).Constraint);
|
||||
var regex = Assert.IsType<RegexRouteConstraint>(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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -641,7 +641,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
|||
|
||||
private class RoutePatternEqualityComparer :
|
||||
IEqualityComparer<RoutePattern>,
|
||||
IEqualityComparer<RoutePatternConstraintReference>
|
||||
IEqualityComparer<RoutePatternParameterPolicyReference>
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue