ASP.NET MVC: Route with optional parameter, but if supplied, must match \d+

The simplest way would be to just add another route without the userId parameter, so you have a fallback:

routes.MapRoute("ProfileDetails", "profile/{userId}",
                new {controller = "Profile",
                     action = "Details",
                     userId = UrlParameter.Optional},
                new {userId = @"\d+"});

routes.MapRoute("Profile", "profile",
                new {controller = "Profile",
                     action = "Details"});

As far as I know, the only other way you can do this would be with a custom constraint. So your route would become:

routes.MapRoute("ProfileDetails", "profile/{userId}",
                new {controller = "Profile",
                     action = "Details",
                     userId = UrlParameter.Optional},
                new {userId = new NullableConstraint());

And the custom constraint code will look like this:

using System;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;

namespace YourNamespace
{
    public class NullableConstraint : IRouteConstraint
    {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (routeDirection == RouteDirection.IncomingRequest && parameterName == "userId")
            {
                // If the userId param is empty (weird way of checking, I know)
                if (values["userId"] == UrlParameter.Optional)
                    return true;

                // If the userId param is an int
                int id;
                if (Int32.TryParse(values["userId"].ToString(), out id))
                    return true;
            }

            return false;
        }
    }
}

I don’t know that NullableConstraint is the best name here, but that’s up to you!

Leave a Comment