ASP.NET MVC: Route with optional parameter, but if supplied, must match \d+

前端 未结 6 1303
孤街浪徒
孤街浪徒 2020-11-29 12:00

I\'m trying to write a route with a nullable int in it. It should be possible to go to both /profile/ but also /profile/\\d+.

route         


        
6条回答
  •  遥遥无期
    2020-11-29 12:33

    ASP.NET MVC 3 has solved this problem, and as Alex Ford brought out, you can use \d* instead of writing a custom constraint. If your pattern is more complicated, like looking for a year with \d{4}, just make sure your pattern matches what you want as well as an empty string, like (\d{4})? or \d{4}|^$. Whatever makes you happy.

    If you are still using ASP.NET MVC 2 and want to use Mark Bell's example or NYCChris' example, please be aware that the route will match as long as the URL parameter contains a match to your pattern. This means that the pattern \d+ will match parameters like abc123def. To avoid this, wrap the pattern with ^( and )$ either when defining your routes or in the custom constraint. (If you look at System.Web.Routing.Route.ProcessConstraint in Reflector, you'll see that it does this for you when using the built in constraint. It also sets the CultureInvariant, Compiled, and IgnoreCase options.)

    Since I already wrote my own custom constraint with the default behavior mentioned above before realizing I didn't have to use it, I'll leave it here:

    public class OptionalConstraint : IRouteConstraint
    {
      public OptionalConstraint(Regex regex)
      {
        this.Regex = regex;
      }
    
      public OptionalConstraint(string pattern) :
        this(new Regex("^(" + pattern + ")$",
          RegexOptions.CultureInvariant |
          RegexOptions.Compiled |
          RegexOptions.IgnoreCase)) { }
    
      public Regex Regex { get; set; }
    
      public bool Match(HttpContextBase httpContext,
                        Route route,
                        string parameterName,
                        RouteValueDictionary values,
                        RouteDirection routeDirection)
      {
        if(routeDirection == RouteDirection.IncomingRequest)
        {
          object value = values[parameterName];
          if(value == UrlParameter.Optional)
            return true;
          if(this.Regex.IsMatch(value.ToString()))
            return true;
        }
    
        return false;
      }
    }
    

    And here's an example route:

    routes.MapRoute("PostsByDate",
                    "{year}/{month}",
                    new { controller = "Posts",
                          action = "ByDate",
                          month = UrlParameter.Optional },
                    new { year = @"\d{4}",
                          month = new OptionalConstraint(@"\d\d") });
    

提交回复
热议问题