diff --git a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Microsoft.AspNetCore.Routing.Performance.csproj b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Microsoft.AspNetCore.Routing.Performance.csproj
index 99413eb58b..625a26262a 100644
--- a/benchmarks/Microsoft.AspNetCore.Routing.Performance/Microsoft.AspNetCore.Routing.Performance.csproj
+++ b/benchmarks/Microsoft.AspNetCore.Routing.Performance/Microsoft.AspNetCore.Routing.Performance.csproj
@@ -36,6 +36,7 @@
Matching\TreeRouterMatcherBuilder.cs
+
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/BoolRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/BoolRouteConstraint.cs
index a65e88ef67..c91f7305a4 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/BoolRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/BoolRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/CompositeRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/CompositeRouteConstraint.cs
index 5acff08294..468699ce8a 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/CompositeRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/CompositeRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/DateTimeRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/DateTimeRouteConstraint.cs
index 9015dc64be..9105108d00 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/DateTimeRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/DateTimeRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/DecimalRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/DecimalRouteConstraint.cs
index ff29d98574..808d448706 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/DecimalRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/DecimalRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/DoubleRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/DoubleRouteConstraint.cs
index e7259d0bf3..0a8064f468 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/DoubleRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/DoubleRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/FloatRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/FloatRouteConstraint.cs
index 5db0e65c28..eff69c8ad1 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/FloatRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/FloatRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/GuidRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/GuidRouteConstraint.cs
index 00d451767f..aa1c74ec07 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/GuidRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/GuidRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/HttpMethodRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/HttpMethodRouteConstraint.cs
index d01140157d..a894acaacb 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/HttpMethodRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/HttpMethodRouteConstraint.cs
@@ -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:
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/IntRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/IntRouteConstraint.cs
index 83b08533bd..82f32052ee 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/IntRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/IntRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/LengthRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/LengthRouteConstraint.cs
index f876c03cbc..f102af6ec4 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/LengthRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/LengthRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/LongRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/LongRouteConstraint.cs
index a76a4de885..6d12c74d79 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/LongRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/LongRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/MaxLengthRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/MaxLengthRouteConstraint.cs
index 42dde182ed..a7858477da 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/MaxLengthRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/MaxLengthRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/MaxRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/MaxRouteConstraint.cs
index e43dac85fe..f20cce6c6c 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/MaxRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/MaxRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/MinLengthRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/MinLengthRouteConstraint.cs
index 1ea64ae216..7a51bf7412 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/MinLengthRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/MinLengthRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/MinRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/MinRouteConstraint.cs
index 68357c59e7..701d5c68e8 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/MinRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/MinRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/OptionalRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/OptionalRouteConstraint.cs
index 3990376410..9a9cca8e42 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/OptionalRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/OptionalRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/RangeRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/RangeRouteConstraint.cs
index 301a75f15a..cc2487cfcb 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/RangeRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/RangeRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/RegexRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/RegexRouteConstraint.cs
index fb3d2390fe..c4e83f40e3 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/RegexRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/RegexRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/RequiredRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/RequiredRouteConstraint.cs
index e03d618565..827f85ea39 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/RequiredRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/RequiredRouteConstraint.cs
@@ -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));
diff --git a/src/Microsoft.AspNetCore.Routing/Constraints/StringRouteConstraint.cs b/src/Microsoft.AspNetCore.Routing/Constraints/StringRouteConstraint.cs
index e7d92ef13c..202fcbb02c 100644
--- a/src/Microsoft.AspNetCore.Routing/Constraints/StringRouteConstraint.cs
+++ b/src/Microsoft.AspNetCore.Routing/Constraints/StringRouteConstraint.cs
@@ -31,16 +31,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
///
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));
diff --git a/src/Microsoft.AspNetCore.Routing/DefaultInlineConstraintResolver.cs b/src/Microsoft.AspNetCore.Routing/DefaultInlineConstraintResolver.cs
index ed58e053ba..1ed1f8e1ab 100644
--- a/src/Microsoft.AspNetCore.Routing/DefaultInlineConstraintResolver.cs
+++ b/src/Microsoft.AspNetCore.Routing/DefaultInlineConstraintResolver.cs
@@ -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 _inlineConstraintMap;
+ private readonly IServiceProvider _serviceProvider;
///
/// Initializes a new instance of the class.
@@ -25,11 +24,23 @@ namespace Microsoft.AspNetCore.Routing
///
/// Accessor for containing the constraints of interest.
///
+ [Obsolete("This constructor is obsolete. Use DefaultInlineConstraintResolver.ctor(IOptions, IServiceProvider) instead.")]
public DefaultInlineConstraintResolver(IOptions routeOptions)
{
_inlineConstraintMap = routeOptions.Value.ConstraintMap;
}
+ public DefaultInlineConstraintResolver(IOptions routeOptions, IServiceProvider serviceProvider)
+ {
+ if (serviceProvider == null)
+ {
+ throw new ArgumentNullException(nameof(serviceProvider));
+ }
+
+ _inlineConstraintMap = routeOptions.Value.ConstraintMap;
+ _serviceProvider = serviceProvider;
+ }
+
///
///
/// 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(_inlineConstraintMap, _serviceProvider, inlineConstraint, out _);
}
}
}
diff --git a/src/Microsoft.AspNetCore.Routing/DefaultParameterPolicyFactory.cs b/src/Microsoft.AspNetCore.Routing/DefaultParameterPolicyFactory.cs
index a85f3d826b..d14bd9f113 100644
--- a/src/Microsoft.AspNetCore.Routing/DefaultParameterPolicyFactory.cs
+++ b/src/Microsoft.AspNetCore.Routing/DefaultParameterPolicyFactory.cs
@@ -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(_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);
- }
}
}
diff --git a/src/Microsoft.AspNetCore.Routing/Internal/ParameterPolicyActivator.cs b/src/Microsoft.AspNetCore.Routing/Internal/ParameterPolicyActivator.cs
new file mode 100644
index 0000000000..1fc3f1a365
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Routing/Internal/ParameterPolicyActivator.cs
@@ -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(IDictionary 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();
+
+ // 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;
+ }
+ }
+}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/DefaultInlineConstraintResolverTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/DefaultInlineConstraintResolverTest.cs
index bba78fb6b2..63aef81de4 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/DefaultInlineConstraintResolverTest.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/DefaultInlineConstraintResolverTest.cs
@@ -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(constraint);
+ }
+
+ private IInlineConstraintResolver GetInlineConstraintResolver(RouteOptions routeOptions, bool hasServiceProvider = true)
{
var optionsAccessor = new Mock>();
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
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/DefaultParameterPolicyFactoryTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/DefaultParameterPolicyFactoryTest.cs
new file mode 100644
index 0000000000..69761f3a0d
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Routing.Tests/DefaultParameterPolicyFactoryTest.cs
@@ -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(
+ () => factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), @"notpresent(\d+)"));
+
+ // Assert
+ Assert.Equal(
+ $"The constraint reference 'notpresent' could not be resolved to a type. " +
+ $"Register the constraint type with '{typeof(RouteOptions)}.{nameof(RouteOptions.ConstraintMap)}'.",
+ exception.Message);
+ }
+
+ [Fact]
+ public void Create_ThrowsException_OnInvalidType()
+ {
+ // Arrange
+ var options = new RouteOptions();
+ options.ConstraintMap.Add("bad", typeof(string));
+
+ var services = new ServiceCollection();
+
+ var factory = GetParameterPolicyFactory(options, services);
+
+ // Act
+ var exception = Assert.Throws(
+ () => factory.Create(RoutePatternFactory.ParameterPart("id"), @"bad"));
+
+ // Assert
+ Assert.Equal(
+ $"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(parameterPolicy);
+ }
+
+ [Fact]
+ public void Create_CreatesParameterPolicy_FromRoutePattern_String_Optional()
+ {
+ // Arrange
+ var factory = GetParameterPolicyFactory();
+
+ var parameter = RoutePatternFactory.ParameterPart(
+ "id",
+ @default: null,
+ parameterKind: RoutePatternParameterKind.Optional,
+ parameterPolicies: new[] { RoutePatternFactory.Constraint("int"), });
+
+ // Act
+ var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);
+
+ // Assert
+ var optionalConstraint = Assert.IsType(parameterPolicy);
+ Assert.IsType(optionalConstraint.InnerConstraint);
+ }
+
+ [Fact]
+ public void Create_CreatesParameterPolicy_FromRoutePattern_Constraint()
+ {
+ // Arrange
+ var factory = GetParameterPolicyFactory();
+
+ var parameter = RoutePatternFactory.ParameterPart(
+ "id",
+ @default: null,
+ parameterKind: RoutePatternParameterKind.Standard,
+ parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new IntRouteConstraint()), });
+
+ // Act
+ var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);
+
+ // Assert
+ Assert.IsType(parameterPolicy);
+ }
+
+ [Fact]
+ public void Create_CreatesParameterPolicy_FromRoutePattern_Constraint_Optional()
+ {
+ // Arrange
+ var factory = GetParameterPolicyFactory();
+
+ var parameter = RoutePatternFactory.ParameterPart(
+ "id",
+ @default: null,
+ parameterKind: RoutePatternParameterKind.Optional,
+ parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new IntRouteConstraint()), });
+
+ // Act
+ var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);
+
+ // Assert
+ var optionalConstraint = Assert.IsType(parameterPolicy);
+ Assert.IsType(optionalConstraint.InnerConstraint);
+ }
+
+ [Fact]
+ public void Create_CreatesParameterPolicy_FromRoutePattern_ParameterPolicy()
+ {
+ // Arrange
+ var factory = GetParameterPolicyFactory();
+
+ var parameter = RoutePatternFactory.ParameterPart(
+ "id",
+ @default: null,
+ parameterKind: RoutePatternParameterKind.Standard,
+ parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new CustomParameterPolicy()), });
+
+ // Act
+ var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);
+
+ // Assert
+ Assert.IsType(parameterPolicy);
+ }
+
+ [Fact]
+ public void Create_CreatesParameterPolicy_FromConstraintText_AndRouteConstraint()
+ {
+ // Arrange
+ var factory = GetParameterPolicyFactory();
+
+ // Act
+ var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "int");
+
+ // Assert
+ Assert.IsType(parameterPolicy);
+ }
+
+ [Fact]
+ public void Create_CreatesParameterPolicy_FromConstraintText_AndRouteConstraintWithArgument()
+ {
+ // Arrange
+ var factory = GetParameterPolicyFactory();
+
+ // Act
+ var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "range(1,20)");
+
+ // Assert
+ var constraint = Assert.IsType(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(parameterPolicy);
+ Assert.IsType(optionalConstraint.InnerConstraint);
+ }
+
+ [Fact]
+ public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicy()
+ {
+ // Arrange
+ var options = new RouteOptions();
+ options.ConstraintMap.Add("customParameterPolicy", typeof(CustomParameterPolicy));
+
+ var services = new ServiceCollection();
+ services.AddTransient();
+
+ var factory = GetParameterPolicyFactory(options, services);
+
+ // Act
+ var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "customParameterPolicy");
+
+ // Assert
+ Assert.IsType(parameterPolicy);
+ }
+
+ [Fact]
+ public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicyWithArgumentAndServices()
+ {
+ // Arrange
+ var options = new RouteOptions();
+ options.ConstraintMap.Add("customConstraintPolicy", typeof(CustomParameterPolicyWithArguments));
+
+ var services = new ServiceCollection();
+ services.AddTransient();
+
+ var factory = GetParameterPolicyFactory(options, services);
+
+ // Act
+ var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(20)");
+
+ // Assert
+ var constraint = Assert.IsType(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();
+
+ var factory = GetParameterPolicyFactory(options, services);
+
+ // Act
+ var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(20,-1)");
+
+ // Assert
+ var constraint = Assert.IsType(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();
+
+ var factory = GetParameterPolicyFactory(options, services);
+
+ // Act
+ var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy");
+
+ // Assert
+ var constraint = Assert.IsType(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();
+
+ var factory = GetParameterPolicyFactory(options, services);
+
+ // Act
+ var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(1)");
+
+ // Assert
+ var constraint = Assert.IsType(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();
+
+ var factory = GetParameterPolicyFactory(options, services);
+
+ // Act
+ var exception = Assert.Throws(
+ () => 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();
+
+ var factory = GetParameterPolicyFactory(options, services);
+
+ // Act
+ var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), @"regex-service(\\d{1,2})");
+
+ // Assert
+ var constraint = Assert.IsType(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(
+ () => factory.Create(RoutePatternFactory.ParameterPart("id"), "customConstraintPolicy(20)"));
+
+ // Assert
+ var inner = Assert.IsType(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();
+
+ var factory = GetParameterPolicyFactory(options, services);
+
+ // Act
+ var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "customParameterPolicy");
+
+ // Assert
+ Assert.IsType(parameterPolicy);
+ }
+
+ private DefaultParameterPolicyFactory GetParameterPolicyFactory(
+ RouteOptions options = null,
+ ServiceCollection services = null)
+ {
+ if (options == null)
+ {
+ options = new RouteOptions();
+ }
+
+ if (services == null)
+ {
+ services = new ServiceCollection();
+ }
+
+ return new DefaultParameterPolicyFactory(
+ Options.Create(options),
+ services.BuildServiceProvider());
+ }
+
+ private class TestRouteConstraint : IRouteConstraint
+ {
+ private TestRouteConstraint() { }
+
+ public HttpContext HttpContext { get; private set; }
+ public IRouter Route { get; private set; }
+ public string RouteKey { get; private set; }
+ public RouteValueDictionary Values { get; private set; }
+ public RouteDirection RouteDirection { get; private set; }
+
+ public static TestRouteConstraint Create()
+ {
+ return new TestRouteConstraint();
+ }
+
+ public bool Match(
+ HttpContext httpContext,
+ IRouter route,
+ string routeKey,
+ RouteValueDictionary values,
+ RouteDirection routeDirection)
+ {
+ HttpContext = httpContext;
+ Route = route;
+ RouteKey = routeKey;
+ Values = values;
+ RouteDirection = routeDirection;
+ return false;
+ }
+ }
+ }
+
+ 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; }
+ }
+}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/InlineRouteParameterParserTests.cs b/test/Microsoft.AspNetCore.Routing.Tests/InlineRouteParameterParserTests.cs
index 0e570c49cc..ccd44a8318 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/InlineRouteParameterParserTests.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/InlineRouteParameterParserTests.cs
@@ -968,7 +968,7 @@ namespace Microsoft.AspNetCore.Routing.Tests
.Add("test", typeof(TestRouteConstraint)));
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService>();
- return new DefaultInlineConstraintResolver(accessor);
+ return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
private class TestRouteConstraint : IRouteConstraint
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultParameterPolicyFactoryTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultParameterPolicyFactoryTest.cs
deleted file mode 100644
index abfb7bde3a..0000000000
--- a/test/Microsoft.AspNetCore.Routing.Tests/Matching/DefaultParameterPolicyFactoryTest.cs
+++ /dev/null
@@ -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(
- () => factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), @"notpresent(\d+)"));
-
- // Assert
- Assert.Equal(
- $"The constraint reference 'notpresent' could not be resolved to a type. " +
- $"Register the constraint type with '{typeof(RouteOptions)}.{nameof(RouteOptions.ConstraintMap)}'.",
- exception.Message);
- }
-
- [Fact]
- public void Create_ThrowsException_OnInvalidType()
- {
- // Arrange
- var options = new RouteOptions();
- options.ConstraintMap.Add("bad", typeof(string));
-
- var services = new ServiceCollection();
-
- var factory = GetParameterPolicyFactory(options, services);
-
- // Act
- var exception = Assert.Throws(
- () => factory.Create(RoutePatternFactory.ParameterPart("id"), @"bad"));
-
- // Assert
- Assert.Equal(
- $"Invalid constraint type '{typeof(string)}' registered as 'bad'. " +
- $"A constraint type must either implement '{typeof(IRouteConstraint)}', or inherit from '{typeof(IParameterPolicy)}'.",
- exception.Message);
- }
-
- [Fact]
- public void Create_CreatesParameterPolicy_FromRoutePattern_String()
- {
- // Arrange
- var factory = GetParameterPolicyFactory();
-
- var parameter = RoutePatternFactory.ParameterPart(
- "id",
- @default: null,
- parameterKind: RoutePatternParameterKind.Standard,
- parameterPolicies: new[] { RoutePatternFactory.Constraint("int"), });
-
- // Act
- var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);
-
- // Assert
- Assert.IsType(parameterPolicy);
- }
-
- [Fact]
- public void Create_CreatesParameterPolicy_FromRoutePattern_String_Optional()
- {
- // Arrange
- var factory = GetParameterPolicyFactory();
-
- var parameter = RoutePatternFactory.ParameterPart(
- "id",
- @default: null,
- parameterKind: RoutePatternParameterKind.Optional,
- parameterPolicies: new[] { RoutePatternFactory.Constraint("int"), });
-
- // Act
- var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);
-
- // Assert
- var optionalConstraint = Assert.IsType(parameterPolicy);
- Assert.IsType(optionalConstraint.InnerConstraint);
- }
-
- [Fact]
- public void Create_CreatesParameterPolicy_FromRoutePattern_Constraint()
- {
- // Arrange
- var factory = GetParameterPolicyFactory();
-
- var parameter = RoutePatternFactory.ParameterPart(
- "id",
- @default: null,
- parameterKind: RoutePatternParameterKind.Standard,
- parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new IntRouteConstraint()), });
-
- // Act
- var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);
-
- // Assert
- Assert.IsType(parameterPolicy);
- }
-
- [Fact]
- public void Create_CreatesParameterPolicy_FromRoutePattern_Constraint_Optional()
- {
- // Arrange
- var factory = GetParameterPolicyFactory();
-
- var parameter = RoutePatternFactory.ParameterPart(
- "id",
- @default: null,
- parameterKind: RoutePatternParameterKind.Optional,
- parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new IntRouteConstraint()), });
-
- // Act
- var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);
-
- // Assert
- var optionalConstraint = Assert.IsType(parameterPolicy);
- Assert.IsType(optionalConstraint.InnerConstraint);
- }
-
- [Fact]
- public void Create_CreatesParameterPolicy_FromRoutePattern_ParameterPolicy()
- {
- // Arrange
- var factory = GetParameterPolicyFactory();
-
- var parameter = RoutePatternFactory.ParameterPart(
- "id",
- @default: null,
- parameterKind: RoutePatternParameterKind.Standard,
- parameterPolicies: new[] { RoutePatternFactory.ParameterPolicy(new CustomParameterPolicy()), });
-
- // Act
- var parameterPolicy = factory.Create(parameter, parameter.ParameterPolicies[0]);
-
- // Assert
- Assert.IsType(parameterPolicy);
- }
-
- private class CustomParameterPolicy : IParameterPolicy
- {
- }
-
- [Fact]
- public void Create_CreatesParameterPolicy_FromConstraintText_AndRouteConstraint()
- {
- // Arrange
- var factory = GetParameterPolicyFactory();
-
- // Act
- var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id"), "int");
-
- // Assert
- Assert.IsType(parameterPolicy);
- }
-
- [Fact]
- public void Create_CreatesParameterPolicy_FromConstraintText_AndRouteConstraint_Optional()
- {
- // Arrange
- var factory = GetParameterPolicyFactory();
-
- // Act
- var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "int");
-
- // Assert
- var optionalConstraint = Assert.IsType(parameterPolicy);
- Assert.IsType(optionalConstraint.InnerConstraint);
- }
-
- [Fact]
- public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicy()
- {
- // Arrange
- var options = new RouteOptions();
- options.ConstraintMap.Add("customParameterPolicy", typeof(CustomParameterPolicy));
-
- var services = new ServiceCollection();
- services.AddTransient();
-
- var factory = GetParameterPolicyFactory(options, services);
-
- // Act
- var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "customParameterPolicy");
-
- // Assert
- Assert.IsType(parameterPolicy);
- }
-
- [Fact]
- public void Create_CreatesParameterPolicy_FromConstraintText_AndParameterPolicy_Optional()
- {
- // Arrange
- var options = new RouteOptions();
- options.ConstraintMap.Add("customParameterPolicy", typeof(CustomParameterPolicy));
-
- var services = new ServiceCollection();
- services.AddTransient();
-
- var factory = GetParameterPolicyFactory(options, services);
-
- // Act
- var parameterPolicy = factory.Create(RoutePatternFactory.ParameterPart("id", @default: null, RoutePatternParameterKind.Optional), "customParameterPolicy");
-
- // Assert
- Assert.IsType(parameterPolicy);
- }
-
- private DefaultParameterPolicyFactory GetParameterPolicyFactory(
- RouteOptions options = null,
- ServiceCollection services = null)
- {
- if (options == null)
- {
- options = new RouteOptions();
- }
-
- if (services == null)
- {
- services = new ServiceCollection();
- }
-
- return new DefaultParameterPolicyFactory(
- Options.Create(options),
- services.BuildServiceProvider());
- }
-
- private class TestRouteConstraint : IRouteConstraint
- {
- private TestRouteConstraint() { }
-
- public HttpContext HttpContext { get; private set; }
- public IRouter Route { get; private set; }
- public string RouteKey { get; private set; }
- public RouteValueDictionary Values { get; private set; }
- public RouteDirection RouteDirection { get; private set; }
-
- public static TestRouteConstraint Create()
- {
- return new TestRouteConstraint();
- }
-
- public bool Match(
- HttpContext httpContext,
- IRouter route,
- string routeKey,
- RouteValueDictionary values,
- RouteDirection routeDirection)
- {
- HttpContext = httpContext;
- Route = route;
- RouteKey = routeKey;
- Values = values;
- RouteDirection = routeDirection;
- return false;
- }
- }
- }
-}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matching/RouteMatcherBuilder.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matching/RouteMatcherBuilder.cs
index ba8d46a920..5d21424cb5 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/Matching/RouteMatcherBuilder.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/Matching/RouteMatcherBuilder.cs
@@ -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();
}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Matching/TreeRouterMatcherBuilder.cs b/test/Microsoft.AspNetCore.Routing.Tests/Matching/TreeRouterMatcherBuilder.cs
index b151d4cf4e..83c5115120 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/Matching/TreeRouterMatcherBuilder.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/Matching/TreeRouterMatcherBuilder.cs
@@ -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(new UriBuilderContextPooledObjectPolicy()),
- new DefaultInlineConstraintResolver(Options.Create(new RouteOptions())));
+ new DefaultInlineConstraintResolver(Options.Create(new RouteOptions()), new TestServiceProvider()));
var selector = new DefaultEndpointSelector(Array.Empty());
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/RouteConstraintBuilderTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/RouteConstraintBuilderTest.cs
index 9eca4d7759..6fb5df1c3d 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/RouteConstraintBuilderTest.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/RouteConstraintBuilderTest.cs
@@ -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);
}
}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/RouteTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/RouteTest.cs
index 1a52c9dec6..81e20b041f 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/RouteTest.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/RouteTest.cs
@@ -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());
}
}
}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Template/TemplateBinderTests.cs b/test/Microsoft.AspNetCore.Routing.Tests/Template/TemplateBinderTests.cs
index c5fd2e7b9e..c3e4ebcb8c 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/Template/TemplateBinderTests.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/Template/TemplateBinderTests.cs
@@ -1293,7 +1293,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
var services = new ServiceCollection().AddOptions();
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService>();
- return new DefaultInlineConstraintResolver(accessor);
+ return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
private class PathAndQuery
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Template/TemplateMatcherTests.cs b/test/Microsoft.AspNetCore.Routing.Tests/Template/TemplateMatcherTests.cs
index 1e5eb7c39e..fc78ef4cdc 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/Template/TemplateMatcherTests.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/Template/TemplateMatcherTests.cs
@@ -1136,7 +1136,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
var services = new ServiceCollection().AddOptions();
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService>();
- return new DefaultInlineConstraintResolver(accessor);
+ return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
}
}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/TemplateParserDefaultValuesTests.cs b/test/Microsoft.AspNetCore.Routing.Tests/TemplateParserDefaultValuesTests.cs
index 96c126fd30..159fb6cea2 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/TemplateParserDefaultValuesTests.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/TemplateParserDefaultValuesTests.cs
@@ -143,7 +143,7 @@ namespace Microsoft.AspNetCore.Routing.Tests
var services = new ServiceCollection().AddOptions();
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService>();
- return new DefaultInlineConstraintResolver(accessor);
+ return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
}
}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouteBuilderTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouteBuilderTest.cs
index 2645e78439..dc9d2c7594 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouteBuilderTest.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouteBuilderTest.cs
@@ -260,7 +260,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
var services = new ServiceCollection().AddOptions();
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetRequiredService>();
- return new DefaultInlineConstraintResolver(accessor);
+ return new DefaultInlineConstraintResolver(accessor, serviceProvider);
}
}
}
diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouterTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouterTest.cs
index a99846126c..37ba101520 100644
--- a/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouterTest.cs
+++ b/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouterTest.cs
@@ -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>();
optionsMock.SetupGet(o => o.Value).Returns(options);
- return new DefaultInlineConstraintResolver(optionsMock.Object);
+ return new DefaultInlineConstraintResolver(optionsMock.Object, new TestServiceProvider());
}
private static TreeRouteBuilder CreateBuilder()