ASP.NET MVC: маршрут с дополнительным параметром, но если он указан, должен соответствовать \ d +

Я пытаюсь написать маршрут с нулевым int в нем. Должно быть возможно перейти на оба параметра /profile/ но также и /profile/\d+ .

 routes.MapRoute("ProfileDetails", "profile/{userId}", new {controller = "Profile", action = "Details", userId = UrlParameter.Optional}, new {userId = @"\d+"}); 

Как вы можете видеть, я говорю, что userId является необязательным, но также должен соответствовать регулярному выражению \d+ . Это не работает, и я понимаю, почему.

Но как мне построить маршрут, который соответствует только /profile/ но также /profile/ за которым следует число?

Самый простой способ – просто добавить еще один маршрут без параметра userId , поэтому у вас есть резерв:

 routes.MapRoute("ProfileDetails", "profile/{userId}", new {controller = "Profile", action = "Details", userId = UrlParameter.Optional}, new {userId = @"\d+"}); routes.MapRoute("Profile", "profile", new {controller = "Profile", action = "Details"}); 

Насколько я знаю, единственный способ, которым вы можете это сделать, – это создать собственное ограничение. Таким образом, ваш маршрут станет следующим:

 routes.MapRoute("ProfileDetails", "profile/{userId}", new {controller = "Profile", action = "Details", userId = UrlParameter.Optional}, new {userId = new NullableConstraint()); 

И код пользовательского ограничения будет выглядеть так:

 using System; using System.Web; using System.Web.Routing; using System.Web.Mvc; namespace YourNamespace { public class NullableConstraint : IRouteConstraint { public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { if (routeDirection == RouteDirection.IncomingRequest && parameterName == "userId") { // If the userId param is empty (weird way of checking, I know) if (values["userId"] == UrlParameter.Optional) return true; // If the userId param is an int int id; if (Int32.TryParse(values["userId"].ToString(), out id)) return true; } return false; } } } 

Я не знаю, что NullableConstraint – лучшее имя здесь, но это зависит от вас!

Возможно, что-то изменилось, поскольку на этот вопрос был дан ответ, но я смог изменить это:

 routes.MapPageRoute( null, "projects/{operation}/{id}", "~/Projects/ProjectWizard.aspx", true, new RouteValueDictionary(new { operation = "new", id = UrlParameter.Optional }), new RouteValueDictionary(new { id = new NullableExpressionConstraint(@"\d+") }) ); 

С этим:

 routes.MapPageRoute( null, "projects/{operation}/{id}", "~/Projects/ProjectWizard.aspx", true, new RouteValueDictionary(new { operation = "new", id = UrlParameter.Optional }), new RouteValueDictionary(new { id = @"\d*" }) ); 

Просто используя * а вместо + в регулярном выражении выполняется одна и та же задача. Маршрут по-прежнему запускается, если параметр не был включен, но если он включен, он будет гореть только в том случае, если значение было действительным целым числом. В противном случае это потерпит неудачу.

ASP.NET MVC 3 решил эту проблему, и, как Алекс Форд вывел , вы можете использовать \d* вместо написания пользовательского ограничения. Если ваш шаблон более сложный, например, поиск года с помощью \d{4} , просто убедитесь, что ваш шаблон соответствует тому, что вам нужно, и пустой строке, например (\d{4})? или \d{4}|^$ . Все, что делает тебя счастливым.

Если вы все еще используете ASP.NET MVC 2 и хотите использовать пример Mark Bell или пример NYCChris , помните, что маршрут будет соответствовать, если параметр URL содержит совпадение с вашим шаблоном. Это означает, что шаблон \d+ будет соответствовать таким параметрам, как abc123def . Чтобы этого избежать, оберните шаблон с помощью ^( и )$ либо при определении маршрутов, либо в пользовательском ограничении. (Если вы посмотрите на System.Web.Routing.Route.ProcessConstraint в Reflector , вы увидите, что он делает это для вас при использовании встроенного ограничения, а также устанавливает параметры CultureInvariant, Compiled и IgnoreCase .)

Поскольку я уже написал собственное пользовательское ограничение с поведением по умолчанию, упомянутым выше, прежде чем осознать, что мне не нужно его использовать, я оставлю его здесь:

 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; } } 

И вот пример маршрута:

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

должно ли ваше регулярное выражение быть \ d *?

Спасибо Марку Белу за этот ответ, это помогло мне совсем немного.

Мне интересно, почему вы жестко закодировали чек на «userId» в ограничении? Я немного переписал ваш class, как пользователь, parameterName parameterName, и, похоже, он работает нормально.

Я что-то пропустил, делая это так?

 public class OptionalRegExConstraint : IRouteConstraint { private readonly Regex _regEx; public OptionalRegExConstraint(string matchExpression=null) { if (!string.IsNullOrEmpty(matchExpression)) _regEx = new Regex(matchExpression); } public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { if (routeDirection == RouteDirection.IncomingRequest) { if (values[parameterName] == UrlParameter.Optional) return true; return _regEx != null && _regEx.Match(values[parameterName].ToString()).Success; } return false; } } 

Мне нужно было проверить некоторые вещи с помощью не только RegEx, но и по-прежнему возникала проблема, подобная этому. Мой подход заключался в том, чтобы написать оболочку ограничений для любых пользовательских ограничений маршрута, которые у меня уже есть:

 public class OptionalRouteConstraint : IRouteConstraint { public IRouteConstraint Constraint { get; set; } public bool Match ( HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection ) { var value = values[parameterName]; if (value != UrlParameter.Optional) { return Constraint.Match(httpContext, route, parameterName, values, routeDirection); } else { return true; } } } 

А затем, в constraints по маршруту в RouteConfig.cs , он будет выглядеть так:

 defaults: new { //... other params userid = UrlParameter.Optional } constraints: new { //... other constraints userid = new OptionalRouteConstraint { Constraint = new UserIdConstraint() } } 
  • Как использовать префикс привязки?
  • В чем разница (если есть) между Html.Partial (view, model) и Html.RenderPartial (view, model) в MVC2?
  • Проверка: как ввести оболочку State Model с помощью Ninject?
  • ASP.NET MVC - Поймать весь маршрут и маршрут по умолчанию
  • Загрузить файл любого типа в Asp.Net MVC с помощью FileResult?
  • Отображение разницы между двумя значениями datetime в часах
  • asp.net mvc azure "Ошибка доступа к хранилищу данных!"
  • jQuery Ajax вызывает и Html.AntiForgeryToken ()
  • Использование DataAnnotations с платформой Entity Framework
  • Как изменить сообщение об ошибке проверки по умолчанию в ASP.NET MVC?
  • Не удается получить sql server compact 3.5 / 4 для работы с ASP.NET MVC 2
  • Давайте будем гением компьютера.