Adding Remaining Inline Route Constraints.

This commit is contained in:
harshgMSFT 2014-06-10 12:15:20 -07:00
parent 0ca5576926
commit fbffcb7b40
47 changed files with 1828 additions and 84 deletions

View File

@ -45,11 +45,11 @@ namespace RoutingSample.Web
routeBuilder.MapRoute("regexStringRoute",
"api/rconstraint/{controller}",
new { foo = "Bar" },
new { controller = new RegexConstraint("^(my.*)$") });
new { controller = new RegexRouteConstraint("^(my.*)$") });
routeBuilder.MapRoute("regexRoute",
"api/r2constraint/{controller}",
new { foo = "Bar2" },
new { controller = new RegexConstraint(new Regex("^(my.*)$")) });
new { controller = new RegexRouteConstraint(new Regex("^(my.*)$")) });
routeBuilder.MapRoute("parameterConstraintRoute",
"api/{controller}/{*extra}",

View File

@ -0,0 +1,18 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to contain only lowercase or uppercase letters A through Z in the English alphabet.
/// </summary>
public class AlphaRouteConstraint : RegexRouteConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="AlphaRouteConstraint" /> class.
/// </summary>
public AlphaRouteConstraint() : base(@"^[a-z]*$")
{
}
}
}

View File

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to represent only Boolean values.
/// </summary>
public class BoolRouteConstraint : IRouteConstraint
{
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
if (value is bool)
{
return true;
}
bool result;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return Boolean.TryParse(valueString, out result);
}
return false;
}
}
}

View File

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to represent only <see cref="DateTime"/> values.
/// Supports date time formats represented by CultureInfo.DateTimeFormat for the CultureInfo.InvariantCulture.
/// </summary>
public class DateTimeRouteConstraint : IRouteConstraint
{
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
if (value is DateTime)
{
return true;
}
DateTime result;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return DateTime.TryParse(valueString, CultureInfo.InvariantCulture, DateTimeStyles.None, out result);
}
return false;
}
}
}

View File

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to represent only decimal values.
/// </summary>
public class DecimalRouteConstraint : IRouteConstraint
{
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
if (value is decimal)
{
return true;
}
decimal result;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return Decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out result);
}
return false;
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to represent only 64-bit floating-point values.
/// </summary>
public class DoubleRouteConstraint : IRouteConstraint
{
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
if (value is double)
{
return true;
}
double result;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return Double.TryParse(valueString,
NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.InvariantCulture,
out result);
}
return false;
}
}
}

View File

@ -0,0 +1,42 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to represent only 32-bit floating-point values.
/// </summary>
public class FloatRouteConstraint : IRouteConstraint
{
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
if (value is float)
{
return true;
}
float result;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return Single.TryParse(valueString,
NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.InvariantCulture,
out result);
}
return false;
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to represent only <see cref="Guid"/> values.
/// Matches values specified in any of the five formats "N", "D", "B", "P", or "X",
/// supported by Guid.ToString(string) and Guid.ToString(String, IFormatProvider) methods.
/// </summary>
public class GuidRouteConstraint : IRouteConstraint
{
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
if (value is Guid)
{
return true;
}
Guid result;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return Guid.TryParse(valueString, out result);
}
return false;
}
}
}

View File

@ -0,0 +1,91 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to be a string of a given length or within a given range of lengths.
/// </summary>
public class LengthRouteConstraint : IRouteConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="LengthRouteConstraint" /> class that constrains
/// a route parameter to be a string of a given length.
/// </summary>
/// <param name="length">The length of the route parameter.</param>
public LengthRouteConstraint(int length)
{
if (length < 0)
{
var errorMessage = Resources.FormatArgumentMustBeGreaterThanOrEqualTo(0);
throw new ArgumentOutOfRangeException("length", length, errorMessage);
}
MinLength = MaxLength = length;
}
/// <summary>
/// Initializes a new instance of the <see cref="LengthRouteConstraint" /> class that constrains
/// a route parameter to be a string of a given length.
/// </summary>
/// <param name="minLength">The minimum length allowed for the route parameter.</param>
/// <param name="maxLength">The maximum length allowed for the route parameter.</param>
public LengthRouteConstraint(int minLength, int maxLength)
{
if (minLength < 0)
{
var errorMessage = Resources.FormatArgumentMustBeGreaterThanOrEqualTo(0);
throw new ArgumentOutOfRangeException("minLength", minLength, errorMessage);
}
if (maxLength < 0)
{
var errorMessage = Resources.FormatArgumentMustBeGreaterThanOrEqualTo(0);
throw new ArgumentOutOfRangeException("maxLength", maxLength, errorMessage);
}
if (minLength > maxLength)
{
var errorMessage =
Resources.FormatRangeConstraint_MinShouldBeLessThanOrEqualToMax("minLength", "maxLength");
throw new ArgumentOutOfRangeException("minLength", minLength, errorMessage);
}
MinLength = minLength;
MaxLength = maxLength;
}
/// <summary>
/// Gets the minimum length allowed for the route parameter.
/// </summary>
public int MinLength { get; private set; }
/// <summary>
/// Gets the maximum length allowed for the route parameter.
/// </summary>
public int MaxLength { get; private set; }
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
var length = valueString.Length;
return length >= MinLength && length <= MaxLength;
}
return false;
}
}
}

View File

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to represent only 64-bit integer values.
/// </summary>
public class LongRouteConstraint : IRouteConstraint
{
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
if (value is long)
{
return true;
}
long result;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return Int64.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
}
return false;
}
}
}

View File

@ -0,0 +1,53 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to be a string with a maximum length.
/// </summary>
public class MaxLengthRouteConstraint : IRouteConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="MaxLengthRouteConstraint" /> class.
/// </summary>
/// <param name="maxLength">The maximum length allowed for the route parameter.</param>
public MaxLengthRouteConstraint(int maxLength)
{
if (maxLength < 0)
{
var errorMessage = Resources.FormatArgumentMustBeGreaterThanOrEqualTo(0);
throw new ArgumentOutOfRangeException("maxLength", maxLength, errorMessage);
}
MaxLength = maxLength;
}
/// <summary>
/// Gets the maximum length allowed for the route parameter.
/// </summary>
public int MaxLength { get; private set; }
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return valueString.Length <= MaxLength;
}
return false;
}
}
}

View File

@ -0,0 +1,51 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to be an integer with a maximum value.
/// </summary>
public class MaxRouteConstraint : IRouteConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="MaxRouteConstraint" /> class.
/// </summary>
/// <param name="max">The maximum value allowed for the route parameter.</param>
public MaxRouteConstraint(long max)
{
Max = max;
}
/// <summary>
/// Gets the maximum allowed value of the route parameter.
/// </summary>
public long Max { get; private set; }
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
long longValue;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
if (Int64.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out longValue))
{
return longValue <= Max;
}
}
return false;
}
}
}

View File

@ -0,0 +1,53 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to be a string with a minimum length.
/// </summary>
public class MinLengthRouteConstraint : IRouteConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="MinLengthRouteConstraint" /> class.
/// </summary>
/// <param name="minLength">The minimum length allowed for the route parameter.</param>
public MinLengthRouteConstraint(int minLength)
{
if (minLength < 0)
{
var errorMessage = Resources.FormatArgumentMustBeGreaterThanOrEqualTo(0);
throw new ArgumentOutOfRangeException("minLength", minLength, errorMessage);
}
MinLength = minLength;
}
/// <summary>
/// Gets the minimum length allowed for the route parameter.
/// </summary>
public int MinLength { get; private set; }
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return valueString.Length >= MinLength;
}
return false;
}
}
}

View File

@ -0,0 +1,51 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constrains a route parameter to be a long with a minimum value.
/// </summary>
public class MinRouteConstraint : IRouteConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="MinRouteConstraint" /> class.
/// </summary>
/// <param name="min">The minimum value allowed for the route parameter.</param>
public MinRouteConstraint(long min)
{
Min = min;
}
/// <summary>
/// Gets the minimum allowed value of the route parameter.
/// </summary>
public long Min { get; private set; }
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
long longValue;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
if (Int64.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out longValue))
{
return longValue >= Min;
}
}
return false;
}
}
}

View File

@ -0,0 +1,65 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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 Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constraints a route parameter to be an integer within a given range of values.
/// </summary>
public class RangeRouteConstraint : IRouteConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="RangeRouteConstraint" /> class.
/// </summary>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <remarks>The minimum value should be less than or equal to the maximum value.</remarks>
public RangeRouteConstraint(long min, long max)
{
if (min > max)
{
var errorMessage = Resources.FormatRangeConstraint_MinShouldBeLessThanOrEqualToMax("min", "max");
throw new ArgumentOutOfRangeException("min", min, errorMessage);
}
Min = min;
Max = max;
}
/// <summary>
/// Gets the minimum allowed value of the route parameter.
/// </summary>
public long Min { get; private set; }
/// <summary>
/// Gets the maximum allowed value of the route parameter.
/// </summary>
public long Max { get; private set; }
/// <inheritdoc />
public bool Match([NotNull] HttpContext httpContext,
[NotNull] IRouter route,
[NotNull] string routeKey,
[NotNull] IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
long longValue;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
if (Int64.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out longValue))
{
return longValue >= Min && longValue <= Max;
}
}
return false;
}
}
}

View File

@ -9,14 +9,14 @@ using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
public class RegexConstraint : IRouteConstraint
public class RegexRouteConstraint : IRouteConstraint
{
public RegexConstraint([NotNull] Regex regex)
public RegexRouteConstraint([NotNull] Regex regex)
{
Constraint = regex;
}
public RegexConstraint([NotNull] string regexPattern)
public RegexRouteConstraint([NotNull] string regexPattern)
{
Constraint = new Regex(regexPattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
}

View File

@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Routing
{
throw new InvalidOperationException(
Resources.FormatDefaultInlineConstraintResolver_CouldNotFindCtor(
constraintTypeInfo.Name, argumentString.Length));
constraintTypeInfo.Name, arguments.Length));
}
else if (constructorMatches == 1)
{
@ -113,7 +113,7 @@ namespace Microsoft.AspNet.Routing
{
throw new InvalidOperationException(
Resources.FormatDefaultInlineConstraintResolver_AmbiguousCtors(
constraintTypeInfo.Name, argumentString.Length));
constraintTypeInfo.Name, arguments.Length));
}
}

View File

@ -78,18 +78,18 @@ namespace Microsoft.AspNet.Routing
}
private static IRouteConstraint GetInlineConstraint(Group constraintGroup,
IInlineConstraintResolver constraintResolver)
IInlineConstraintResolver _constraintResolver)
{
var parameterConstraints = new List<IRouteConstraint>();
foreach (Capture constraintCapture in constraintGroup.Captures)
{
var inlineConstraint = constraintCapture.Value;
var constraint = constraintResolver.ResolveConstraint(inlineConstraint);
var constraint = _constraintResolver.ResolveConstraint(inlineConstraint);
if (constraint == null)
{
throw new InvalidOperationException(
Resources.FormatInlineRouteParser_CouldNotResolveConstraint(
constraintResolver.GetType().Name, inlineConstraint));
_constraintResolver.GetType().Name, inlineConstraint));
}
parameterConstraints.Add(constraint);

View File

@ -25,8 +25,22 @@
<ItemGroup>
<Compile Include="BuilderExtensions.cs" />
<Compile Include="Constraints\CompositeRouteConstraint.cs" />
<Compile Include="Constraints\DateTimeRouteConstraint.cs" />
<Compile Include="Constraints\DoubleRouteConstraint.cs" />
<Compile Include="Constraints\DecimalRouteConstraint.cs" />
<Compile Include="Constraints\FloatRouteConstraint.cs" />
<Compile Include="Constraints\GuidRouteConstraint.cs" />
<Compile Include="Constraints\AlphaRouteConstraint.cs" />
<Compile Include="Constraints\LongRouteConstraint.cs" />
<Compile Include="Constraints\MaxLengthRouteConstraint.cs" />
<Compile Include="Constraints\MaxRouteConstraint.cs" />
<Compile Include="Constraints\MinLengthRouteConstraint.cs" />
<Compile Include="Constraints\RangeRouteConstraint.cs" />
<Compile Include="Constraints\MinRouteConstraint.cs" />
<Compile Include="Constraints\LengthRouteConstraint.cs" />
<Compile Include="Constraints\BoolRouteConstraint.cs" />
<Compile Include="Constraints\IntRouteConstraint.cs" />
<Compile Include="Constraints\RegexConstraint.cs" />
<Compile Include="Constraints\RegexRouteConstraint.cs" />
<Compile Include="DefaultInlineConstraintResolver.cs" />
<Compile Include="IInlineConstraintResolver.cs" />
<Compile Include="INamedRouter.cs" />
@ -46,9 +60,9 @@
<Compile Include="RouteContext.cs" />
<Compile Include="RouteData.cs" />
<Compile Include="RouteDirection.cs" />
<Compile Include="RouterServices.cs" />
<Compile Include="RouterMiddleware.cs" />
<Compile Include="RouteValueDictionary.cs" />
<Compile Include="RoutingServices.cs" />
<Compile Include="Template\Template.cs" />
<Compile Include="Template\TemplateBinder.cs" />
<Compile Include="Template\TemplateMatcher.cs" />

View File

@ -10,6 +10,38 @@ namespace Microsoft.AspNet.Routing
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNet.Routing.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// Value must be greater than or equal to {0}.
/// </summary>
internal static string ArgumentMustBeGreaterThanOrEqualTo
{
get { return GetString("ArgumentMustBeGreaterThanOrEqualTo"); }
}
/// <summary>
/// Value must be greater than or equal to {0}.
/// </summary>
internal static string FormatArgumentMustBeGreaterThanOrEqualTo(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentMustBeGreaterThanOrEqualTo"), p0);
}
/// <summary>
/// The value for argument '{0}' should be less than or equal to the value for the argument '{1}'.
/// </summary>
internal static string RangeConstraint_MinShouldBeLessThanOrEqualToMax
{
get { return GetString("RangeConstraint_MinShouldBeLessThanOrEqualToMax"); }
}
/// <summary>
/// The value for argument '{0}' should be less than or equal to the value for the argument '{1}'.
/// </summary>
internal static string FormatRangeConstraint_MinShouldBeLessThanOrEqualToMax(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("RangeConstraint_MinShouldBeLessThanOrEqualToMax"), p0, p1);
}
/// <summary>
/// The '{0}' property of '{1}' must not be null.
/// </summary>

View File

@ -117,6 +117,12 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentMustBeGreaterThanOrEqualTo" xml:space="preserve">
<value>Value must be greater than or equal to {0}.</value>
</data>
<data name="RangeConstraint_MinShouldBeLessThanOrEqualToMax" xml:space="preserve">
<value>The value for argument '{0}' should be less than or equal to the value for the argument '{1}'.</value>
</data>
<data name="PropertyOfTypeCannotBeNull" xml:space="preserve">
<value>The '{0}' property of '{1}' must not be null.</value>
</data>

View File

@ -58,7 +58,7 @@ namespace Microsoft.AspNet.Routing
var constraintsRegEx = "^(" + regexPattern + ")$";
constraint = new RegexConstraint(constraintsRegEx);
constraint = new RegexRouteConstraint(constraintsRegEx);
}
constraints.Add(kvp.Key, constraint);

View File

@ -36,6 +36,26 @@ namespace Microsoft.AspNet.Routing
{
// Type-specific constraints
{ "int", typeof(IntRouteConstraint) },
{ "bool", typeof(BoolRouteConstraint) },
{ "datetime", typeof(DateTimeRouteConstraint) },
{ "decimal", typeof(DecimalRouteConstraint) },
{ "double", typeof(DoubleRouteConstraint) },
{ "float", typeof(FloatRouteConstraint) },
{ "guid", typeof(GuidRouteConstraint) },
{ "long", typeof(LongRouteConstraint) },
// Length constraints
{ "minlength", typeof(MinLengthRouteConstraint) },
{ "maxlength", typeof(MaxLengthRouteConstraint) },
{ "length", typeof(LengthRouteConstraint) },
// Min/Max value constraints
{ "min", typeof(MinRouteConstraint) },
{ "max", typeof(MaxRouteConstraint) },
{ "range", typeof(RangeRouteConstraint) },
// Regex-based constraints
{ "alpha", typeof(AlphaRouteConstraint) },
};
}
}

View File

@ -0,0 +1,36 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class AlphaRouteConstraintTests
{
[Theory]
[InlineData("alpha", true)]
[InlineData("a1pha", false)]
[InlineData("ALPHA", true)]
[InlineData("A1PHA", false)]
[InlineData("alPHA", true)]
[InlineData("A1pHA", false)]
[InlineData("AlpHA╥", false)]
[InlineData("", true)]
public void AlphaRouteConstraintTest(string parameterValue, bool expected)
{
// Arrange
var constraint = new AlphaRouteConstraint();
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,44 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing.Constraints;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class BoolRouteConstraintTests
{
[Theory]
[InlineData("true", true)]
[InlineData("TruE", true)]
[InlineData("false", true)]
[InlineData("FalSe", true)]
[InlineData(" FalSe", true)]
[InlineData("True ", true)]
[InlineData(" False ", true)]
[InlineData(true, true)]
[InlineData(false, true)]
[InlineData(1, false)]
[InlineData("not-parseable-as-bool", false)]
public void BoolRouteConstraint(object parameterValue, bool expected)
{
// Arrange
var constraint = new BoolRouteConstraint();
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -7,38 +7,19 @@ using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing.Constraints;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class RouteConstraintsTests
public class CompositeRouteConstraintTests
{
[Theory]
[InlineData(42, true)]
[InlineData("42", true)]
[InlineData(3.14, false)]
[InlineData("43.567", false)]
[InlineData("42a", false)]
public void IntRouteConstraint_Match_AppliesConstraint(object parameterValue, bool expected)
{
// Arrange
var constraint = new IntRouteConstraint();
// Act
var actual = TestValue(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(true, true, true)]
[InlineData(true, false, false)]
[InlineData(false, true, false)]
[InlineData(false, false, false)]
public void CompoundRouteConstraint_Match_CallsMatchOnInnerConstraints(bool inner1Result,
public void CompositeRouteConstraint_Match_CallsMatchOnInnerConstraints(bool inner1Result,
bool inner2Result,
bool expected)
{
@ -48,7 +29,7 @@ namespace Microsoft.AspNet.Routing.Tests
// Act
var constraint = new CompositeRouteConstraint(new[] { inner1.Object, inner2.Object });
var actual = TestValue(constraint, null);
var actual = ConstraintsTestHelper.TestConstraint(constraint, null);
// Assert
Assert.Equal(expected, actual);
@ -69,28 +50,6 @@ namespace Microsoft.AspNet.Routing.Tests
.Verifiable();
return mock;
}
private static void AssertMatchWasCalled(Mock<IRouteConstraint> mock, Times times)
{
mock.Verify(ConstraintMatchMethodExpression, times);
}
private static bool TestValue(IRouteConstraint constraint, object value, Action<IRouter> routeConfig = null)
{
var context = new Mock<HttpContext>();
IRouter route = new RouteCollection();
if (routeConfig != null)
{
routeConfig(route);
}
var parameterName = "fake";
var values = new Dictionary<string, object>() { { parameterName, value } };
var routeDirection = RouteDirection.IncomingRequest;
return constraint.Match(context.Object, route, parameterName, values, routeDirection);
}
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Http;
using Moq;
namespace Microsoft.AspNet.Routing.Tests
{
public class ConstraintsTestHelper
{
public static bool TestConstraint(IRouteConstraint constraint, object value, Action<IRouter> routeConfig = null)
{
var context = new Mock<HttpContext>();
var route = new RouteCollection();
if (routeConfig != null)
{
routeConfig(route);
}
var parameterName = "fake";
var values = new Dictionary<string, object>() { { parameterName, value } };
var routeDirection = RouteDirection.IncomingRequest;
return constraint.Match(context.Object, route, parameterName, values, routeDirection);
}
}
}
#endif

View File

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class DateTimeRouteConstraintTests
{
public static IEnumerable<object[]> GetDateTimeObject
{
get
{
yield return new object[]
{
DateTime.Now,
true
};
}
}
[Theory]
[InlineData("12/25/2009", true)]
[InlineData("25/12/2009 11:45:00 PM", false)]
[InlineData("25/12/2009", false)]
[InlineData("11:45:00 PM", true)]
[InlineData("11:45:00", true)]
[InlineData("11:45", true)]
[InlineData("11", false)]
[InlineData("", false)]
[InlineData("Apr 5 2009 11:45:00 PM", true)]
[InlineData("April 5 2009 11:45:00 PM", true)]
[InlineData("12/25/2009 11:45:00 PM", true)]
[InlineData("11:45:00 PM", true)]
[InlineData("2009-05-12T11:45:00Z", true)]
[InlineData("not-parseable-as-date", false)]
[InlineData(false, false)]
[MemberData("GetDateTimeObject")]
public void DateTimeRouteConstraint(object parameterValue, bool expected)
{
// Arrange
var constraint = new DateTimeRouteConstraint();
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,47 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System.Collections.Generic;
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class DecimalRouteConstraintTests
{
public static IEnumerable<object[]> GetDecimalObject
{
get
{
yield return new object[]
{
2m,
true
};
}
}
[Theory]
[InlineData("3.14", true)]
[InlineData("9223372036854775808.9223372036854775808", true)]
[InlineData("1.79769313486232E+300", false)]
[InlineData("not-parseable-as-decimal", false)]
[InlineData(false, false)]
[MemberData("GetDecimalObject")]
public void DecimalRouteConstraint_ApplyConstraint(object parameterValue, bool expected)
{
// Arrange
var constraint = new DecimalRouteConstraint();
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class DoubleRouteConstraintTests
{
[Theory]
[InlineData("3.14", true)]
[InlineData(3.14f, true)]
[InlineData(3.14d, true)]
[InlineData("1.79769313486232E+300", true)]
[InlineData("not-parseable-as-double", false)]
[InlineData(false, false)]
public void DoubleRouteConstraint_ApplyConstraint(object parameterValue, bool expected)
{
// Arrange
var constraint = new DoubleRouteConstraint();
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class FloatRouteConstraintTests
{
[Theory]
[InlineData("3.14", true)]
[InlineData(3.14, true)]
[InlineData("not-parseable-as-float", false)]
[InlineData(false, false)]
[InlineData("1.79769313486232E+300", false)]
public void FloatRouteConstraint_ApplyConstraint(object parameterValue, bool expected)
{
// Arrange
var constraint = new FloatRouteConstraint();
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class GuidRouteConstraintTests
{
[Theory]
[InlineData("12345678-1234-1234-1234-123456789012", false, true)]
[InlineData("12345678-1234-1234-1234-123456789012", true, true)]
[InlineData("12345678901234567890123456789012", false, true)]
[InlineData("not-parseable-as-guid", false, false)]
[InlineData(12, false, false)]
public void GuidRouteConstraint_ApplyConstraint(object parameterValue, bool parseBeforeTest, bool expected)
{
// Arrange
if (parseBeforeTest)
{
parameterValue = Guid.Parse(parameterValue.ToString());
}
var constraint = new GuidRouteConstraint();
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class IntRouteConstraintsTests
{
[Theory]
[InlineData(42, true)]
[InlineData("42", true)]
[InlineData(3.14, false)]
[InlineData("43.567", false)]
[InlineData("42a", false)]
public void IntRouteConstraint_Match_AppliesConstraint(object parameterValue, bool expected)
{
// Arrange
var constraint = new IntRouteConstraint();
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,90 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class LengthRouteConstraintTests
{
[Theory]
[InlineData(3, "123", true)]
[InlineData(3, "1234", false)]
[InlineData(0, "", true)]
public void LengthRouteConstraint_ExactLength_Tests(int length, string parameterValue, bool expected)
{
// Arrange
var constraint = new LengthRouteConstraint(length);
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(3, 5, "12", false)]
[InlineData(3, 5, "123", true)]
[InlineData(3, 5, "1234", true)]
[InlineData(3, 5, "12345", true)]
[InlineData(3, 5, "123456", false)]
public void LengthRouteConstraint_Range_Tests(int min, int max, string parameterValue, bool expected)
{
// Arrange
var constraint = new LengthRouteConstraint(min, max);
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void LengthRouteConstraint_SettingLengthLessThanZero_Throws()
{
// Act & Assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new LengthRouteConstraint(-1));
Assert.Equal("Value must be greater than or equal to 0.\r\nParameter name: length\r\n" +
"Actual value was -1.",
ex.Message);
}
[Fact]
public void LengthRouteConstraint_SettingMinLengthLessThanZero_Throws()
{
// Act & Assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new LengthRouteConstraint(-1, 3));
Assert.Equal("Value must be greater than or equal to 0.\r\nParameter name: minLength\r\n"+
"Actual value was -1.",
ex.Message);
}
[Fact]
public void LengthRouteConstraint_SettingMaxLengthLessThanZero_Throws()
{
// Act & Assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new LengthRouteConstraint(0, -1));
Assert.Equal("Value must be greater than or equal to 0.\r\nParameter name: maxLength\r\n" +
"Actual value was -1.",
ex.Message);
}
[Fact]
public void LengthRouteConstraint_MinGreaterThanMax_Throws()
{
// Arrange Act & Assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new LengthRouteConstraint(3, 2));
Assert.Equal("The value for argument 'minLength' should be less than or equal to the "+
"value for the argument 'maxLength'.\r\nParameter name: minLength\r\nActual value was 3.",
ex.Message);
}
}
}
#endif

View File

@ -0,0 +1,35 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class LongRouteConstraintTests
{
[Theory]
[InlineData(42, true)]
[InlineData(42L, true)]
[InlineData("42", true)]
[InlineData("9223372036854775807", true)]
[InlineData(3.14, false)]
[InlineData("43.567", false)]
[InlineData("42a", false)]
public void LongRouteConstraintTest(object parameterValue, bool expected)
{
// Arrange
var constraint = new LongRouteConstraint();
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,43 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class MaxLengthRouteConstraintTests
{
[Theory]
[InlineData(3, "", true)]
[InlineData(3, "12", true)]
[InlineData(3, "123", true)]
[InlineData(3, "1234", false)]
public void MaxLengthRouteConstraint_ApplyConstraint(int min, string parameterValue, bool expected)
{
// Arrange
var constraint = new MaxLengthRouteConstraint(min);
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void MaxLengthRouteConstraint_SettingMaxLengthLessThanZero_Throws()
{
// Act & Assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(()=> new MaxLengthRouteConstraint(-1));
Assert.Equal("Value must be greater than or equal to 0.\r\nParameter name: maxLength\r\n" +
"Actual value was -1.",
ex.Message);
}
}
}
#endif

View File

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class MaxRouteConstraintTests
{
[Theory]
[InlineData(3, 2, true)]
[InlineData(3, 3, true)]
[InlineData(3, 4, false)]
public void MaxRouteConstraint_ApplyConstraint(long max, int parameterValue, bool expected)
{
// Arrange
var constraint = new MaxRouteConstraint(max);
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,43 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class MinLengthRouteConstraintTests
{
[Theory]
[InlineData(3, "1234", true)]
[InlineData(3, "123", true)]
[InlineData(3, "12", false)]
[InlineData(3, "", false)]
public void MinLengthRouteConstraint_ApplyConstraint(int min, string parameterValue, bool expected)
{
// Arrange
var constraint = new MinLengthRouteConstraint(min);
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void MinLengthRouteConstraint_SettingMinLengthLessThanZero_Throws()
{
// Act & Assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new MinLengthRouteConstraint(-1));
Assert.Equal("Value must be greater than or equal to 0.\r\nParameter name: minLength\r\n" +
"Actual value was -1.",
ex.Message);
}
}
}
#endif

View File

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class MinRouteConstraintTests
{
[Theory]
[InlineData(3, 4, true)]
[InlineData(3, 3, true)]
[InlineData(3, 2, false)]
public void MinRouteConstraint_ApplyConstraint(long min, int parameterValue, bool expected)
{
// Arrange
var constraint = new MinRouteConstraint(min);
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
}
}
#endif

View File

@ -0,0 +1,47 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using Microsoft.AspNet.Routing.Constraints;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class RangeRouteConstraintTests
{
[Theory]
[InlineData(long.MinValue, long.MaxValue, 2, true)]
[InlineData(3, 5, 3, true)]
[InlineData(3, 5, 4, true)]
[InlineData(3, 5, 5, true)]
[InlineData(3, 5, 6, false)]
[InlineData(3, 5, 2, false)]
[InlineData(3, 3, 2, false)]
[InlineData(3, 3, 3, true)]
public void RangeRouteConstraintTest_ValidValue_ApplyConstraint(long min, long max, int parameterValue, bool expected)
{
// Arrange
var constraint = new RangeRouteConstraint(min, max);
// Act
var actual = ConstraintsTestHelper.TestConstraint(constraint, parameterValue);
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void RangeRouteConstraint_MinGreaterThanMax_Throws()
{
// Arrange Act & Assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new RangeRouteConstraint(3, 2));
Assert.Equal("The value for argument 'min' should be less than or equal to the value for the argument "+
"'max'.\r\nParameter name: min\r\nActual value was 3.",
ex.Message);
}
}
}
#endif

View File

@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Routing.Tests
bool shouldMatch)
{
// Arrange
var constraint = new RegexConstraint(constraintValue);
var constraint = new RegexRouteConstraint(constraintValue);
var values = new RouteValueDictionary(new {controller = routeValue});
// Assert
@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Routing.Tests
public void RegexConstraint_TakesRegexAsInput_SimpleMatch()
{
// Arrange
var constraint = new RegexConstraint(new Regex("^abc$"));
var constraint = new RegexRouteConstraint(new Regex("^abc$"));
var values = new RouteValueDictionary(new { controller = "abc"});
// Assert
@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Routing.Tests
public void RegexConstraintConstructedWithRegex_SimpleFailedMatch()
{
// Arrange
var constraint = new RegexConstraint(new Regex("^abc$"));
var constraint = new RegexRouteConstraint(new Regex("^abc$"));
var values = new RouteValueDictionary(new { controller = "Abc" });
// Assert
@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Routing.Tests
public void RegexConstraintFailsIfKeyIsNotFoundInRouteValues()
{
// Arrange
var constraint = new RegexConstraint(new Regex("^abc$"));
var constraint = new RegexRouteConstraint(new Regex("^abc$"));
var values = new RouteValueDictionary(new { action = "abc" });
// Assert
@ -71,7 +71,7 @@ namespace Microsoft.AspNet.Routing.Tests
public void RegexConstraintIsCultureInsensitiveWhenConstructredWithString()
{
// Arrange
var constraint = new RegexConstraint("^([a-z]+)$");
var constraint = new RegexRouteConstraint("^([a-z]+)$");
var values = new RouteValueDictionary(new { controller = "\u0130" }); // Turkish upper-case dotted I
var currentThread = Thread.CurrentThread;

View File

@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Routing.Tests
var constraint = constraintDictionary["controller"];
Assert.IsType<RegexConstraint>(constraint);
Assert.IsType<RegexRouteConstraint>(constraint);
}
[Fact]

View File

@ -15,15 +15,18 @@ namespace Microsoft.AspNet.Routing.Tests
{
public class DefaultInlineConstraintResolverTest
{
private IInlineConstraintResolver _constraintResolver;
public DefaultInlineConstraintResolverTest()
{
var routeOptions = new RouteOptions();
_constraintResolver = GetInlineConstraintResolver(routeOptions);
}
[Fact]
public void ResolveConstraint_IntConstraint_ResolvesCorrectly()
{
// Arrange
var routeOptions = new RouteOptions();
var constraintResolver = GetInlineConstraintResolver(routeOptions);
// Act
var constraint = constraintResolver.ResolveConstraint("int");
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("int");
// Assert
Assert.IsType<IntRouteConstraint>(constraint);
@ -32,17 +35,190 @@ namespace Microsoft.AspNet.Routing.Tests
[Fact]
public void ResolveConstraint_IntConstraintWithArgument_Throws()
{
// Arrange
var routeOptions = new RouteOptions();
var constraintResolver = GetInlineConstraintResolver(routeOptions);
// Act & Assert
// Arrange, Act & Assert
var ex = Assert.Throws<InvalidOperationException>(
() => constraintResolver.ResolveConstraint("int(5)"));
() => _constraintResolver.ResolveConstraint("int(5)"));
Assert.Equal("Could not find a constructor for constraint type 'IntRouteConstraint'"+
" with the following number of parameters: 1.",
ex.Message);
}
[Fact]
public void ResolveConstraint_AlphaConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("alpha");
// Assert
Assert.IsType<AlphaRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_BoolConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("bool");
// Assert
Assert.IsType<BoolRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_CompositeConstraintIsNotRegistered()
{
// Arrange, Act & Assert
Assert.Null(_constraintResolver.ResolveConstraint("composite"));
}
[Fact]
public void ResolveConstraint_DateTimeConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("datetime");
// Assert
Assert.IsType<DateTimeRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_DecimalConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("decimal");
// Assert
Assert.IsType<DecimalRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_DoubleConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("double");
// Assert
Assert.IsType<DoubleRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_FloatConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("float");
// Assert
Assert.IsType<FloatRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_GuidConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("guid");
// Assert
Assert.IsType<GuidRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_IntConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("int");
// Assert
Assert.IsType<IntRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_LengthConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("length(5)");
// Assert
Assert.IsType<LengthRouteConstraint>(constraint);
Assert.Equal(5, ((LengthRouteConstraint)constraint).MinLength);
Assert.Equal(5, ((LengthRouteConstraint)constraint).MaxLength);
}
[Fact]
public void ResolveConstraint_LengthRangeConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("length(5, 10)");
// Assert
var lengthConstraint = Assert.IsType<LengthRouteConstraint>(constraint);
Assert.Equal(5, lengthConstraint.MinLength);
Assert.Equal(10, lengthConstraint.MaxLength);
}
[Fact]
public void ResolveConstraint_LongRangeConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("long");
// Assert
Assert.IsType<LongRouteConstraint>(constraint);
}
[Fact]
public void ResolveConstraint_MaxConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("max(10)");
// Assert
Assert.IsType<MaxRouteConstraint>(constraint);
Assert.Equal(10, ((MaxRouteConstraint)constraint).Max);
}
[Fact]
public void ResolveConstraint_MaxLengthConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("maxlength(10)");
// Assert
Assert.IsType<MaxLengthRouteConstraint>(constraint);
Assert.Equal(10, ((MaxLengthRouteConstraint)constraint).MaxLength);
}
[Fact]
public void ResolveConstraint_MinConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("min(3)");
// Assert
Assert.IsType<MinRouteConstraint>(constraint);
Assert.Equal(3, ((MinRouteConstraint)constraint).Min);
}
[Fact]
public void ResolveConstraint_MinLengthConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("minlength(3)");
// Assert
Assert.IsType<MinLengthRouteConstraint>(constraint);
Assert.Equal(3, ((MinLengthRouteConstraint)constraint).MinLength);
}
[Fact]
public void ResolveConstraint_RangeConstraint()
{
// Arrange & Act
var constraint = _constraintResolver.ResolveConstraint("range(5, 10)");
// Assert
Assert.IsType<RangeRouteConstraint>(constraint);
var rangeConstraint = (RangeRouteConstraint)constraint;
Assert.Equal(5, rangeConstraint.Min);
Assert.Equal(10, rangeConstraint.Max);
}
[Fact]
public void ResolveConstraint_SupportsCustomConstraints()
@ -74,6 +250,32 @@ namespace Microsoft.AspNet.Routing.Tests
ex.Message);
}
[Fact]
public void ResolveConstraint_AmbiguousConstructors_Throws()
{
// Arrange
var routeOptions = new RouteOptions();
routeOptions.ConstraintMap.Add("custom", typeof(MultiConstructorRouteConstraint));
var resolver = GetInlineConstraintResolver(routeOptions);
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => resolver.ResolveConstraint("custom(5,6)"));
Assert.Equal("The constructor to use for activating the constraint type 'MultiConstructorRouteConstraint' is ambiguous." +
" Multiple constructors were found with the following number of parameters: 2.",
ex.Message);
}
[Fact]
public void ResolveConstraint_NoMatchingConstructor_Throws()
{
// Arrange
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => _constraintResolver.ResolveConstraint("int(5,6)"));
Assert.Equal("Could not find a constructor for constraint type 'IntRouteConstraint'" +
" with the following number of parameters: 2.",
ex.Message);
}
private IInlineConstraintResolver GetInlineConstraintResolver(RouteOptions routeOptions)
{
var optionsAccessor = new Mock<IOptionsAccessor<RouteOptions>>();
@ -84,6 +286,26 @@ namespace Microsoft.AspNet.Routing.Tests
return new DefaultInlineConstraintResolver(serviceProvider.Object, optionsAccessor.Object);
}
private class MultiConstructorRouteConstraint : IRouteConstraint
{
public MultiConstructorRouteConstraint(string pattern, int intArg)
{
}
public MultiConstructorRouteConstraint(int intArg, string pattern)
{
}
public bool Match(HttpContext httpContext,
IRouter route,
string routeKey,
IDictionary<string, object> values,
RouteDirection routeDirection)
{
return true;
}
}
private class CustomRouteConstraint : IRouteConstraint
{
public CustomRouteConstraint(string pattern)

View File

@ -176,6 +176,18 @@ namespace Microsoft.AspNet.Routing.Tests
Assert.Equal(@"\w,\w", ((TestRouteConstraint)templatePart.InlineConstraint).Pattern);
}
[Fact]
public void ParseRouteParameter_ConstraintWithEqualsFollowedByQuestionMark_PatternIsParsedCorrectly()
{
// Arrange & Act
var templatePart = ParseParameter(@"param:int=?");
// Assert
Assert.Equal("param", templatePart.Name);
var constraint = Assert.IsType<IntRouteConstraint>(templatePart.InlineConstraint);
Assert.Equal("", templatePart.DefaultValue);
}
[Theory]
[InlineData(",")]
[InlineData("(")]
@ -270,15 +282,15 @@ namespace Microsoft.AspNet.Routing.Tests
private TemplatePart ParseParameter(string routeParameter)
{
var constraintResolver = GetConstraintResolver();
var templatePart = InlineRouteParameterParser.ParseRouteParameter(routeParameter, constraintResolver);
var _constraintResolver = GetConstraintResolver();
var templatePart = InlineRouteParameterParser.ParseRouteParameter(routeParameter, _constraintResolver);
return templatePart;
}
private static Template.Template ParseRouteTemplate(string template)
{
var constraintResolver = GetConstraintResolver();
return TemplateParser.Parse(template, constraintResolver);
var _constraintResolver = GetConstraintResolver();
return TemplateParser.Parse(template, _constraintResolver);
}
private static IInlineConstraintResolver GetConstraintResolver()

View File

@ -22,16 +22,35 @@
<ItemGroup>
<Compile Include="ConstraintMatcherTests.cs" />
<Compile Include="ConstraintsBuilderTests.cs" />
<Compile Include="Constraints\ConstraintsTestHelper.cs" />
<Compile Include="Constraints\BoolRouteConstraintTests.cs" />
<Compile Include="Constraints\DateTimeRouteConstraintTests.cs" />
<Compile Include="Constraints\DecimalRouteConstraintTests.cs" />
<Compile Include="Constraints\DoubleRouteConstraintTests.cs" />
<Compile Include="Constraints\FloatRouteConstraintTests.cs" />
<Compile Include="Constraints\GuidRouteConstraintTests.cs" />
<Compile Include="Constraints\LengthRouteConstraintTests.cs" />
<Compile Include="Constraints\CompositeRouteConstraintTests.cs" />
<Compile Include="Constraints\MaxLengthRouteConstraintTests.cs" />
<Compile Include="Constraints\MinLengthRouteConstraintTests.cs" />
<Compile Include="Constraints\MaxRouteConstraintTests.cs" />
<Compile Include="Constraints\LongRouteConstraintTests.cs" />
<Compile Include="Constraints\RangeRouteConstraintTests.cs" />
<Compile Include="Constraints\MinRouteConstraintTests.cs" />
<Compile Include="Constraints\AlphaRouteConstraintTests.cs" />
<Compile Include="Constraints\RegexConstraintTests.cs" />
<Compile Include="Constraints\IntRouteConstraintsTests.cs" />
<Compile Include="DefaultInlineConstraintResolverTest.cs" />
<Compile Include="RegexConstraintTests.cs" />
<Compile Include="RouteCollectionTest.cs" />
<Compile Include="InlineRouteParameterParserTests.cs" />
<Compile Include="RouteConstraintsTests.cs" />
<Compile Include="DefaultValueTests.cs" />
<Compile Include="RouteOptionsTests.cs" />
<Compile Include="RouteValueDictionaryTests.cs" />
<Compile Include="TemplateParserDefaultValuesTests.cs" />
<Compile Include="Template\TemplateBinderTests.cs" />
<Compile Include="Template\TemplateMatcherTests.cs" />
<Compile Include="Template\TemplateParserTests.cs" />
<Compile Include="Template\TemplateRouteTests.cs" />
</ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
</Project>

View File

@ -423,7 +423,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests
// Assert
Assert.Equal(2, constraints.Count);
Assert.IsType<RegexConstraint>(constraints["controller"]);
Assert.IsType<RegexRouteConstraint>(constraints["controller"]);
Assert.Equal(mockConstraint, constraints["action"]);
}
@ -444,7 +444,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests
Assert.Equal(1, constraints.Count);
var constraint = (CompositeRouteConstraint)constraints["id"];
Assert.IsType<CompositeRouteConstraint>(constraint);
Assert.IsType<RegexConstraint>(constraint.Constraints.ElementAt(0));
Assert.IsType<RegexRouteConstraint>(constraint.Constraints.ElementAt(0));
Assert.IsType<IntRouteConstraint>(constraint.Constraints.ElementAt(1));
}

View File

@ -0,0 +1,117 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing.Constraints;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class TemplateParserDefaultValuesTests
{
private static IInlineConstraintResolver _inlineConstraintResolver = GetInlineConstraintResolver();
[Fact]
public void InlineDefaultValueSpecified_InlineValueIsUsed()
{
// Arrange & Act
var routeBuilder = CreateRouteBuilder();
// Act
routeBuilder.MapRoute("mockName",
"{controller}/{action}/{id:int=12}",
defaults: null,
constraints: null);
// Assert
var defaults = ((Template.TemplateRoute)routeBuilder.Routes[0]).Defaults;
Assert.Equal("12", defaults["id"]);
}
[Fact]
public void ExplicitDefaultValueSpecified_WithInlineDefaultValue_Throws()
{
// Arrange
var routeBuilder = CreateRouteBuilder();
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(
() => routeBuilder.MapRoute("mockName",
"{controller}/{action}/{id:int=12}",
defaults: new { id = 13 },
constraints: null));
var message = "The route parameter 'id' has both an inline default value and an explicit default" +
" value specified. A route parameter cannot contain an inline default value when" +
" a default value is specified explicitly. Consider removing one of them.";
Assert.Equal(message, ex.Message);
}
[Fact]
public void EmptyDefaultValue_WithOptionalParameter_Throws()
{
// Arrange
var routeBuilder = CreateRouteBuilder();
// Act & Assert
var ex = Assert.Throws<ArgumentException>(
() => routeBuilder.MapRoute("mockName",
"{controller}/{action}/{id:int=?}",
defaults: new { id = 13 },
constraints: null));
var message = "An optional parameter cannot have default value.\r\nParameter name: routeTemplate";
Assert.Equal(message, ex.Message);
}
[Fact]
public void NonEmptyDefaultValue_WithOptionalParameter_Throws()
{
// Arrange
var routeBuilder = CreateRouteBuilder();
// Act & Assert
var ex = Assert.Throws<ArgumentException>(
() => routeBuilder.MapRoute("mockName",
"{controller}/{action}/{id:int=12?}",
defaults: new { id = 13 },
constraints: null));
var message = "An optional parameter cannot have default value.\r\nParameter name: routeTemplate";
Assert.Equal(message, ex.Message);
}
private static IRouteBuilder CreateRouteBuilder()
{
var routeBuilder = new RouteBuilder();
routeBuilder.DefaultHandler = new Mock<IRouter>().Object;
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock.Setup(o => o.GetService(typeof(IInlineConstraintResolver)))
.Returns(_inlineConstraintResolver);
routeBuilder.ServiceProvider = serviceProviderMock.Object;
return routeBuilder;
}
private static IInlineConstraintResolver GetInlineConstraintResolver()
{
var services = new ServiceCollection { OptionsServices.GetDefaultServices() };
var serviceProvider = services.BuildServiceProvider();
var accessor = serviceProvider.GetService<IOptionsAccessor<RouteOptions>>();
return new DefaultInlineConstraintResolver(serviceProvider, accessor);
}
}
}
#endif