Route value with dashes

2019-05-06 22:06发布

问题:

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

回答1:

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()));