From 604fc6bb54b4aa12f774a9f56b7e4bcfb6e9ceaf Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 11 Dec 2015 17:02:06 -0800 Subject: [PATCH] Fix #248 Add HttpMethodRouteConstraint Constraint code ported from WebAPI2. Tests are new. Also a bunch of misc cleanup for constraints. - Move IRouteConstraint to abstractions - Fix namespace of a constraint - Some general style cleanup - use RouteValueDictionary in the public API --- .../IRouteConstraint.cs | 11 ++- .../RouteDirection.cs | 0 .../Constraints/BoolRouteConstraint.cs | 5 +- .../Constraints/CompositeRouteConstraint.cs | 4 +- .../Constraints/DateTimeRouteConstraint.cs | 3 +- .../Constraints/DecimalRouteConstraint.cs | 5 +- .../Constraints/DoubleRouteConstraint.cs | 13 +-- .../Constraints/FloatRouteConstraint.cs | 12 +-- .../Constraints/GuidRouteConstraint.cs | 3 +- .../Constraints/HttpMethodRouteConstraint.cs | 96 +++++++++++++++++++ .../Constraints/IntRouteConstraint.cs | 5 +- .../Constraints/LengthRouteConstraint.cs | 7 +- .../Constraints/LongRouteConstraint.cs | 3 +- .../Constraints/MaxLengthRouteConstraint.cs | 5 +- .../Constraints/MaxRouteConstraint.cs | 5 +- .../Constraints/MinLengthRouteConstraint.cs | 3 +- .../Constraints/MinRouteConstraint.cs | 7 +- .../Constraints/OptionalRouteConstraint.cs | 3 +- .../Constraints/RangeRouteConstraint.cs | 3 +- .../Constraints/RegexInlineRouteConstraint.cs | 2 - .../Constraints/RegexRouteConstraint.cs | 3 +- .../Constraints/RequiredRouteConstraint.cs | 3 +- .../RouteConstraintMatcher.cs | 2 +- .../ConstraintMatcherTest.cs | 22 +++-- .../CompositeRouteConstraintTests.cs | 4 +- .../Constraints/ConstraintsTestHelper.cs | 2 +- .../HttpMethodRouteConstraintTests.cs | 94 ++++++++++++++++++ .../DefaultInlineConstraintResolverTest.cs | 4 +- .../InlineRouteParameterParserTests.cs | 2 +- .../RouteOptionsTests.cs | 2 +- .../RouteTest.cs | 15 +-- .../Tree/TreeRouterTest.cs | 2 +- 32 files changed, 266 insertions(+), 84 deletions(-) rename src/{Microsoft.AspNet.Routing => Microsoft.AspNet.Routing.Abstractions}/IRouteConstraint.cs (76%) rename src/{Microsoft.AspNet.Routing => Microsoft.AspNet.Routing.Abstractions}/RouteDirection.cs (100%) create mode 100644 src/Microsoft.AspNet.Routing/Constraints/HttpMethodRouteConstraint.cs create mode 100644 test/Microsoft.AspNet.Routing.Tests/Constraints/HttpMethodRouteConstraintTests.cs diff --git a/src/Microsoft.AspNet.Routing/IRouteConstraint.cs b/src/Microsoft.AspNet.Routing.Abstractions/IRouteConstraint.cs similarity index 76% rename from src/Microsoft.AspNet.Routing/IRouteConstraint.cs rename to src/Microsoft.AspNet.Routing.Abstractions/IRouteConstraint.cs index 392cf36d6b..0da713865e 100644 --- a/src/Microsoft.AspNet.Routing/IRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing.Abstractions/IRouteConstraint.cs @@ -1,13 +1,13 @@ // 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.Collections.Generic; using Microsoft.AspNet.Http; namespace Microsoft.AspNet.Routing { /// - /// Defines the contract that a class must implement in order to check whether a URL parameter value is valid for a constraint. + /// Defines the contract that a class must implement in order to check whether a URL parameter + /// value is valid for a constraint. /// public interface IRouteConstraint { @@ -18,13 +18,16 @@ namespace Microsoft.AspNet.Routing /// The router that this constraint belongs to. /// The name of the parameter that is being checked. /// A dictionary that contains the parameters for the URL. - /// An object that indicates whether the constraint check is being performed when an incoming request is being handled or when a URL is being generated. + /// + /// An object that indicates whether the constraint check is being performed + /// when an incoming request is being handled or when a URL is being generated. + /// /// true if the URL parameter contains a valid value; otherwise, false. bool Match( HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection); } } diff --git a/src/Microsoft.AspNet.Routing/RouteDirection.cs b/src/Microsoft.AspNet.Routing.Abstractions/RouteDirection.cs similarity index 100% rename from src/Microsoft.AspNet.Routing/RouteDirection.cs rename to src/Microsoft.AspNet.Routing.Abstractions/RouteDirection.cs diff --git a/src/Microsoft.AspNet.Routing/Constraints/BoolRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/BoolRouteConstraint.cs index 8c603bf9c3..05b620c426 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/BoolRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/BoolRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -18,7 +17,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) @@ -51,7 +50,7 @@ namespace Microsoft.AspNet.Routing.Constraints bool result; var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); - return Boolean.TryParse(valueString, out result); + return bool.TryParse(valueString, out result); } return false; diff --git a/src/Microsoft.AspNet.Routing/Constraints/CompositeRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/CompositeRouteConstraint.cs index 4ba46b4eeb..20db00d7ad 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/CompositeRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/CompositeRouteConstraint.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using Microsoft.AspNet.Http; -namespace Microsoft.AspNet.Routing +namespace Microsoft.AspNet.Routing.Constraints { /// /// Constrains a route by several child constraints. @@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Routing HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/DateTimeRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/DateTimeRouteConstraint.cs index 64777c590d..4bc3f982aa 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/DateTimeRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/DateTimeRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -24,7 +23,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/DecimalRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/DecimalRouteConstraint.cs index 114d22dccb..b237fb62a7 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/DecimalRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/DecimalRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -18,7 +17,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) @@ -51,7 +50,7 @@ namespace Microsoft.AspNet.Routing.Constraints decimal result; var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); - return Decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out result); + return decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out result); } return false; diff --git a/src/Microsoft.AspNet.Routing/Constraints/DoubleRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/DoubleRouteConstraint.cs index 1a91446a7e..5f51e73572 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/DoubleRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/DoubleRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -18,7 +17,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) @@ -51,11 +50,13 @@ namespace Microsoft.AspNet.Routing.Constraints double result; var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); - return Double.TryParse(valueString, - NumberStyles.Float | NumberStyles.AllowThousands, - CultureInfo.InvariantCulture, - out result); + return double.TryParse( + valueString, + NumberStyles.Float | NumberStyles.AllowThousands, + CultureInfo.InvariantCulture, + out result); } + return false; } } diff --git a/src/Microsoft.AspNet.Routing/Constraints/FloatRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/FloatRouteConstraint.cs index 21a5ac2292..da4a3e72c8 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/FloatRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/FloatRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -18,7 +17,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) @@ -51,10 +50,11 @@ namespace Microsoft.AspNet.Routing.Constraints float result; var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); - return Single.TryParse(valueString, - NumberStyles.Float | NumberStyles.AllowThousands, - CultureInfo.InvariantCulture, - out result); + return float.TryParse( + valueString, + NumberStyles.Float | NumberStyles.AllowThousands, + CultureInfo.InvariantCulture, + out result); } return false; diff --git a/src/Microsoft.AspNet.Routing/Constraints/GuidRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/GuidRouteConstraint.cs index d815f5ebd4..142991dbc6 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/GuidRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/GuidRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -20,7 +19,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/HttpMethodRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/HttpMethodRouteConstraint.cs new file mode 100644 index 0000000000..7a986c62dd --- /dev/null +++ b/src/Microsoft.AspNet.Routing/Constraints/HttpMethodRouteConstraint.cs @@ -0,0 +1,96 @@ +// 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.Linq; +using Microsoft.AspNet.Http; + +namespace Microsoft.AspNet.Routing.Constraints +{ + /// + /// Constrains the HTTP method of request or a route. + /// + public class HttpMethodConstraint : IRouteConstraint + { + /// + /// Creates a new that accepts the HTTP methods specified + /// by . + /// + /// The allowed HTTP methods. + public HttpMethodConstraint(params string[] allowedMethods) + { + if (allowedMethods == null) + { + throw new ArgumentNullException(nameof(allowedMethods)); + } + + AllowedMethods = new List(allowedMethods); + } + + /// + /// Gets the HTTP methods allowed by the constraint. + /// + public IList AllowedMethods { get; } + + /// + public virtual bool Match( + HttpContext httpContext, + IRouter route, + string routeKey, + RouteValueDictionary values, + RouteDirection routeDirection) + { + if (httpContext == null) + { + throw new ArgumentNullException(nameof(httpContext)); + } + + if (route == null) + { + throw new ArgumentNullException(nameof(route)); + } + + if (routeKey == null) + { + throw new ArgumentNullException(nameof(routeKey)); + } + + if (values == null) + { + throw new ArgumentNullException(nameof(values)); + } + + switch (routeDirection) + { + case RouteDirection.IncomingRequest: + return AllowedMethods.Contains(httpContext.Request.Method, StringComparer.OrdinalIgnoreCase); + + case RouteDirection.UrlGeneration: + // We need to see if the user specified the HTTP method explicitly. Consider these two routes: + // + // a) Route: template = "/{foo}", Constraints = { httpMethod = new HttpMethodConstraint("GET") } + // b) Route: template = "/{foo}", Constraints = { httpMethod = new HttpMethodConstraint("POST") } + // + // A user might know ahead of time that a URI he/she is generating might be used with a particular HTTP + // method. If a URI will be used for an HTTP POST but we match on (a) while generating the URI, then + // the HTTP GET-specific route will be used for URI generation, which might have undesired behavior. + // + // To prevent this, a user might call GetVirtualPath(..., { httpMethod = "POST" }) to + // signal that he is generating a URI that will be used for an HTTP POST, so he wants the URI + // generation to be performed by the (b) route instead of the (a) route, consistent with what would + // happen on incoming requests. + object obj; + if (!values.TryGetValue(routeKey, out obj)) + { + return true; + } + + return AllowedMethods.Contains(Convert.ToString(obj), StringComparer.OrdinalIgnoreCase); + + default: + throw new ArgumentOutOfRangeException(nameof(routeDirection)); + } + } + } +} diff --git a/src/Microsoft.AspNet.Routing/Constraints/IntRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/IntRouteConstraint.cs index 939b913d26..d714504aa2 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/IntRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/IntRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -18,7 +17,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) @@ -51,7 +50,7 @@ namespace Microsoft.AspNet.Routing.Constraints int result; var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); - return Int32.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out result); + return int.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out result); } return false; diff --git a/src/Microsoft.AspNet.Routing/Constraints/LengthRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/LengthRouteConstraint.cs index 8978a328ab..891e87dd76 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/LengthRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/LengthRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -63,19 +62,19 @@ namespace Microsoft.AspNet.Routing.Constraints /// /// Gets the minimum length allowed for the route parameter. /// - public int MinLength { get; private set; } + public int MinLength { get; } /// /// Gets the maximum length allowed for the route parameter. /// - public int MaxLength { get; private set; } + public int MaxLength { get; } /// public bool Match( HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/LongRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/LongRouteConstraint.cs index e7e8723ce6..ea178ce423 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/LongRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/LongRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -18,7 +17,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/MaxLengthRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/MaxLengthRouteConstraint.cs index 3027a94995..59ec40255e 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/MaxLengthRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/MaxLengthRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -31,14 +30,14 @@ namespace Microsoft.AspNet.Routing.Constraints /// /// Gets the maximum length allowed for the route parameter. /// - public int MaxLength { get; private set; } + public int MaxLength { get; } /// public bool Match( HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/MaxRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/MaxRouteConstraint.cs index e2db3419c2..65b225ee2c 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/MaxRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/MaxRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -32,7 +31,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) @@ -60,7 +59,7 @@ namespace Microsoft.AspNet.Routing.Constraints { long longValue; var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); - if (Int64.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out longValue)) + if (long.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out longValue)) { return longValue <= Max; } diff --git a/src/Microsoft.AspNet.Routing/Constraints/MinLengthRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/MinLengthRouteConstraint.cs index ee67aac988..ec20c6e873 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/MinLengthRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/MinLengthRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -38,7 +37,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/MinRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/MinRouteConstraint.cs index 7c50f70d41..0490dd20ad 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/MinRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/MinRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -25,14 +24,14 @@ namespace Microsoft.AspNet.Routing.Constraints /// /// Gets the minimum allowed value of the route parameter. /// - public long Min { get; private set; } + public long Min { get; } /// public bool Match( HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) @@ -60,7 +59,7 @@ namespace Microsoft.AspNet.Routing.Constraints { long longValue; var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); - if (Int64.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out longValue)) + if (long.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out longValue)) { return longValue >= Min; } diff --git a/src/Microsoft.AspNet.Routing/Constraints/OptionalRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/OptionalRouteConstraint.cs index ad6e3f7969..6e8d310a42 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/OptionalRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/OptionalRouteConstraint.cs @@ -2,7 +2,6 @@ // 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 Microsoft.AspNet.Http; namespace Microsoft.AspNet.Routing.Constraints @@ -28,7 +27,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/RangeRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/RangeRouteConstraint.cs index 7b1bc6599c..8121e436f4 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/RangeRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/RangeRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -46,7 +45,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/RegexInlineRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/RegexInlineRouteConstraint.cs index d13469ef33..3fd9b8fcb4 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/RegexInlineRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/RegexInlineRouteConstraint.cs @@ -1,8 +1,6 @@ // 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; - namespace Microsoft.AspNet.Routing.Constraints { /// diff --git a/src/Microsoft.AspNet.Routing/Constraints/RegexRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/RegexRouteConstraint.cs index 0ccd6f5eba..3e9785999d 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/RegexRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/RegexRouteConstraint.cs @@ -2,7 +2,6 @@ // 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.Text.RegularExpressions; using Microsoft.AspNet.Http; @@ -42,7 +41,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/Constraints/RequiredRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/RequiredRouteConstraint.cs index 03f46b00e9..c3cb229547 100644 --- a/src/Microsoft.AspNet.Routing/Constraints/RequiredRouteConstraint.cs +++ b/src/Microsoft.AspNet.Routing/Constraints/RequiredRouteConstraint.cs @@ -2,7 +2,6 @@ // 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; @@ -22,7 +21,7 @@ namespace Microsoft.AspNet.Routing.Constraints HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { if (httpContext == null) diff --git a/src/Microsoft.AspNet.Routing/RouteConstraintMatcher.cs b/src/Microsoft.AspNet.Routing/RouteConstraintMatcher.cs index 260da1693d..ee4aace33d 100644 --- a/src/Microsoft.AspNet.Routing/RouteConstraintMatcher.cs +++ b/src/Microsoft.AspNet.Routing/RouteConstraintMatcher.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Routing { public static bool Match( IDictionary constraints, - IDictionary routeValues, + RouteValueDictionary routeValues, HttpContext httpContext, IRouter route, RouteDirection routeDirection, diff --git a/test/Microsoft.AspNet.Routing.Tests/ConstraintMatcherTest.cs b/test/Microsoft.AspNet.Routing.Tests/ConstraintMatcherTest.cs index 72bab7bcba..5856b87c7d 100644 --- a/test/Microsoft.AspNet.Routing.Tests/ConstraintMatcherTest.cs +++ b/test/Microsoft.AspNet.Routing.Tests/ConstraintMatcherTest.cs @@ -220,11 +220,12 @@ namespace Microsoft.AspNet.Routing _expectedKey = expectedKey; } - public bool Match(HttpContext httpContext, - IRouter route, - string routeKey, - IDictionary values, - RouteDirection routeDirection) + public bool Match( + HttpContext httpContext, + IRouter route, + string routeKey, + RouteValueDictionary values, + RouteDirection routeDirection) { if (_expectedKey != null) { @@ -237,11 +238,12 @@ namespace Microsoft.AspNet.Routing private class FailConstraint : IRouteConstraint { - public bool Match(HttpContext httpContext, - IRouter route, - string routeKey, - IDictionary values, - RouteDirection routeDirection) + public bool Match( + HttpContext httpContext, + IRouter route, + string routeKey, + RouteValueDictionary values, + RouteDirection routeDirection) { return false; } diff --git a/test/Microsoft.AspNet.Routing.Tests/Constraints/CompositeRouteConstraintTests.cs b/test/Microsoft.AspNet.Routing.Tests/Constraints/CompositeRouteConstraintTests.cs index 39e76d6446..8b837977be 100644 --- a/test/Microsoft.AspNet.Routing.Tests/Constraints/CompositeRouteConstraintTests.cs +++ b/test/Microsoft.AspNet.Routing.Tests/Constraints/CompositeRouteConstraintTests.cs @@ -2,9 +2,9 @@ // 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.Linq.Expressions; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Routing.Constraints; using Moq; using Xunit; @@ -39,7 +39,7 @@ namespace Microsoft.AspNet.Routing.Tests It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny>(), + It.IsAny(), It.IsAny()); private static Mock MockConstraintWithResult(bool result) diff --git a/test/Microsoft.AspNet.Routing.Tests/Constraints/ConstraintsTestHelper.cs b/test/Microsoft.AspNet.Routing.Tests/Constraints/ConstraintsTestHelper.cs index c0c0e3c684..edd5a0c7ae 100644 --- a/test/Microsoft.AspNet.Routing.Tests/Constraints/ConstraintsTestHelper.cs +++ b/test/Microsoft.AspNet.Routing.Tests/Constraints/ConstraintsTestHelper.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Routing.Tests } var parameterName = "fake"; - var values = new Dictionary() { { parameterName, value } }; + var values = new RouteValueDictionary() { { parameterName, value } }; var routeDirection = RouteDirection.IncomingRequest; return constraint.Match(context.Object, route, parameterName, values, routeDirection); } diff --git a/test/Microsoft.AspNet.Routing.Tests/Constraints/HttpMethodRouteConstraintTests.cs b/test/Microsoft.AspNet.Routing.Tests/Constraints/HttpMethodRouteConstraintTests.cs new file mode 100644 index 0000000000..30a125defd --- /dev/null +++ b/test/Microsoft.AspNet.Routing.Tests/Constraints/HttpMethodRouteConstraintTests.cs @@ -0,0 +1,94 @@ +// 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 Microsoft.AspNet.Http.Internal; +using Moq; +using Xunit; + +namespace Microsoft.AspNet.Routing.Constraints +{ + public class HttpMethodRouteConstraintTests + { + [Theory] + [InlineData("GET")] + [InlineData("PosT")] + public void HttpMethodRouteConstraint_IncomingRequest_AcceptsAllowedMethods(string httpMethod) + { + // Arrange + var constraint = new HttpMethodConstraint("GET", "post"); + + var httpContext = new DefaultHttpContext(); + httpContext.Request.Method = httpMethod; + var route = Mock.Of(); + + var values = new RouteValueDictionary(new { }); + + // Act + var result = constraint.Match(httpContext, route, "httpMethod", values, RouteDirection.IncomingRequest); + + // Assert + Assert.True(result); + } + + [Theory] + [InlineData("OPTIONS")] + [InlineData("SomeRandomThing")] + public void HttpMethodRouteConstraint_IncomingRequest_RejectsOtherMethods(string httpMethod) + { + // Arrange + var constraint = new HttpMethodConstraint("GET", "post"); + + var httpContext = new DefaultHttpContext(); + httpContext.Request.Method = httpMethod; + var route = Mock.Of(); + + var values = new RouteValueDictionary(new { }); + + // Act + var result = constraint.Match(httpContext, route, "httpMethod", values, RouteDirection.IncomingRequest); + + // Assert + Assert.False(result); + } + + [Theory] + [InlineData("GET")] + [InlineData("PosT")] + public void HttpMethodRouteConstraint_UrlGeneration_AcceptsAllowedMethods(string httpMethod) + { + // Arrange + var constraint = new HttpMethodConstraint("GET", "post"); + + var httpContext = new DefaultHttpContext(); + var route = Mock.Of(); + + var values = new RouteValueDictionary(new { httpMethod = httpMethod }); + + // Act + var result = constraint.Match(httpContext, route, "httpMethod", values, RouteDirection.UrlGeneration); + + // Assert + Assert.True(result); + } + + [Theory] + [InlineData("OPTIONS")] + [InlineData("SomeRandomThing")] + public void HttpMethodRouteConstraint_UrlGeneration_RejectsOtherMethods(string httpMethod) + { + // Arrange + var constraint = new HttpMethodConstraint("GET", "post"); + + var httpContext = new DefaultHttpContext(); + var route = Mock.Of(); + + var values = new RouteValueDictionary(new { httpMethod = httpMethod }); + + // Act + var result = constraint.Match(httpContext, route, "httpMethod", values, RouteDirection.UrlGeneration); + + // Assert + Assert.False(result); + } + } +} diff --git a/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs b/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs index ce0a923424..a561b1fa9a 100644 --- a/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs +++ b/test/Microsoft.AspNet.Routing.Tests/DefaultInlineConstraintResolverTest.cs @@ -343,7 +343,7 @@ namespace Microsoft.AspNet.Routing.Tests public bool Match(HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { return true; @@ -361,7 +361,7 @@ namespace Microsoft.AspNet.Routing.Tests public bool Match(HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { return true; diff --git a/test/Microsoft.AspNet.Routing.Tests/InlineRouteParameterParserTests.cs b/test/Microsoft.AspNet.Routing.Tests/InlineRouteParameterParserTests.cs index 1c4b6801a6..281711e6cd 100644 --- a/test/Microsoft.AspNet.Routing.Tests/InlineRouteParameterParserTests.cs +++ b/test/Microsoft.AspNet.Routing.Tests/InlineRouteParameterParserTests.cs @@ -982,7 +982,7 @@ namespace Microsoft.AspNet.Routing.Tests public bool Match(HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { throw new NotImplementedException(); diff --git a/test/Microsoft.AspNet.Routing.Tests/RouteOptionsTests.cs b/test/Microsoft.AspNet.Routing.Tests/RouteOptionsTests.cs index 464f97d1c0..e2b900c994 100644 --- a/test/Microsoft.AspNet.Routing.Tests/RouteOptionsTests.cs +++ b/test/Microsoft.AspNet.Routing.Tests/RouteOptionsTests.cs @@ -39,7 +39,7 @@ namespace Microsoft.AspNet.Routing.Tests HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { throw new NotImplementedException(); diff --git a/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs b/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs index 4f2cc35a66..db1d594020 100644 --- a/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs +++ b/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs @@ -832,11 +832,14 @@ namespace Microsoft.AspNet.Routing var context = CreateVirtualPathContext(new { p1 = "hello", p2 = "1234" }); var target = new Mock(); - target.Setup(e => e.Match(It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny>(), - It.IsAny())) + target + .Setup( + e => e.Match( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) .Returns(true) .Verifiable(); @@ -1594,7 +1597,7 @@ namespace Microsoft.AspNet.Routing HttpContext httpContext, IRouter route, string routeKey, - IDictionary values, + RouteValueDictionary values, RouteDirection routeDirection) { Values = new RouteValueDictionary(values); diff --git a/test/Microsoft.AspNet.Routing.Tests/Tree/TreeRouterTest.cs b/test/Microsoft.AspNet.Routing.Tests/Tree/TreeRouterTest.cs index fe8a4c1f10..cdef62983e 100644 --- a/test/Microsoft.AspNet.Routing.Tests/Tree/TreeRouterTest.cs +++ b/test/Microsoft.AspNet.Routing.Tests/Tree/TreeRouterTest.cs @@ -1610,7 +1610,7 @@ namespace Microsoft.AspNet.Routing.Tree It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny>(), + It.IsAny(), It.IsAny())) .Returns(true);