Routing to index with id in ASP.NET MVC 4

asp.net, asp.net-mvc, asp.net-mvc-routing, c#

Solution

In case, that the list of your actions (e.g. Send) is well known, and their (action) names cannot be the same as some ID value, we can use our custom ConstraintImplementation:

public class MyRouteConstraint : IRouteConstraint
{
  public readonly IList<string> KnownActions = new List<string> 
       { "Send", "Find", ... }; // explicit action names

  public bool Match(System.Web.HttpContextBase httpContext, Route route
                  , string parameterName, RouteValueDictionary values
                  , RouteDirection routeDirection)
  {
    // for now skip the Url generation
    if (routeDirection.Equals(RouteDirection.UrlGeneration))
    {
      return false; // leave it on default
    }

    // try to find out our parameters
    string action = values["action"].ToString();
    string id = values["id"].ToString();

    // id and action were provided?
    var bothProvided = !(string.IsNullOrEmpty(action) || string.IsNullOrEmpty(id));
    if (bothProvided)
    {
      return false; // leave it on default
    }

    var isKnownAction = KnownActions.Contains(action
                           , StringComparer.InvariantCultureIgnoreCase);

    // action is known
    if (isKnownAction)
    {
      return false; // leave it on default
    }

    // action is not known, id was found
    values["action"] = "Index"; // change action
    values["id"] = action; // use the id

    return true;
  }

And the route map (before the default one - both must be provided), should look like this:

routes.MapRoute(
  name: "DefaultMap",
  url: "{controller}/{action}/{id}",
  defaults: new { controller = string.Empty, action = "Index", id = string.Empty },
  constraints: new { lang = new MyRouteConstraint() }
);

Summary: In this case, we are evaluating the value of the "action" parameter.

- if both 1) action and 2) id are provided, we won't handle it here.

- nor if this is known action (in the list, or reflected...).

- only if the action name is unknown, let's change the route values: set action to "Index" and action value to ID.

NOTE: `action` names and `id` values need to be unique... then this will work

Problem

I'd like to maintain ASP.NET MVC 4's existing controller/action/id routing with default controller = Home and default action = Index, but also enable controller/id to route to the controller's index method as long as the second item is not a known action. For example, given a controller Home with actions Index and Send: ``` /Home/Send -> controller's Send method /Home -> controller's Index method /Home/Send/xyz -> controller's Send method with id = xyz /Home/abc -> controller's Index method with id = abc ``` However, if I define either route first, it hides the other one. How would I do this?

Original source

Related problems