NullableGuidConstraint for ASP.NET MVC & WebApi

Have you ever written a very usable Route-constraint in ASP.NET MVC or in WebAPI than you wanted to share between them both? For example a constraint that supports nullable Guids (Guid?) as route-parameter.

This can be done by implementing both System.Web.Routing.IRouteConstraint and System.Web.Http.Routing.IHttpRouteConstraint.

Hopefully this article will be obsolete with the release of ASP.NET 5, but until then, here's how you solve this problem:

public class NullableGuidConstraint : IRouteConstraint, IHttpRouteConstraint
{
    // ASP.NET MVC-signature
    public bool Match(
        HttpContextBase httpContext,
        Route route,
        string parameterName,
        RouteValueDictionary values,
        RouteDirection routeDirection)
    {
        return MatchInternal(parameterName, values);
    }

    // WebAPI-signature
    public bool Match(
        HttpRequestMessage request,
        IHttpRoute route,
        string parameterName,
        IDictionary values,
        HttpRouteDirection routeDirection)
    {
        return MatchInternal(parameterName, values);
    }

    private static bool MatchInternal(string parameterName, IDictionary values)
    {
        object value;
        if (!values.TryGetValue(parameterName, out value))
        {
            return false;
        }

        if (value is Guid)
        {
            return true;
        }

        string stringValue = Convert.ToString(value, CultureInfo.InvariantCulture);

        Guid guid;
        bool isMatch = string.IsNullOrWhiteSpace(stringValue) || Guid.TryParse(stringValue, out guid);
        return isMatch;
    }
}

Then you register this constraint through, for example, DefaultInlineConstraintResolver in System.Web.Mvc.Routing for ASP.NET MVC and System.Web.Http.Routing for WebAPI.

var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("guid?", typeof(NullableGuidConstraint));

// ASP.NET MVC
routes.MapMvcAttributeRoutes(constraintResolver);

// WebAPI
routes.MapHttpAttributeRoutes(constraintResolver);

Now you can write attribute-routes like this:

[Route("{controller}/{action}/{id=guid?}")]
Comments