New Dev
New Dev

Reputation: 49590

MVC routing - conflict between parameter and controller name

How can I resolve the following routing rules without explicitly wiring them up?

I would like to add friendly URLs for promotion reasons, like so:

domain.com/promoA
domain.com/promoB

These should be handled by a single "promotions" controller. (I don't mind if this is handled by the "home" controller)

Then, I would like to have URLs of the following form mapped directly to a controller

domain.com/account       ---> controller=account, action=index
domain.com/account/login ---> controller=account, action=login
domain.com/product/list  ---> controller=product, action=list
domain.com               ---> controller=home, action=index

Is it possible?

Thanks!

Upvotes: 1

Views: 639

Answers (2)

bmavity
bmavity

Reputation: 2508

I am not sure if this is the easiest way, but you could set up a route with a constraint. Just make sure you declare it before your other routes.

routes.MapRoute(
    "Promos", // Route name
    "{action}", // URL with parameters
    new { controller = "Promotions", }, // Parameter defaults
    new { action = new PromoConstraint(), }
);

Where PromoConstraint is defined as

public class PromoConstraint : IRouteConstraint
{
    private readonly List<string> _promos = new List<string> { "promoA", "promoB", }; 

    public bool Match(
        HttpContextBase httpContext
        , Route route
        , string parameterName
        , RouteValueDictionary values
        , RouteDirection routeDirection
    )   {
        object value;
        if(!values.TryGetValue(parameterName, out value)) return false;

        var str = value as string;
        if(str == null) return false;

        return _promos.Any(promo => promo.ToLower() == str.ToLower());
    }
}

Upvotes: 1

Andy T
Andy T

Reputation: 9881

Yes it is possible.

All you have to do is have the Index action method in the Home controller check to see if the provided product exists in the product table. If so, return the view for that product, otherwise, just return the index view.

You would need to set up routes for all the other controllers, like you described in your question.

And your root route would need to specify that it will take an optional "product" parameter.

routes.MapRoute("Root",   "{product}",   new { controller = "Home", action = "Index", product = "" });

If they follow a certain pattern, you could add a new route that would handle these promos by adding a constraint using a regular expression.

Upvotes: 0

Related Questions