1

I would like my MVC website to be able to route the following URLs:

http://www.example.com/{userId}
http://www.example.com/{userId}/enroll

Note: userId is a string of letters, numbers and/or hyphens.

I realize this is problematic because the URL does not specify a controller name. However, it should be possible in theory. I can use reflection to get a list of all the controllers in my application. If {userId} does not match any of those controllers, then it should be redirected to a particular controller/action.

My first question is how would you specify a map like this? I can specify a string value, I can even specify a regular expression. But how can I filter based on whether or not it matches a list of strings?

Beyond that, just wondered if anyone else has thought of doing things and if they have any other creative ideas on how I might accomplish it.

Community
  • 1
  • 1
Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • Answer to opinion based part: pretty everyone thought to do that, many done it and almost everyone got burned... It is insanely hard to carve out url space later for something else if you have broad rule that matches pretty much anything for first segments... If you are doing it for real site consider dedicating first one or two segments for url classification (i.e. /users/{uid} or /{lang}/users/{uid}, also see SO urls). – Alexei Levenkov Apr 02 '17 at 19:53
  • @AlexeiLevenkov: Yes, that is an option I am considering. Obviously, the way I'm asking about would be more clean from the user's perspective. I should point out that the number of IDs I will have for this value is pretty small (it is a SAAS for these users). If I add a new controller in the future, all it takes is a second to make sure I don't have any matching IDs in the database and I'm good to go. So I'm very open to hear why it this approach might be a problem, but I'm not sure I see trying to add new controllers in the future as a big concern. – Jonathan Wood Apr 02 '17 at 19:58
  • 1
    One of the biggest problems with routing like this is when the URL is ambiguous. For example (and this may be a little contrived for your example) what if the `userId` was `enroll`? – DavidG Apr 02 '17 at 20:12
  • @DavidG: I think that would be ok if the ID was "enroll". It would be interpreted as the user ID because my application has no controllers named "Enroll". And I don't see where that would cause problems with my second URL ("enroll/enroll") either. Do you think I might be missing something? – Jonathan Wood Apr 02 '17 at 21:49
  • OK, bad example :) But I'm sure your app has more URLs than the ones shown? – DavidG Apr 02 '17 at 21:57
  • @DavidG: Honestly, I think I would only need to implement this technique for these two landing page URLs. I understand your point about potentially problematic. But it seems like it could be done, and with the cleaner URL, it might be worth the trade off. – Jonathan Wood Apr 02 '17 at 22:18
  • A more detailed [answer here](http://stackoverflow.com/questions/37358416/routing-in-asp-net-mvc-showing-username-in-url/37359345#37359345) which might help –  Apr 02 '17 at 22:31
  • StephenMuecke: Nice find. Thanks! – Jonathan Wood Apr 02 '17 at 22:35

1 Answers1

3

If I understand your question right:

routes.MapRoute(
  name: "Default",
  url: "{id}/{action}",
  defaults: new { controller = "Custom", action = "Index" },
  constraint: new { id = new MyRouteConstraint()});

In custom MyRouteConstraint: IRouteConstraint you can match your parameter with list of strings

Denis Krasakov
  • 1,498
  • 2
  • 13
  • 17
  • 1
    I'm looking into this. Not sure why you assign the instance of `MyRouteContraints` to `id`. Shouldn't it be specifying the controller? – Jonathan Wood Apr 02 '17 at 19:41
  • @JonathanWood ? You may want to read on routing basics... Controller is specified in `defaults:` in this sample, `constraints` limit values in `url`. – Alexei Levenkov Apr 02 '17 at 19:56
  • Side note: it is likely you want to check if userId is valid in the route but this is impossible in ASP.Net MVC if you want to do in asynchronous (as you'd normally would). So you can only roughly limit "id" to "potentially valid userId" rather than "existing user ID". – Alexei Levenkov Apr 02 '17 at 19:57
  • @JonathanWood `id = new MyRouteConstraint()` means that `MyRouteConstraint` class check `id` parameter. When you implement `IRouteConstraint` you should add method `Match` - [see msdn](https://msdn.microsoft.com/en-GB/library/system.web.routing.irouteconstraint.match(v=vs.110).aspx). parameterName would receive value that you specified here ("id" in my case) – Denis Krasakov Apr 02 '17 at 19:58