Support policy arguments and resolving services by constructors (#753)

This commit is contained in:
James Newton-King 2018-08-29 14:51:34 +12:00 committed by GitHub
parent 40fb13a021
commit 99c4f2f36a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 778 additions and 644 deletions

View File

@ -36,6 +36,7 @@
<Compile Include="..\..\test\Microsoft.AspNetCore.Routing.Tests\Matching\TreeRouterMatcherBuilder.cs">
<Link>Matching\TreeRouterMatcherBuilder.cs</Link>
</Compile>
<Compile Include="..\..\test\Microsoft.AspNetCore.Routing.Tests\TestObjects\TestServiceProvider.cs" Link="Matching\TestServiceProvider.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -39,16 +39,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -26,16 +26,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -22,16 +22,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -41,16 +41,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));
@ -64,6 +54,12 @@ namespace Microsoft.AspNetCore.Routing.Constraints
switch (routeDirection)
{
case RouteDirection.IncomingRequest:
// Only required for constraining incoming requests
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
return AllowedMethods.Contains(httpContext.Request.Method, StringComparer.OrdinalIgnoreCase);
case RouteDirection.UrlGeneration:

View File

@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -77,16 +77,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -40,16 +40,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -34,16 +34,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -40,16 +40,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -34,16 +34,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -30,16 +30,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -48,16 +48,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -44,16 +44,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -24,16 +24,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -31,16 +31,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
/// <inheritdoc />
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));

View File

@ -3,9 +3,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Routing
@ -18,6 +16,7 @@ namespace Microsoft.AspNetCore.Routing
public class DefaultInlineConstraintResolver : IInlineConstraintResolver
{
private readonly IDictionary<string, Type> _inlineConstraintMap;
private readonly IServiceProvider _serviceProvider;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultInlineConstraintResolver"/> class.
@ -25,11 +24,23 @@ namespace Microsoft.AspNetCore.Routing
/// <param name="routeOptions">
/// Accessor for <see cref="RouteOptions"/> containing the constraints of interest.
/// </param>
[Obsolete("This constructor is obsolete. Use DefaultInlineConstraintResolver.ctor(IOptions<RouteOptions>, IServiceProvider) instead.")]
public DefaultInlineConstraintResolver(IOptions<RouteOptions> routeOptions)
{
_inlineConstraintMap = routeOptions.Value.ConstraintMap;
}
public DefaultInlineConstraintResolver(IOptions<RouteOptions> routeOptions, IServiceProvider serviceProvider)
{
if (serviceProvider == null)
{
throw new ArgumentNullException(nameof(serviceProvider));
}
_inlineConstraintMap = routeOptions.Value.ConstraintMap;
_serviceProvider = serviceProvider;
}
/// <inheritdoc />
/// <example>
/// A typical constraint looks like the following
@ -45,112 +56,7 @@ namespace Microsoft.AspNetCore.Routing
throw new ArgumentNullException(nameof(inlineConstraint));
}
string constraintKey;
string argumentString;
var indexOfFirstOpenParens = inlineConstraint.IndexOf('(');
if (indexOfFirstOpenParens >= 0 && inlineConstraint.EndsWith(")", StringComparison.Ordinal))
{
constraintKey = inlineConstraint.Substring(0, indexOfFirstOpenParens);
argumentString = inlineConstraint.Substring(indexOfFirstOpenParens + 1,
inlineConstraint.Length - indexOfFirstOpenParens - 2);
}
else
{
constraintKey = inlineConstraint;
argumentString = null;
}
Type constraintType;
if (!_inlineConstraintMap.TryGetValue(constraintKey, out constraintType))
{
// Cannot resolve the constraint key
return null;
}
if (!typeof(IRouteConstraint).GetTypeInfo().IsAssignableFrom(constraintType.GetTypeInfo()))
{
throw new RouteCreationException(
Resources.FormatDefaultInlineConstraintResolver_TypeNotConstraint(
constraintType, constraintKey, typeof(IRouteConstraint).Name));
}
try
{
return CreateConstraint(constraintType, argumentString);
}
catch (RouteCreationException)
{
throw;
}
catch (Exception exception)
{
throw new RouteCreationException(
$"An error occurred while trying to create an instance of route constraint '{constraintType.FullName}'.",
exception);
}
}
internal static IRouteConstraint CreateConstraint(Type constraintType, string argumentString)
{
// No arguments - call the default constructor
if (argumentString == null)
{
return (IRouteConstraint)Activator.CreateInstance(constraintType);
}
var constraintTypeInfo = constraintType.GetTypeInfo();
ConstructorInfo activationConstructor = null;
object[] parameters = null;
var constructors = constraintTypeInfo.DeclaredConstructors.ToArray();
// If there is only one constructor and it has a single parameter, pass the argument string directly
// This is necessary for the Regex RouteConstraint to ensure that patterns are not split on commas.
if (constructors.Length == 1 && constructors[0].GetParameters().Length == 1)
{
activationConstructor = constructors[0];
parameters = ConvertArguments(activationConstructor.GetParameters(), new string[] { argumentString });
}
else
{
var arguments = argumentString.Split(',').Select(argument => argument.Trim()).ToArray();
var matchingConstructors = constructors.Where(ci => ci.GetParameters().Length == arguments.Length)
.ToArray();
var constructorMatches = matchingConstructors.Length;
if (constructorMatches == 0)
{
throw new RouteCreationException(
Resources.FormatDefaultInlineConstraintResolver_CouldNotFindCtor(
constraintTypeInfo.Name, arguments.Length));
}
else if (constructorMatches == 1)
{
activationConstructor = matchingConstructors[0];
parameters = ConvertArguments(activationConstructor.GetParameters(), arguments);
}
else
{
throw new RouteCreationException(
Resources.FormatDefaultInlineConstraintResolver_AmbiguousCtors(
constraintTypeInfo.Name, arguments.Length));
}
}
return (IRouteConstraint)activationConstructor.Invoke(parameters);
}
private static object[] ConvertArguments(ParameterInfo[] parameterInfos, string[] arguments)
{
var parameters = new object[parameterInfos.Length];
for (var i = 0; i < parameterInfos.Length; i++)
{
var parameter = parameterInfos[i];
var parameterType = parameter.ParameterType;
parameters[i] = Convert.ChangeType(arguments[i], parameterType, CultureInfo.InvariantCulture);
}
return parameters;
return ParameterPolicyActivator.ResolveParameterPolicy<IRouteConstraint>(_inlineConstraintMap, _serviceProvider, inlineConstraint, out _);
}
}
}

View File

@ -3,8 +3,8 @@
using System;
using Microsoft.AspNetCore.Routing.Constraints;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Routing
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Routing
if (parameterPolicy is IRouteConstraint routeConstraint)
{
return InitializeRouteConstraint(parameter?.IsOptional ?? false, routeConstraint, argument: null);
return InitializeRouteConstraint(parameter?.IsOptional ?? false, routeConstraint);
}
return parameterPolicy;
@ -44,47 +44,26 @@ namespace Microsoft.AspNetCore.Routing
throw new ArgumentNullException(nameof(inlineText));
}
// Example:
// {productId:regex(\d+)}
//
// ParameterName: productId
// value: regex(\d+)
// name: regex
// argument: \d+
(var name, var argument) = Parse(inlineText);
if (!_options.ConstraintMap.TryGetValue(name, out var type))
var parameterPolicy = ParameterPolicyActivator.ResolveParameterPolicy<IParameterPolicy>(_options.ConstraintMap, _serviceProvider, inlineText, out var parameterPolicyKey);
if (parameterPolicy == null)
{
throw new InvalidOperationException(Resources.FormatRoutePattern_ConstraintReferenceNotFound(
name,
typeof(RouteOptions),
nameof(RouteOptions.ConstraintMap)));
parameterPolicyKey,
typeof(RouteOptions),
nameof(RouteOptions.ConstraintMap)));
}
if (typeof(IRouteConstraint).IsAssignableFrom(type))
if (parameterPolicy is IRouteConstraint constraint)
{
var constraint = DefaultInlineConstraintResolver.CreateConstraint(type, argument);
return InitializeRouteConstraint(parameter?.IsOptional ?? false, constraint, argument);
return InitializeRouteConstraint(parameter?.IsOptional ?? false, constraint);
}
if (typeof(IParameterPolicy).IsAssignableFrom(type))
{
var parameterPolicy = (IParameterPolicy)_serviceProvider.GetRequiredService(type);
return parameterPolicy;
}
var message = Resources.FormatRoutePattern_InvalidStringConstraintReference(
type,
name,
typeof(IRouteConstraint),
typeof(IParameterPolicy));
throw new InvalidOperationException(message);
return parameterPolicy;
}
private IParameterPolicy InitializeRouteConstraint(
bool optional,
IRouteConstraint routeConstraint,
string argument)
IRouteConstraint routeConstraint)
{
if (optional)
{
@ -93,25 +72,5 @@ namespace Microsoft.AspNetCore.Routing
return routeConstraint;
}
private (string name, string argument) Parse(string text)
{
string name;
string argument;
var indexOfFirstOpenParens = text.IndexOf('(');
if (indexOfFirstOpenParens >= 0 && text.EndsWith(")", StringComparison.Ordinal))
{
name = text.Substring(0, indexOfFirstOpenParens);
argument = text.Substring(
indexOfFirstOpenParens + 1,
text.Length - indexOfFirstOpenParens - 2);
}
else
{
name = text;
argument = null;
}
return (name, argument);
}
}
}

View File

@ -0,0 +1,174 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Routing.Internal
{
internal static class ParameterPolicyActivator
{
public static T ResolveParameterPolicy<T>(IDictionary<string, Type> inlineParameterPolicyMap, IServiceProvider serviceProvider, string inlineParameterPolicy, out string parameterPolicyKey)
where T : IParameterPolicy
{
// IServiceProvider could be null
// DefaultInlineConstraintResolver can be created without an IServiceProvider and then call this method
if (inlineParameterPolicyMap == null)
{
throw new ArgumentNullException(nameof(inlineParameterPolicyMap));
}
if (inlineParameterPolicy == null)
{
throw new ArgumentNullException(nameof(inlineParameterPolicy));
}
string argumentString;
var indexOfFirstOpenParens = inlineParameterPolicy.IndexOf('(');
if (indexOfFirstOpenParens >= 0 && inlineParameterPolicy.EndsWith(")", StringComparison.Ordinal))
{
parameterPolicyKey = inlineParameterPolicy.Substring(0, indexOfFirstOpenParens);
argumentString = inlineParameterPolicy.Substring(
indexOfFirstOpenParens + 1,
inlineParameterPolicy.Length - indexOfFirstOpenParens - 2);
}
else
{
parameterPolicyKey = inlineParameterPolicy;
argumentString = null;
}
if (!inlineParameterPolicyMap.TryGetValue(parameterPolicyKey, out var parameterPolicyType))
{
return default;
}
if (!typeof(T).IsAssignableFrom(parameterPolicyType))
{
throw new RouteCreationException(
Resources.FormatDefaultInlineConstraintResolver_TypeNotConstraint(
parameterPolicyType, parameterPolicyKey, typeof(T).Name));
}
try
{
return (T)CreateParameterPolicy(serviceProvider, parameterPolicyType, argumentString);
}
catch (RouteCreationException)
{
throw;
}
catch (Exception exception)
{
throw new RouteCreationException(
$"An error occurred while trying to create an instance of '{parameterPolicyType.FullName}'.",
exception);
}
}
private static IParameterPolicy CreateParameterPolicy(IServiceProvider serviceProvider, Type parameterPolicyType, string argumentString)
{
ConstructorInfo activationConstructor = null;
object[] parameters = null;
var constructors = parameterPolicyType.GetConstructors();
// If there is only one constructor and it has a single parameter, pass the argument string directly
// This is necessary for the Regex RouteConstraint to ensure that patterns are not split on commas.
if (constructors.Length == 1 && GetNonConvertableParameterTypeCount(serviceProvider, constructors[0].GetParameters()) == 1)
{
activationConstructor = constructors[0];
parameters = ConvertArguments(serviceProvider, activationConstructor.GetParameters(), new string[] { argumentString });
}
else
{
var arguments = !string.IsNullOrEmpty(argumentString)
? argumentString.Split(',').Select(argument => argument.Trim()).ToArray()
: Array.Empty<string>();
// We want to find the constructors that match the number of passed in arguments
// We either want a single match, or a single best match. The best match is the one with the most
// arguments that can be resolved from DI
//
// For example, ctor(string, IService) will beat ctor(string)
var matchingConstructors = constructors
.Where(ci => GetNonConvertableParameterTypeCount(serviceProvider, ci.GetParameters()) == arguments.Length)
.OrderByDescending(ci => ci.GetParameters().Length)
.ToArray();
if (matchingConstructors.Length == 0)
{
throw new RouteCreationException(
Resources.FormatDefaultInlineConstraintResolver_CouldNotFindCtor(
parameterPolicyType.Name, arguments.Length));
}
else
{
// When there are multiple matching constructors, choose the one with the most service arguments
if (matchingConstructors.Length == 1
|| matchingConstructors[0].GetParameters().Length > matchingConstructors[1].GetParameters().Length)
{
activationConstructor = matchingConstructors[0];
}
else
{
throw new RouteCreationException(
Resources.FormatDefaultInlineConstraintResolver_AmbiguousCtors(
parameterPolicyType.Name, matchingConstructors[0].GetParameters().Length));
}
parameters = ConvertArguments(serviceProvider, activationConstructor.GetParameters(), arguments);
}
}
return (IParameterPolicy)activationConstructor.Invoke(parameters);
}
private static int GetNonConvertableParameterTypeCount(IServiceProvider serviceProvider, ParameterInfo[] parameters)
{
if (serviceProvider == null)
{
return parameters.Length;
}
var count = 0;
for (var i = 0; i < parameters.Length; i++)
{
if (typeof(IConvertible).IsAssignableFrom(parameters[i].ParameterType))
{
count++;
}
}
return count;
}
private static object[] ConvertArguments(IServiceProvider serviceProvider, ParameterInfo[] parameterInfos, string[] arguments)
{
var parameters = new object[parameterInfos.Length];
var argumentPosition = 0;
for (var i = 0; i < parameterInfos.Length; i++)
{
var parameter = parameterInfos[i];
var parameterType = parameter.ParameterType;
if (serviceProvider != null && !typeof(IConvertible).IsAssignableFrom(parameterType))
{
parameters[i] = serviceProvider.GetRequiredService(parameterType);
}
else
{
parameters[i] = Convert.ChangeType(arguments[argumentPosition], parameterType, CultureInfo.InvariantCulture);
argumentPosition++;
}
}
return parameters;
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Constraints;
using Microsoft.AspNetCore.Routing.TestObjects;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Moq;
@ -324,11 +325,33 @@ namespace Microsoft.AspNetCore.Routing.Tests
ex.Message);
}
private IInlineConstraintResolver GetInlineConstraintResolver(RouteOptions routeOptions)
[Fact]
public void ResolveConstraint_HasArguments_NoServiceProvider()
{
// Arrange
var routeOptions = new RouteOptions();
var constraintResolver = GetInlineConstraintResolver(routeOptions, hasServiceProvider: false);
// Act
var constraint = constraintResolver.ResolveConstraint("regex(ab,1)");
// Assert
Assert.IsType<RegexInlineRouteConstraint>(constraint);
}
private IInlineConstraintResolver GetInlineConstraintResolver(RouteOptions routeOptions, bool hasServiceProvider = true)
{
var optionsAccessor = new Mock<IOptions<RouteOptions>>();
optionsAccessor.SetupGet(o => o.Value).Returns(routeOptions);
if (hasServiceProvider)
{
return new DefaultInlineConstraintResolver(optionsAccessor.Object, new TestServiceProvider());
}
#pragma warning disable CS0618 // Type or member is obsolete
return new DefaultInlineConstraintResolver(optionsAccessor.Object);
#pragma warning restore CS0618 // Type or member is obsolete
}
private class MultiConstructorRouteConstraint : IRouteConstraint

View File

@ -0,0 +1,533 @@
// 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
{
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<RouteCreationException>(
() => factory.Create(RoutePatternFactory.ParameterPart("id"), @"bad"));
// Assert
Assert.Equal(
$"The constraint type '{typeof(string)}' which is mapped to constraint key 'bad' must implement the '{nameof(IParameterPolicy)}' interface.",
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);
}
[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_AndRouteConstraintWithArgument()
{
// Arrange
var factory = GetParameterPolicyFactory();
// Act
var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "range(1,20)");
// Assert
var constraint = Assert.IsType<RangeRouteConstraint>(parameterPolicy);
Assert.Equal(1, constraint.Min);
Assert.Equal(20, constraint.Max);
}
[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_AndParameterPolicyWithArgumentAndServices()
{
// Arrange
var options = new RouteOptions();
options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithArguments));
var services = new ServiceCollection();
services.AddTransient<ITestService, TestService>();
var factory = GetParameterPolicyFactory(options, services);
// Act
var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(20)");
// Assert
var constraint = Assert.IsType<CustomParameterPolicyWithArguments>(parameterPolicy);
Assert.Equal(20, constraint.Count);
Assert.NotNull(constraint.TestService);
}
[Fact]
public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithArgumentAndMultipleServices()
{
// Arrange
var options = new RouteOptions();
options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithMultipleArguments));
var services = new ServiceCollection();
services.AddTransient<ITestService, TestService>();
var factory = GetParameterPolicyFactory(options, services);
// Act
var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(20,-1)");
// Assert
var constraint = Assert.IsType<CustomParameterPolicyWithMultipleArguments>(parameterPolicy);
Assert.Equal(20, constraint.First);
Assert.Equal(-1, constraint.Second);
Assert.NotNull(constraint.TestService1);
Assert.NotNull(constraint.TestService2);
}
[Fact]
public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithOnlyServiceArguments()
{
// Arrange
var options = new RouteOptions();
options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithOnlyServiceArguments));
var services = new ServiceCollection();
services.AddTransient<ITestService, TestService>();
var factory = GetParameterPolicyFactory(options, services);
// Act
var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy");
// Assert
var constraint = Assert.IsType<CustomParameterPolicyWithOnlyServiceArguments>(parameterPolicy);
Assert.NotNull(constraint.TestService1);
Assert.NotNull(constraint.TestService2);
}
[Fact]
public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithMultipleMatchingCtors()
{
// Arrange
var options = new RouteOptions();
options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithMultpleCtors));
var services = new ServiceCollection();
services.AddTransient<ITestService, TestService>();
var factory = GetParameterPolicyFactory(options, services);
// Act
var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(1)");
// Assert
var constraint = Assert.IsType<CustomParameterPolicyWithMultpleCtors>(parameterPolicy);
Assert.NotNull(constraint.TestService);
Assert.Equal(1, constraint.Count);
}
[Fact]
public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithAmbigiousMatchingCtors()
{
// Arrange
var options = new RouteOptions();
options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithAmbigiousMultpleCtors));
var services = new ServiceCollection();
services.AddTransient<ITestService, TestService>();
var factory = GetParameterPolicyFactory(options, services);
// Act
var exception = Assert.Throws<RouteCreationException>(
() => factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(1)"));
// Assert
Assert.Equal($"The constructor to use for activating the constraint type '{nameof(CustomParameterPolicyWithAmbigiousMultpleCtors)}' is ambiguous. "
+ $"Multiple constructors were found with the following number of parameters: 2.", exception.Message);
}
[Fact]
public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithSingleArgumentAndServiceArgument()
{
// Arrange
var options = new RouteOptions();
options.ConstraintMap.Add("regex-service", typeof(RegexInlineRouteConstraintWithService));
var services = new ServiceCollection();
services.AddTransient<ITestService, TestService>();
var factory = GetParameterPolicyFactory(options, services);
// Act
var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), @"regex-service(\\d{1,2})");
// Assert
var constraint = Assert.IsType<RegexInlineRouteConstraintWithService>(parameterPolicy);
Assert.NotNull(constraint.TestService);
Assert.Equal("\\\\d{1,2}", constraint.Constraint.ToString());
}
[Fact]
public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithArgumentAndUnresolvedServices_Throw()
{
// Arrange
var options = new RouteOptions();
options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithArguments));
var services = new ServiceCollection();
var factory = GetParameterPolicyFactory(options, services);
// Act
var exception = Assert.Throws<RouteCreationException>(
() => factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(20)"));
// Assert
var inner = Assert.IsType<InvalidOperationException>(exception.InnerException);
Assert.Equal($"No service for type '{typeof(ITestService).FullName}' has been registered.", inner.Message);
}
[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;
}
}
}
public class CustomParameterPolicy : IParameterPolicy
{
}
public class CustomParameterPolicyWithArguments : IParameterPolicy
{
public CustomParameterPolicyWithArguments(ITestService testService, int count)
{
TestService = testService;
Count = count;
}
public ITestService TestService { get; }
public int Count { get; }
}
public class CustomParameterPolicyWithMultpleCtors : IParameterPolicy
{
public CustomParameterPolicyWithMultpleCtors(ITestService testService, int count)
{
TestService = testService;
Count = count;
}
public CustomParameterPolicyWithMultpleCtors(int count)
: this(testService: null, count)
{
}
public ITestService TestService { get; }
public int Count { get; }
}
public class CustomParameterPolicyWithAmbigiousMultpleCtors : IParameterPolicy
{
public CustomParameterPolicyWithAmbigiousMultpleCtors(ITestService testService, int count)
{
TestService = testService;
Count = count;
}
public CustomParameterPolicyWithAmbigiousMultpleCtors(object testService, int count)
: this(testService: null, count)
{
}
public CustomParameterPolicyWithAmbigiousMultpleCtors(int count)
: this(testService: null, count)
{
}
public ITestService TestService { get; }
public int Count { get; }
}
public class CustomParameterPolicyWithMultipleArguments : IParameterPolicy
{
public CustomParameterPolicyWithMultipleArguments(int first, ITestService testService1, int second, ITestService testService2)
{
First = first;
TestService1 = testService1;
Second = second;
TestService2 = testService2;
}
public int First { get; }
public ITestService TestService1 { get; }
public int Second { get; }
public ITestService TestService2 { get; }
}
public class CustomParameterPolicyWithOnlyServiceArguments : IParameterPolicy
{
public CustomParameterPolicyWithOnlyServiceArguments(ITestService testService1, ITestService testService2)
{
TestService1 = testService1;
TestService2 = testService2;
}
public ITestService TestService1 { get; }
public ITestService TestService2 { get; }
}
public interface ITestService
{
}
public class TestService : ITestService
{
}
public class RegexInlineRouteConstraintWithService : RegexRouteConstraint
{
public RegexInlineRouteConstraintWithService(string regexPattern, ITestService testService)
: base(regexPattern)
{
TestService = testService;
}
public ITestService TestService { get; }
}
}

View File

@ -968,7 +968,7 @@ namespace Microsoft.AspNetCore.Routing.Tests
.Add("test", typeof(TestRouteConstraint)));
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
return new DefaultInlineConstraintResolver(accessor);
return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
private class TestRouteConstraint : IRouteConstraint

View File

@ -1,272 +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 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;
}
}
}
}

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.AspNetCore.Routing.TestObjects;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Routing.Matching
@ -18,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public RouteMatcherBuilder()
{
_constraintResolver = new DefaultInlineConstraintResolver(Options.Create(new RouteOptions()));
_constraintResolver = new DefaultInlineConstraintResolver(Options.Create(new RouteOptions()), new TestServiceProvider());
_endpoints = new List<RouteEndpoint>();
}

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Template;
using Microsoft.AspNetCore.Routing.TestObjects;
using Microsoft.AspNetCore.Routing.Tree;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.ObjectPool;
@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
var builder = new TreeRouteBuilder(
NullLoggerFactory.Instance,
new DefaultObjectPool<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy()),
new DefaultInlineConstraintResolver(Options.Create(new RouteOptions())));
new DefaultInlineConstraintResolver(Options.Create(new RouteOptions()), new TestServiceProvider()));
var selector = new DefaultEndpointSelector(Array.Empty<MatcherPolicy>());

View File

@ -5,6 +5,7 @@ using System;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Constraints;
using Microsoft.AspNetCore.Routing.TestObjects;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Options;
using Moq;
@ -183,7 +184,7 @@ namespace Microsoft.AspNetCore.Routing
.SetupGet(o => o.Value)
.Returns(new RouteOptions());
var inlineConstraintResolver = new DefaultInlineConstraintResolver(options.Object);
var inlineConstraintResolver = new DefaultInlineConstraintResolver(options.Object, new TestServiceProvider());
return new RouteConstraintBuilder(inlineConstraintResolver, template);
}
}

View File

@ -1842,7 +1842,7 @@ namespace Microsoft.AspNetCore.Routing
.SetupGet(o => o.Value)
.Returns(new RouteOptions());
return new DefaultInlineConstraintResolver(routeOptions.Object);
return new DefaultInlineConstraintResolver(routeOptions.Object, new TestServiceProvider());
}
}
}

View File

@ -1293,7 +1293,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
var services = new ServiceCollection().AddOptions();
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
return new DefaultInlineConstraintResolver(accessor);
return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
private class PathAndQuery

View File

@ -1136,7 +1136,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
var services = new ServiceCollection().AddOptions();
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
return new DefaultInlineConstraintResolver(accessor);
return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
}
}

View File

@ -143,7 +143,7 @@ namespace Microsoft.AspNetCore.Routing.Tests
var services = new ServiceCollection().AddOptions();
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
return new DefaultInlineConstraintResolver(accessor);
return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
}
}

View File

@ -260,7 +260,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
var services = new ServiceCollection().AddOptions();
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
return new DefaultInlineConstraintResolver(accessor);
return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
}
}

View File

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Template;
using Microsoft.AspNetCore.Routing.TestObjects;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.ObjectPool;
@ -2133,7 +2134,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
var optionsMock = new Mock<IOptions<RouteOptions>>();
optionsMock.SetupGet(o => o.Value).Returns(options);
return new DefaultInlineConstraintResolver(optionsMock.Object);
return new DefaultInlineConstraintResolver(optionsMock.Object, new TestServiceProvider());
}
private static TreeRouteBuilder CreateBuilder()