File: Routing\HttpMethodConstraint.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
namespace System.Web.Routing {
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Runtime.CompilerServices;
 
    [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
    public class HttpMethodConstraint : IRouteConstraint {
 
        public HttpMethodConstraint(params string[] allowedMethods) {
            if (allowedMethods == null) {
                throw new ArgumentNullException("allowedMethods");
            }
 
            AllowedMethods = allowedMethods.ToList().AsReadOnly();
        }
 
        public ICollection<string> AllowedMethods {
            get;
            private set;
        }
 
        protected virtual bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
            if (httpContext == null) {
                throw new ArgumentNullException("httpContext");
            }
            if (route == null) {
                throw new ArgumentNullException("route");
            }
            if (parameterName == null) {
                throw new ArgumentNullException("parameterName");
            }
            if (values == null) {
                throw new ArgumentNullException("values");
            }
 
            switch (routeDirection) {
                case RouteDirection.IncomingRequest:
                    return AllowedMethods.Any(method => String.Equals(method, httpContext.Request.HttpMethod,
                        StringComparison.OrdinalIgnoreCase));
 
                case RouteDirection.UrlGeneration:
                    // We need to see if the user specified the HTTP method explicitly.  Consider these two routes:
                    //
                    // a) Route: Url = "/{foo}", Constraints = { httpMethod = new HttpMethodConstraint("GET") }
                    // b) Route: Url = "/{foo}", Constraints = { httpMethod = new HttpMethodConstraint("POST") }
                    //
                    // A user might know ahead of time that a URL he is generating might be used with a particular HTTP
                    // method.  If a URL will be used for an HTTP POST but we match on (a) while generating the URL, then
                    // the HTTP GET-specific route will be used for URL generation, which might have undesired behavior.
                    // To prevent this, a user might call RouteCollection.GetVirtualPath(..., { httpMethod = "POST" }) to
                    // signal that he is generating a URL that will be used for an HTTP POST, so he wants the URL
                    // generation to be performed by the (b) route instead of the (a) route, consistent with what would
                    // happen on incoming requests.
 
                    object parameterValue;
                    if (!values.TryGetValue(parameterName, out parameterValue)) {
                        return true;
                    }
 
                    string parameterValueString = parameterValue as string;
                    if (parameterValueString == null) {
                        throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
                            SR.GetString(SR.HttpMethodConstraint_ParameterValueMustBeString), parameterName, route.Url));
                    }
 
                    return AllowedMethods.Any(method => String.Equals(method, parameterValueString,
                        StringComparison.OrdinalIgnoreCase));
 
                default:
                    return true;
            }
        }
 
        #region IRouteConstraint Members
        bool IRouteConstraint.Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
            return Match(httpContext, route, parameterName, values, routeDirection);
        }
        #endregion
 
    }
}