如何自定义路由以将动态映射到ASP.NET MVC3中的组合命名控制器

时间:2012-11-28 09:50:56

标签: asp.net-mvc asp.net-mvc-3

我需要映射这样的网址:

/ stock / risk - > StockRiskController.Index()

/ stock / risk / attr - > StockRiskController.Attr()

/ srock / risk / chart - > StockRiskController.Chart()

...

/ bond / performance - > BondPerformanceController.Index()

/ bond / performance / attr - > BondPerformanceController.Attr()

/ bond / performance / chart - > BondPerformanceController.Chart() ...

第一部分是动态但可枚举,第二部分只有两个选项(风险|性能)。

目前我只知道两种方式:

  1. 自定义一个ControllerFactory(似乎过度使用或复杂)
  2. 硬编码所有组合,因为它们是可枚举的(丑陋的)。
  3. 我可以使用routes.MapRoute来实现这一目标吗?还是其他任何方便的方式?

1 个答案:

答案 0 :(得分:2)

有一个基于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;
}

你可以更多地使用这种方法,但现在应该清楚这个概念。

注意:我喜欢你的方法。有时,扩展/调整路由然后转到代码并“修改名称”更为重要。类似的解决方案在这里工作:Dynamically modify RouteValueDictionary