RegEx Route Constraints and RouteParameter.Optional

Topics: ASP.NET Web API
Sep 3, 2012 at 9:15 AM
Edited Sep 3, 2012 at 9:26 AM

Currently, the RouteParameter.Optional and regular expression route constraints don’t get along very well. Let's take the following example:

protected void Application_Start(object sender, EventArgs e) {

    var routes = GlobalConfiguration.Configuration.Routes;

    routes.MapHttpRoute(
        "DefaultHttpRoute",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional },
        constraints: new { id = @"\d+" }
    );
}

With this route in place, all the requests that came to /api/cars would be rejected because the regular expression values would not match. To workaround this problem, we would have an implementation of IHttpRouteConstraint as below: 

public class DefaultHttpRouteIdConstraint : IHttpRouteConstraint {

    public bool Match(
        HttpRequestMessage request,
        IHttpRoute route, 
        string parameterName, 
        IDictionary<string, object> values, 
        HttpRouteDirection routeDirection) {

        int idParamValue;
        if (values[parameterName] == RouteParameter.Optional || 
            int.TryParse(values[parameterName].ToString(), 
            out idParamValue)) { 
        
            return true;
        }

            return true;

        return false;
    }
}

Now, we can register this route as below:

protected void Application_Start(object sender, EventArgs e) {

    var routes = GlobalConfiguration.Configuration.Routes;

    routes.MapHttpRoute(
        "DefaultHttpRoute",
        "api/{controller}/{id}",
        new { id = RouteParameter.Optional },
        new { id = new DefaultHttpRouteIdConstraint() }
    );
}

I am not sure if this can be changed as this might be the feature of underlying routing module (with ASP.NET Host) and AFAIK, ASP.NET MVC has the same issue.

Sep 4, 2012 at 7:37 AM
This is By Design behavior in the ASP.NET routing system.

The default value is not exempted from the constraint. It sounds like you either want a default value of "0" rather than RouteParameter.Optional, or you want a regex which is okay with an empty string (i.e., "\d*" rather than "\d+").
Sep 4, 2012 at 7:44 AM

Thanks for the response Brad.

I assume the same behavior is also reflected to Self-Hosting as well. Fortunately, the workaround for this is simple (with a custom route constraint or as u suggested) if the default is not the desired behavior.