Merge branch 'merge/release/2.2-to-master'
This commit is contained in:
commit
2d8b187ca0
|
|
@ -36,6 +36,7 @@
|
||||||
<Compile Include="..\..\test\Microsoft.AspNetCore.Routing.Tests\Matching\TreeRouterMatcherBuilder.cs">
|
<Compile Include="..\..\test\Microsoft.AspNetCore.Routing.Tests\Matching\TreeRouterMatcherBuilder.cs">
|
||||||
<Link>Matching\TreeRouterMatcherBuilder.cs</Link>
|
<Link>Matching\TreeRouterMatcherBuilder.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\..\test\Microsoft.AspNetCore.Routing.Tests\TestObjects\TestServiceProvider.cs" Link="Matching\TestServiceProvider.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -41,16 +41,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
@ -64,6 +54,12 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
switch (routeDirection)
|
switch (routeDirection)
|
||||||
{
|
{
|
||||||
case RouteDirection.IncomingRequest:
|
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);
|
return AllowedMethods.Contains(httpContext.Request.Method, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
case RouteDirection.UrlGeneration:
|
case RouteDirection.UrlGeneration:
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -77,16 +77,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -40,16 +40,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -34,16 +34,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -40,16 +40,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -34,16 +34,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -30,16 +30,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -48,16 +48,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -44,16 +44,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -24,16 +24,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(route));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (routeKey == null)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -31,16 +31,6 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
|
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)
|
if (routeKey == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeKey));
|
throw new ArgumentNullException(nameof(routeKey));
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
@ -18,6 +16,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public class DefaultInlineConstraintResolver : IInlineConstraintResolver
|
public class DefaultInlineConstraintResolver : IInlineConstraintResolver
|
||||||
{
|
{
|
||||||
private readonly IDictionary<string, Type> _inlineConstraintMap;
|
private readonly IDictionary<string, Type> _inlineConstraintMap;
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="DefaultInlineConstraintResolver"/> class.
|
/// Initializes a new instance of the <see cref="DefaultInlineConstraintResolver"/> class.
|
||||||
|
|
@ -25,11 +24,23 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
/// <param name="routeOptions">
|
/// <param name="routeOptions">
|
||||||
/// Accessor for <see cref="RouteOptions"/> containing the constraints of interest.
|
/// Accessor for <see cref="RouteOptions"/> containing the constraints of interest.
|
||||||
/// </param>
|
/// </param>
|
||||||
|
[Obsolete("This constructor is obsolete. Use DefaultInlineConstraintResolver.ctor(IOptions<RouteOptions>, IServiceProvider) instead.")]
|
||||||
public DefaultInlineConstraintResolver(IOptions<RouteOptions> routeOptions)
|
public DefaultInlineConstraintResolver(IOptions<RouteOptions> routeOptions)
|
||||||
{
|
{
|
||||||
_inlineConstraintMap = routeOptions.Value.ConstraintMap;
|
_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 />
|
/// <inheritdoc />
|
||||||
/// <example>
|
/// <example>
|
||||||
/// A typical constraint looks like the following
|
/// A typical constraint looks like the following
|
||||||
|
|
@ -45,112 +56,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
throw new ArgumentNullException(nameof(inlineConstraint));
|
throw new ArgumentNullException(nameof(inlineConstraint));
|
||||||
}
|
}
|
||||||
|
|
||||||
string constraintKey;
|
return ParameterPolicyActivator.ResolveParameterPolicy<IRouteConstraint>(_inlineConstraintMap, _serviceProvider, inlineConstraint, out _);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Routing.Constraints;
|
using Microsoft.AspNetCore.Routing.Constraints;
|
||||||
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
if (parameterPolicy is IRouteConstraint routeConstraint)
|
if (parameterPolicy is IRouteConstraint routeConstraint)
|
||||||
{
|
{
|
||||||
return InitializeRouteConstraint(parameter?.IsOptional ?? false, routeConstraint, argument: null);
|
return InitializeRouteConstraint(parameter?.IsOptional ?? false, routeConstraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parameterPolicy;
|
return parameterPolicy;
|
||||||
|
|
@ -44,47 +44,26 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
throw new ArgumentNullException(nameof(inlineText));
|
throw new ArgumentNullException(nameof(inlineText));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example:
|
var parameterPolicy = ParameterPolicyActivator.ResolveParameterPolicy<IParameterPolicy>(_options.ConstraintMap, _serviceProvider, inlineText, out var parameterPolicyKey);
|
||||||
// {productId:regex(\d+)}
|
if (parameterPolicy == null)
|
||||||
//
|
|
||||||
// ParameterName: productId
|
|
||||||
// value: regex(\d+)
|
|
||||||
// name: regex
|
|
||||||
// argument: \d+
|
|
||||||
(var name, var argument) = Parse(inlineText);
|
|
||||||
|
|
||||||
if (!_options.ConstraintMap.TryGetValue(name, out var type))
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(Resources.FormatRoutePattern_ConstraintReferenceNotFound(
|
throw new InvalidOperationException(Resources.FormatRoutePattern_ConstraintReferenceNotFound(
|
||||||
name,
|
parameterPolicyKey,
|
||||||
typeof(RouteOptions),
|
typeof(RouteOptions),
|
||||||
nameof(RouteOptions.ConstraintMap)));
|
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);
|
||||||
return InitializeRouteConstraint(parameter?.IsOptional ?? false, constraint, argument);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof(IParameterPolicy).IsAssignableFrom(type))
|
return parameterPolicy;
|
||||||
{
|
|
||||||
var parameterPolicy = (IParameterPolicy)_serviceProvider.GetRequiredService(type);
|
|
||||||
return parameterPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
var message = Resources.FormatRoutePattern_InvalidStringConstraintReference(
|
|
||||||
type,
|
|
||||||
name,
|
|
||||||
typeof(IRouteConstraint),
|
|
||||||
typeof(IParameterPolicy));
|
|
||||||
throw new InvalidOperationException(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IParameterPolicy InitializeRouteConstraint(
|
private IParameterPolicy InitializeRouteConstraint(
|
||||||
bool optional,
|
bool optional,
|
||||||
IRouteConstraint routeConstraint,
|
IRouteConstraint routeConstraint)
|
||||||
string argument)
|
|
||||||
{
|
{
|
||||||
if (optional)
|
if (optional)
|
||||||
{
|
{
|
||||||
|
|
@ -93,25 +72,5 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
return routeConstraint;
|
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 System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Constraints;
|
using Microsoft.AspNetCore.Routing.Constraints;
|
||||||
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -324,11 +325,33 @@ namespace Microsoft.AspNetCore.Routing.Tests
|
||||||
ex.Message);
|
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>>();
|
var optionsAccessor = new Mock<IOptions<RouteOptions>>();
|
||||||
optionsAccessor.SetupGet(o => o.Value).Returns(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);
|
return new DefaultInlineConstraintResolver(optionsAccessor.Object);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MultiConstructorRouteConstraint : IRouteConstraint
|
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)));
|
.Add("test", typeof(TestRouteConstraint)));
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
|
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
|
||||||
return new DefaultInlineConstraintResolver(accessor);
|
return new DefaultInlineConstraintResolver(accessor, serviceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestRouteConstraint : IRouteConstraint
|
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 System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
@ -18,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
public RouteMatcherBuilder()
|
public RouteMatcherBuilder()
|
||||||
{
|
{
|
||||||
_constraintResolver = new DefaultInlineConstraintResolver(Options.Create(new RouteOptions()));
|
_constraintResolver = new DefaultInlineConstraintResolver(Options.Create(new RouteOptions()), new TestServiceProvider());
|
||||||
_endpoints = new List<RouteEndpoint>();
|
_endpoints = new List<RouteEndpoint>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
using Microsoft.AspNetCore.Routing.Tree;
|
using Microsoft.AspNetCore.Routing.Tree;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
|
|
@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
var builder = new TreeRouteBuilder(
|
var builder = new TreeRouteBuilder(
|
||||||
NullLoggerFactory.Instance,
|
NullLoggerFactory.Instance,
|
||||||
new DefaultObjectPool<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy()),
|
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>());
|
var selector = new DefaultEndpointSelector(Array.Empty<MatcherPolicy>());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Constraints;
|
using Microsoft.AspNetCore.Routing.Constraints;
|
||||||
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -183,7 +184,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
.SetupGet(o => o.Value)
|
.SetupGet(o => o.Value)
|
||||||
.Returns(new RouteOptions());
|
.Returns(new RouteOptions());
|
||||||
|
|
||||||
var inlineConstraintResolver = new DefaultInlineConstraintResolver(options.Object);
|
var inlineConstraintResolver = new DefaultInlineConstraintResolver(options.Object, new TestServiceProvider());
|
||||||
return new RouteConstraintBuilder(inlineConstraintResolver, template);
|
return new RouteConstraintBuilder(inlineConstraintResolver, template);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1842,7 +1842,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
.SetupGet(o => o.Value)
|
.SetupGet(o => o.Value)
|
||||||
.Returns(new RouteOptions());
|
.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 services = new ServiceCollection().AddOptions();
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
|
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
|
||||||
return new DefaultInlineConstraintResolver(accessor);
|
return new DefaultInlineConstraintResolver(accessor, serviceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PathAndQuery
|
private class PathAndQuery
|
||||||
|
|
|
||||||
|
|
@ -1136,7 +1136,7 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests
|
||||||
var services = new ServiceCollection().AddOptions();
|
var services = new ServiceCollection().AddOptions();
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
|
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 services = new ServiceCollection().AddOptions();
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
|
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 services = new ServiceCollection().AddOptions();
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
var accessor = serviceProvider.GetRequiredService<IOptions<RouteOptions>>();
|
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.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
|
|
@ -2133,7 +2134,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
var optionsMock = new Mock<IOptions<RouteOptions>>();
|
var optionsMock = new Mock<IOptions<RouteOptions>>();
|
||||||
optionsMock.SetupGet(o => o.Value).Returns(options);
|
optionsMock.SetupGet(o => o.Value).Returns(options);
|
||||||
|
|
||||||
return new DefaultInlineConstraintResolver(optionsMock.Object);
|
return new DefaultInlineConstraintResolver(optionsMock.Object, new TestServiceProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TreeRouteBuilder CreateBuilder()
|
private static TreeRouteBuilder CreateBuilder()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue