简体   繁体   中英

MVC Routing not giving desired route

I have the following code in my RouteConfig.cs file:

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

    routes.MapRoute(
        name: "Location",
        url: "Order/Location",
        defaults: new { controller = "Order", action = "Location" }
    );

    routes.MapRoute(
        name: "Step3",
        url: "Order/{location}/{category}/{item}/{id}/{orderId}",
        defaults: new { controller = "Order", action = "Step3", orderId = UrlParameter.Optional }
    );

    routes.MapRoute(
        name: "Step2",
        url: "Order/{location}/{category}/{orderId}",
        defaults: new { controller = "Order", action = "Step2", orderId = UrlParameter.Optional }
    );

    routes.MapRoute(
        name: "Step1",
        url: "Order/{location}/{orderId}",
        defaults: new { controller = "Order", action = "Step1", orderId = UrlParameter.Optional }
    );

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

Here is what I'm trying to achieve:

-----------------------------------------------------------------------
| Url                                              | Desired Action   |
|--------------------------------------------------|------------------|
| http://localhost/Order/Phoenix                   | Step1            |
| http://localhost/Order/Phoenix/Parts             | Step2            |
| http://localhost/Order/Phoenix/Parts/Plugs/12    | Step3            |
| http://localhost/Order/Phoenix/47                | Step1            |
| http://localhost/Order/Phoenix/Parts/47          | Step2            |
| http://localhost/Order/Phoenix/Parts/Plugs/12/47 | Step3            |
|---------------------------------------------------------------------|

The first 3 URLs are working, as expected. The problem is with the last 3. I know what's happening. The MVC route engine is evaluating the routes in the order they were mapped and when it sees http://localhost/Phoenix/47 , it is thinking 47 is a category and its going to Step2 before it gets to Step1 . I almost need the route engine to be smart enough to know that a number will be an orderId .

How can I re-engineer my route list to get me the desired behavior?

Assuming that your methods in OrderController are (in particular that orderId is type of int )

// Order/{location}/{orderId}
public ActionResult Step1(string location, int? orderId)

// Order/{location}/{category}/{orderId}
public ActionResult Step2(string location, string category, int? orderId)

// Order/{location}/{category}/{item}/{id}/{orderId}
public ActionResult Step3(string location, string category, string item, int id, int? orderId)

The you can add a route constraint to check if orderId has been supplied and that it is an int . Change the order of the routes to

routes.MapRoute(
    name: "Step1",
    url: "Order/{location}/{orderId}",
    defaults: new { controller = "Order", action = "Step1", orderId = UrlParameter.Optional },
    constraints: new { orderId = new OrderConstraint() }
);

routes.MapRoute(
    name: "Step2",
    url: "Order/{location}/{category}/{orderId}",
    defaults: new { controller = "Order", action = "Step2", orderId = UrlParameter.Optional },
    constraints: new { orderId = new OrderConstraint() }
);

routes.MapRoute(
    name: "Step3",
    url: "Order/{location}/{category}/{item}/{id}/{orderId}",
    defaults: new { controller = "Order", action = "Step3", orderId = UrlParameter.Optional },
    constraints: new { orderId = new OrderConstraint() }
);

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

and add a route constraint

public class OrderConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        string v = values["orderId"].ToString();
        if (String.IsNullOrEmpty(v))
        {
            return true;
        }
        int value;
        return int.TryParse(values["orderId"].ToString(), out value);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM