0

When I'm trying to add constraint to default route as follows

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        constraints: new { id = @"\d+" }
    );
}

and running the site, I'm getting:

HTTP Error 403.14 - Forbidden error

The Web server is configured to not list the contents of this directory.

Just this single line with constraint causes the issue. When it's commented the site is running as expected. I'm even able to reproduce this locally on newly created MVC project.

Is this some sort of bug, or don't I understand something crucial about route constraints?

I'm using .NET 4.5.2, MVC 5.2.3, VS 2015 with IIS Express 10.0.

drty
  • 200
  • 1
  • 11
  • Well, you have added a constraint to the id parameter which is effectively making the id required. I guess you get your error with urls like `yourhost/` or `yourhost/controller/action` – Daniel J.G. Oct 15 '15 at 16:53
  • @Daniel, does this really make it required? If so, how can i specify that it should be integer only, but not making it required? – drty Oct 15 '15 at 16:57
  • Its a tricky thing. I guess you could define a route `{controller}/{action}/{id}` where none of them are optional and id has the constraint. Then another route `{controller}/{action}` where both are optional and have Home/Index default values – Daniel J.G. Oct 15 '15 at 17:02
  • Looks weird to me, but it works. Thanks. – drty Oct 15 '15 at 17:14

2 Answers2

1

Ok i suppose your problem and solutions for it you can find here.

Solution adapted to your situation:

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

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

        return false;
    }
}

And your Route:

        routes.MapRoute(
           name: "Default",
           url: "{controller}/{action}/{id}",
           defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
           constraints: new { id = new NullableConstraint() }
       );
Community
  • 1
  • 1
teo van kot
  • 12,350
  • 10
  • 38
  • 70
0

Haven't tried this ,You might want to define two routes to achieve what you need

 routes.MapRoute(
                name: "Default1",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index"}, 
                constraints: new {id=@"\d+"}
            );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index",id= UrlParameter.Optional }             
            );

If id is null it falls back to the default route.

curiousgeek
  • 846
  • 6
  • 11