Изменить маршрутизацию MVC с динамическим префиксом при сохранении обратной совместимости URL - PullRequest
0 голосов
/ 30 ноября 2011

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

/ {friendlyName} / {controller} / {index} / {id}

, что понятное имя уникально иПозволяет мне выбрать правильного клиента без использования cookie Kludge.

У меня есть контроллеры: Home, Redirect, для которых мне не нужна часть с дружественным именем (и, возможно, больше).

У меня есть несколько других людей, которые подпадают под эту категорию, и я хотел бы перейти в их собственные области.Как я могу не включать области в качестве допустимых дружеских имен?Например, у меня есть контроллер, который обслуживает контент в iframe с именем Framed.в настоящее время URL для этого выглядит как / Framed / action / id.Я мог бы поместить это в область под названием Framed с контроллером с тем же именем, что и у действия, и я все еще смогу поддерживать тот же URL.

Для контроллера Error Мне нужно понятное имябыть необязательным

У меня есть другие контроллеры, которые я хочу, чтобы требовалось дружественное имя: SignIn, SignOut, Account

Как только у меня есть маршрутизация, проблема меняетсякод, чтобы мои перенаправления поддерживали friendlyurl.Любые идеи о том, как это сделать?

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

Ответы [ 2 ]

3 голосов
/ 30 ноября 2011

Для достижения ваших целей вам понадобится комбинация маршрутов и RouteConstraints.Кроме того, вам нужно будет применять правила, которые friendlyName уникальны и отличаются от имен любых контроллеров или областей.

Следующие маршруты должны быть достаточными в RegisterRoutes() в Global.asax.cs:

routes.MapRoute(
    "WithFriendlyName",
    "{friendlyName}/{controller}/{index}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    new { friendlyName = new MustBeFriendlyName() }
);

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    new { controller = new MustNotRequireFriendlyName() }
);

RouteConstraints должны выглядеть примерно так:

using System;
using System.Web;
using System.Web.Routing;

namespace Examples.Extensions
{
    public class MustBeFriendlyName : IRouteConstraint
    {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            // return true if this is a valid friendlyName
            // MUST BE CERTAIN friendlyName DOES NOT MATCH ANY
            // CONTROLLER NAMES OR AREA NAMES
            var _db = new DbContext();
            return _db.FriendlyNames.FirstOrDefault(x => x.FriendlyName.ToLowerInvariant() ==
                values[parameterName].ToString().ToLowerInvariant()) != null;
        }
    }

    public class MustNotRequireFriendlyName : IRouteConstraint
    {
        private const string controllersRequiringFriendlyNames = 
            "SignIn~SignOut~Account";

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            // return true if this controller does NOT require a friendlyName
            return controllersRequiringFriendlyNames.ToLowerInvariant()
                .Contains(values[parameterName].ToString().ToLowerInvariant());
        }
    }
} 

Это должно помочь вам начать работу.

Что касается URL, генерируемых вашими перенаправлениями, еслимаршрутизация настроена правильно, генерация URL должна следовать, так что единственные изменения, которые вам, вероятно, понадобятся, это изменения, чтобы обеспечить передачу {friendlyName}.

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

1 голос
/ 19 декабря 2012

Просто хотел добавить к этому, поскольку дополнительный префикс кусал меня последние пару дней. Хотя я хочу использовать решение, предоставляемое @counsellorben, мне также нужно было иметь возможность обращаться к маршрутам с одинаковым именем, что невозможно при использовании 2 маршрутов.

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

public class AggregateRoute : RouteBase
{
  private readonly RouteBase[] _routes;

  public AggregateRoute(params RouteBase[] routes)
  {
    _routes = routes;
  }

  public override RouteData GetRouteData(HttpContextBase httpContext)
  {
    RouteData routeData = null;
    foreach (var route in _routes)
    {
      routeData = route.GetRouteData(httpContext);
      if (routeData != null) break;
    }

    return routeData;
  }

  public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
  {
    VirtualPathData virtualPath = null;
    foreach (var route in _routes)
    {
      virtualPath = route.GetVirtualPath(requestContext, values);
      if (virtualPath != null) break;
    }

    return virtualPath;
  }
}

Это позволяет мне сделать:

routes.Add(
    "RouteName",
    new AggregateRoute(
      new Route("{path}", new MvcRouteHandler()),
      new Route("{prefix}/{path}", new MvcRouteHandler())
    )
);

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

Url.RouteLink("RouteName", new RouteValueDictionary{
  new{path="some-path"}});

Url.RouteLink("RouteName", new RouteValueDictionary{
  new{path="some-prefix/some-path"}});
...