Sepehr Estaki
Sepehr Estaki

Reputation: 351

custom mapRoute for special controller and action to be like this in MVC: http://example.com/someValue

I have this default mapRoute:

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

and some other mapRoutes for some other sontrollers before default,

now, I want a mapRoute for special controller to show the url like : myDomain.com/someValue, but when I use this:

routes.MapRoute(
name: "categories",
url: "{sub}",
defaults: new { controller = "cat", action = "Index" }
);

all of my url.Actions which have "Index" as action like @Url.Action("index","login") not work, I have also used :

sub=UrlParameter.Optional

and

sub=""

, but they did not work, what should I do ?

Upvotes: 1

Views: 1257

Answers (2)

Sam FarajpourGhamari
Sam FarajpourGhamari

Reputation: 14741

Your categories route catches all urls because it is match with the role. You need to write a custom constraint class to filter out unmatched subs form your database for example.

public class MyCatConstraint : IRouteConstraint
{
    // suppose this is your cats list. In the real world a DB provider 
    private string[] _myCats = new[] { "cat1", "cat2", "cat3" };

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        // return true if you found a match on your cat's list otherwise false
        // in the real world you could query from DB to match cats instead of searching from the array.  
        if(values.ContainsKey(parameterName))
        {
            return _myCats.Any(c => c == values[parameterName].ToString());
        }
        return false;
    }
}

and then add this constraint to your route.

routes.MapRoute(
    name: "categories",
    url: "{sub}",
    defaults: new { controller = "cat", action = "Index" }
    ,constraints: new { sub = new MyCatConstraint() }
    );

Upvotes: 0

Artur Kedzior
Artur Kedzior

Reputation: 4273

Sam's answer is good but I would do it the other way around. If your parameter {sub} for "someValue" is dynamic (stored in database) I would create a constraint that excludes your existing controllers. So If you call

domain.com/home or domain.com/contact

it would reach these controllers otherwise route through categories. For example:

public class NotEqual : IRouteConstraint
{
    private string[] _match = null;

    public NotEqual(string[] match)
    {
        _match = match;
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        foreach(var controllername in _match)
        {
            if (String.Compare(values[parameterName].ToString(), controllername, true) == 0)
                return false;
        }
        return true;
    }
}

Modified version of: http://stephenwalther.com/archive/2008/08/07/asp-net-mvc-tip-30-create-custom-route-constraints

and your route would be:

        routes.MapRoute(
            name: "categories",
            url: "{sub}",
            defaults: new { controller = "cat", action = "Index" }
            , constraints: new { sub = new NotEqual(new string[] { "Contact", "Home" }) }
         );

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

This way whatever you put that is different to domain.com/contact or domain.com/home will get re-routed to your cat controller

@Url.Action("Index","Contact") 

Should produce:

/Contact

Upvotes: 0

Related Questions