Как настроить маршрут для динамической привязки url к составленному именованному контроллеру в ASP.NET MVC3


Мне нужно сопоставить URL-адреса следующим образом:

/ акции / риск -->StockRiskController.Index()

/ акции / риск / АТР -->StockRiskController.Attr()

/ srock / риск / Диаграмма -->StockRiskController.Chart()

...

/ связь / производительность -->BondPerformanceController.Index()

/ связь / производительность / attr -->BondPerformanceController.Attr()

/ облигации / производительность / график -->BondPerformanceController.Chart() ...

Первая часть динамична, но поддается перечислению, вторая часть имеет только два варианта(риск|производительность).

На данный момент я знаю только два способа:

  1. настроил ControllerFactory (кажется переполненным или сложным)
  2. жестко кодируйте все комбинации, потому что они перечислимы(уродливы).

Могу ли я использовать routes.MapRoute для достижения этой цели? Или любым другим удобным способом?

1   3  

1 ответ:

Есть хорошее решение, основанное на IRouteConstraint. Прежде всего, мы должны создать новое отображение маршрута:

routes.MapRoute(
  name: "PrefixedMap",
  url: "{prefix}/{body}/{action}/{id}",
  defaults: new { prefix = string.Empty, body = string.Empty
                    , action = "Index", id = string.Empty },
  constraints: new { lang = new MyRouteConstraint() }
);
Следующий шаг-создать наше ограничение. Прежде чем я представлю некоторый способ, как проверить релевантность, как упоминалось выше - два списка с возможными значениями, но логика может быть скорректирована
public class MyRouteConstraint : IRouteConstraint
{
  public readonly IList<string> ControllerPrefixes = new List<string> { "stock", "bond" };
  public readonly IList<string> ControllerBodies = new List<string> { "risk", "performance" };
  ...

А теперь метод Match, который будет корректировать маршрут так, как нам нужно

public bool Match(System.Web.HttpContextBase httpContext
      , Route route, string parameterName, RouteValueDictionary values
      , RouteDirection routeDirection)
{
    // for now skip the Url generation
    if (routeDirection.Equals(RouteDirection.UrlGeneration))
    {
        return false;
    }

    // try to find out our parameters
    string prefix = values["prefix"].ToString();
    string body = values["body"].ToString();

    var arePartsKnown =
        ControllerPrefixes.Contains(prefix, StringComparer.InvariantCultureIgnoreCase) &&
        ControllerBodies.Contains(body, StringComparer.InvariantCultureIgnoreCase);

    // not our case
    if (!arePartsKnown)
    {
        return false;
    }

    // change controller value
    values["controller"] = prefix + body;
    values.Remove("prefix");
    values.Remove("body");

    return true;
}
Вы можете играть с этим методом больше, но теперь концепция должна быть ясна.

Примечание: мне нравится ваш подход. Иногда просто гораздо важнее расширить / настроить маршрутизацию, а затем перейти к коду и "исправить имена". Аналогичное решение работало и здесь: динамически модифицируйте RouteValueDictionary