ASP.net MVC пользовательский маршрут обработчик/ограничение

Мне нужно реализовать сайт MVC с URL-адресами ниже:

  • category1/продукт/1/вики
  • category1/продукта/2/вики
  • category1/суб-category2/продукта/3/вики
  • category1/суб-category2/суб-category3/продукта/4/вики
  • и т.д.. и др.

где критерии соответствия заключаются в том, что URL-адрес заканчивается "wiki".

К сожалению, нижеследующий catch-all работает только в последней части URL-адреса:

routes.MapRoute("page1", // Route name
                "{*path}/wiki", // URL with parameters
                new { controller = "Wiki", action = "page", version = "" } // Parameter defaults

У меня не было времени пройти через возможности расширения MVC, поэтому мне было интересно, какие возможные варианты для реализации этого? Любой образец/пример был бы просто фантастическим!

Ответы

Ответ 1

Как вы упомянули, параметр catch-all может появляться только в конце маршрута - код, который вы опубликовали, будет вызывать ошибку во время выполнения и дать вам желтый экран смерти, если вы даже попытаетесь запустить свой приложение.

Существует несколько точек расширяемости для создания пользовательских маршрутных сценариев. Это - Route, RouteBase и IRouteHandler.

Вы можете создать сгенерированный список маршрутов для обработки, расширив RouteBase. Как правило, вы должны следовать шаблону наличия конструктора, который принимает ресурс (имя контроллера), а затем присваивает ему список маршрутов, за которые он отвечает, а затем сопоставляет его в вашем global.asax. Вот пример кода, из которого вы можете построить:

public class MyRoute : RouteBase
{
    private List<Route> _routes = new List<Route>();

    public MyRoute(string resource)
    {
        // make a Resource property, not shown in this example
        this.Resource = resource;

        // Generate all your routes here
        _routes.Add(
            new Route("some/url/{param1}",
            new McvRouteHandler {
                Defaults = new RouteValueDictionary(new {
                    controller = resource,
                    action = actionName
                }),
            Constraints = new RouteValueDictionary()
        );
        _routes.Add(...); // another new route   
    }

    public override RouteData GetRouteData(HttpContextBase context)
    {
        foreach (var route in _routes)
        {
            var data = route.GetRouteData(context);
            if (data != null)
            { 
                return data;
            }
        }
        return null;
    }

    public override VirtualPathData GetVirtualPath(RequestContext context, RouteValueDictionary rvd)
    {
        foreach (var route in _routes)
        {
            var path = route.GetVirtualPath(context, rvd);
            if (path != null)
            { 
                return path;
            }
        }
        return null;
    }
}

Чтобы использовать свой класс маршрутизации, сделайте routes.Add(new MyRoute("page1")); в своем приложении Global.asax.

Если вам нужен еще больший контроль, вы можете реализовать IRouteHandler, а вместо создания MvcRouteHandlers() для ваших маршрутов, как показано в приведенном выше примере, используйте свой собственный IRouteHandler. Это позволит вам переопределить логику выбора контроллера из данных запроса.

Вся инфраструктура чрезвычайно расширяема, но вам нужно немного научиться, чтобы сделать это правильно. Я бы предложил просто переупорядочить ваш URL, если это возможно, чтобы воспользоваться опцией catch-all, если вы можете.