4
votes

I created this route

          routes.MapRoute( 
                name: "Survey", 
                url: "{controller}/{action}/{surveyid}/{userid}/{hash}", 
                defaults: new { controller = "Home", action = "Survey" }, 
                constraints: new { surveyid = @"\d+", userid = @"\d+" } 
           );

When I then browse to

http://localhost:3086/Home/Survey/1/1/3r2ytg

It works, however if I browse to

http://localhost:3086/1/1/3r2ytg

it does not work.

If I then changed the route like so

        routes.MapRoute(
            name: "Survey",
            url: "{surveyid}/{userid}/{hash}",
            defaults: new { controller = "Home", action = "Survey" },
            constraints: new { surveyid = @"\d+", userid = @"\d+" }
        );

The exact opposite would work (and that makes sense).

But I am curious with the first route i thought both URLs should work since it shoudl grab the default controller and action when none is given.

Update

In the end I went with only this

        routes.MapRoute(
            name: "Survey",
            url: "{surveyId}/{userId}/{hash}",
            defaults: new { controller = "Home", action = "Survey" },
            constraints: new { surveyId = @"\d+", userId = @"\d+" }
        );

as that is the behavior I wanted. However when I then call

@Url.Action("Survey", "Home", new 
{ 
    userId = @Model.UserId, 
    surveyId = survey.Id, 
    hash = HashHelpers.CreateShortenedUrlSafeHash(@Model.SecretString + survey.Id.ToString() + @Model.UserId.ToString())
})

It generates

/Admin/Home/Survey?userId=25&surveyId=19&hash=2Norc

instead of a shiny path. I can force it with Url.RouteUrl but I thought it should have picked this one automatically.

2

2 Answers

3
votes

You need to create route for each combination.

Check this Phil Haack Article

  routes.MapRoute( 
            name: "Survey", 
            url: "{controller}/{action}/{surveyid}/{userid}/{hash}", 
            defaults: new { controller = "Home", action = "Survey" }, 
            constraints: new { surveyid = @"\d+", userid = @"\d+" } 
  );

  routes.MapRoute(
        name: "Survey",
        url: "{surveyid}/{userid}/{hash}",
        defaults: new { controller = "Home", action = "Survey" },
        constraints: new { surveyid = @"\d+", userid = @"\d+" }
  );

Check this Route with Two optional parameters in MVC3 not working

1
votes

The routehandler doesn't really know that if you say /1/1/3r2ytg the 1 is for surveyId, the other 1 is for userId etc.
It just knows a path (localhost:3086) and x amount of "folders"
So if you call http://localhost:3086/1/1/3r2ytg he will map 1 to controller, 1 to action and 3r2ytg to surveyId.
It can't find userId or hash and since there are no defaults specified he can't find the route.
The defaults in your first route are pointless since they will never trigger.
Default values should be at the end of your url, which kinda makes sense.