Ограничение маршрута регулярного выражения ASP.NET MVC - PullRequest
8 голосов
/ 30 декабря 2010

У меня проблемы с определенным ограничением, которое я пытаюсь установить на маршруте. Мой URL должен выглядеть следующим образом: http://hostname/id-my-title-can-be-that-long, где идентификатор состоит только из цифр, а заголовок состоит из строчных букв с разделителем тире. Идентификатор и заголовок также разделены тире. Например: http://hostname/123-my-title.

Вот мое определение маршрута:

routes.MapRoute(
    "Test",
    "{id}-{title}",
    new { controller = "Article", action = "Index" },
    new { id = @"(\d)+", title = @"([a-z]+-?)+" }
);

URL-адрес правильно генерируется с помощью помощника html:

<%: Html.ActionLink("My link", "Index", "Article", new { id = Model.IdArticle, title = Model.UrlTitle }, null) %>

, где, конечно, Model.IdArticle - это Int32, а Model.UrlTitle - предварительно сформированная строка моего заголовка, которая соответствует моим требованиям (только строчные буквы, пробел заменяется на тире).

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

Для записей я нахожусь на ASP.NET MVC 2.

У кого-нибудь есть идея?

Заранее спасибо, Fabian

Ответы [ 2 ]

0 голосов
/ 30 декабря 2010

Несколько символов в маршруте являются «специальными» и разделяют такие параметры, как - и /. Возможно, что дополнительные параметры в маршруте вызывают его сбой. Попробуйте "{id}-{*title}", так как это делает заголовок включающим все, что следует.

Обновление

Ответ выше - это то, что происходит, когда вы заходите в StackOverflow до того, как вы выпили достаточно кофе.

Мы столкнулись с той же проблемой, связанной с именами файлов для файлов, загружаемых пользователями, маршрут включал «-» в качестве разделителя, но его также можно использовать в значении в более позднем параметре, он может генерировать правильный URL, но не будет » не соответствует этому. В конце я написал класс SpecialFileRoute для решения этой проблемы и зарегистрировал этот маршрут. Это немного уродливо, но делает работу.

Обратите внимание, что я придерживался старого стиля MVC для генерации URL-адреса, я пытался заставить это сделать это правильно, но к этому нужно вернуться позже.

    /// <summary>
/// Special route to handle hyphens in the filename, a catchall parameter in the commented route caused exceptions
/// </summary>
public class SpecialFileRoute : RouteBase, IRouteWithArea
{
    public string Controller { get; set; }
    public string Action { get; set; }
    public IRouteHandler RouteHandler = new MvcRouteHandler();
    public string Area { get; private set; }

    //Doc/{doccode} - {CatNumber}.{version} - {*filename},

    public SpecialFileRoute(string area)
    {
        Area = area;
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        string url = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2);
        var urlmatch = Regex.Match(url, @"doc/(\w*) - (\d*).(\d*) - (.*)", RegexOptions.IgnoreCase);
        if (urlmatch.Success)
        {
            var routeData = new RouteData(this, this.RouteHandler);

            routeData.Values.Add("doccode", urlmatch.Groups[1].Value);
            routeData.Values.Add("CatNumber", urlmatch.Groups[2].Value);
            routeData.Values.Add("version", urlmatch.Groups[3].Value);
            routeData.Values.Add("filename", urlmatch.Groups[4].Value);
            routeData.Values.Add("controller", this.Controller);
            routeData.Values.Add("action", this.Action);
            return routeData;
        }
        else
            return null;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        if (values.ContainsKey("controller") && (!string.Equals(Controller, values["controller"] as string, StringComparison.InvariantCultureIgnoreCase)))
            return null;
        if (values.ContainsKey("action") && (!string.Equals(Action, values["action"] as string, StringComparison.InvariantCultureIgnoreCase)))
            return null;
        if ((!values.ContainsKey("contentUrl")) || (!values.ContainsKey("format")))
            return null;
        return new VirtualPathData(this, string.Format("{0}.{1}", values["contentUrl"], values["format"]));
    }
}

Маршрут добавляется следующим образом:

context.Routes.Add(new SpecialFileRoute(AreaName) { Controller = "Doc", Action = "Download" });

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

0 голосов
/ 30 декабря 2010

Вы можете попробовать передать всю строку маршрута "{id} - {title}" и вручную проанализировать строку, прежде чем она попадет в ваши действия, выполнив что-то похожее на атрибут slug to id Фила Хаака для id actionfilter - ссылка

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...