Support policy arguments and resolving services by constructors (#753)
This commit is contained in:
parent
40fb13a021
commit
99c4f2f36a
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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 _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>());
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue