Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Route value with dashes

I have this route:

            routes.MapRoute(
            "News",
            "News/{id}-{alias}",
            new { controller = "News", action = "Show" },
            new
                {
                    id = @"^[0-9]+$"
                },
            namespaces: new[] { "Site.Controllers" }
        );

This route working for url's like this:

http://localhost:54010/News/6-news

But not working for url's like this:

http://localhost:54010/News/6-nice-news

How use dashes in my route value "alias"?

EDITED

Route like this:

"News/{id}_{alias}"

works for both url's:

http://localhost:54010/News/6_news
http://localhost:54010/News/6_nice-news
like image 532
Alexander Shlenchack Avatar asked Dec 28 '12 20:12

Alexander Shlenchack


1 Answers

The problem is with your pattern: News/{id}-{alias} because the Routeing is parsing the patterns greedily.

So the url http://localhost:54010/News/6-news generates the following tokens:

id = 6, alias = news

But the http://localhost:54010/News/6-nice-news generates the following tokens:

id = 6-nice, alias = news

And the id = 6-nice token will fail your routing contraint @"^[0-9]+$". so you will get 404.

There is now way to configure this behavior of MVC so you have the following options:

  1. Use something else than dashes. As you noted combining dashes and hyphens works.
  2. Take flem approach and parse inside the id and alias inside your controller action
  3. You can create a custom Route which will take of the re-parsing. E.g transforming id = 6-nice, alias = news to id = 6, alias = news-nice

I will show you a raw (without any error handling or good coding practices!) implementation of the option 3 to get you started.

So you need to inherit from Route:

public class MyRoute : Route
{
    public MyRoute(string url, 
        RouteValueDictionary defaults, 
        RouteValueDictionary constraints, 
        RouteValueDictionary dataTokens) 
        : base(url, defaults, constraints, dataTokens, new MvcRouteHandler())
    {
    }

    protected override bool ProcessConstraint(HttpContextBase httpContext, 
        object constraint, string parameterName, RouteValueDictionary values, 
        RouteDirection routeDirection)
    {
        var parts = ((string) values["id"]).Split('-');
        if (parts.Length > 1)
        {
            values["id"] = parts[0];
            values["alias"] = // build up the alias part
                string.Join("-", parts.Skip(1)) + "-" + values["alias"];
        }
        var processConstraint = base.ProcessConstraint(httpContext, constraint, 
            parameterName, values, routeDirection);
        return processConstraint;
    }
}

Then you just need to register your route:

routes.Add("News",
            new MyRoute("News/{id}-{alias}",
            new RouteValueDictionary(new {controller = "News", action = "Show"}),
            new RouteValueDictionary(new
                                        {
                                             id = @"^[0-9]+$"
                                        }),
            new RouteValueDictionary()));
like image 59
nemesv Avatar answered Oct 06 '22 01:10

nemesv