5

我的路线设置如下:

        context.MapRoute(
        name: "Area",
        url: "Area/{controller}/{action}",
        defaults: new
        {
            controller = "Home",
            action = "Dashboard"
        }
        );

        context.MapRoute(
        name: "AccountArea",
        url: "Area/{accountFriendlyId}/{controller}/{action}",
        defaults: new
        {
            controller = "Home",
            action = "Dashboard",
            accountFriendlyId = RouteParameter.Optional
        }
        );

        context.MapRoute(
        name: "AccountCampaignArea",
        url: "Area/{accountFriendlyId}/{campaignFriendlyId}/{controller}/{action}",
        defaults: new
                {
                    controller = "Home", 
                    action = "Dashboard",
                    accountFriendlyId = RouteParameter.Optional,
                    campaignFriendlyId = RouteParameter.Optional
                }
        );

而且我有强烈的愿望要Area/friendlyAccountName/Home带我去,Dashboard()但这不起作用(404)。我认为原因是我们去寻找一个friendlyAccountName 控制器。

知道如果我应该选择在我的一个控制器崩溃后命名一个帐户,那么如果字符串无法找到相应的控制器,是否有办法进入下一个路由?每次修改控制器列表时,是否有某种方法可以使用反射并避免维护约束?

编辑

您是否知道一种不使用反射或至少包含对该区域的派生类型搜索的方法?我不喜欢在第二个路由参数与控制器名称匹配时产生两次开销的想法(传递约束,然后在构造控制器时再次搜索)。我希望有一种方法可以在构造控制器时捕获异常,然后备份并下降到下一条路线。

4

3 回答 3

7

为什么你需要第一条路线?如果{accountFriendlyId}是可选的,您应该能够省略它并获得与您的第一个注册路由相同的路由默认值。

这样,它将首先匹配AccountArea命名路由,这是您想要的,然后如果{accountFriendlyId}未指定 an ,它将将该区域之后的第一个标记视为控制器。

事实上,我觉得你应该能够完全删除前两个路由并坚持最后一个,因为前两个路由参数是可选的,默认值是相同的。

更新

由于{accountFriendlyId}可能是一个有效的控制器操作名称,你可以做一些其他的事情:

  1. 移动{accountFriendlyId}到路线的终点,而不是起点。这遵循从最广泛的资源到资源中特定细节的更自然的 URL 样式。
  2. 使用路线约束。理论上,您可以使用反射来生成正则表达式以匹配自定义约束中的控制器名称,或者您可以手动将它们写出来。像这样的东西:

上下文.MapRoute(

    name: "Area",
    url: "Area/{controller}/{action}",
    defaults: new
    {
        controller = "Home",
        action = "Dashboard",
        new { controller = @"(Account|Profile|Maintenance)" }
    }

);

于 2012-05-02T18:37:00.013 回答
6

最终,为了方便我想要的(这取决于让应用程序动态区分任意字符串和控制器名称),我设置了这样的路由:

public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
        name: "AccountCampaignArea",
        url: "Area/{accountFriendlyId}/{campaignFriendlyId}/{controller}/{action}",
        defaults: new
            {
                controller = "Home",
                action = "Dashboard",
                accountFriendlyId = RouteParameter.Optional,
                campaignFriendlyId = RouteParameter.Optional,
                id = UrlParameter.Optional
            },
        constraints: new { accountFriendlyId = new ControllerNameConstraint(), campaignFriendlyId = new ControllerNameConstraint() }
        );

        context.MapRoute(
            name: "AccountArea",
            url: "Area/{accountFriendlyId}/{controller}/{action}",
            defaults: new
                {
                    controller = "Home",
                    action = "Dashboard",
                    accountFriendlyId = RouteParameter.Optional,
                    id = UrlParameter.Optional
                },
            constraints: new { accountFriendlyId = new ControllerNameConstraint() }
            );

        context.MapRoute(
        name: "Area",
        url: "Area/{controller}/{action}",
        defaults: new
            {
                controller = "Home",
                action = "Dashboard"
            }
        );
    }

并设置这样的约束(也可以称为约束NotControllerNameContraint):

public class ControllerNameConstraint : IRouteConstraint
{
    private static List<Type> GetSubClasses<T>()
    {
        return Assembly.GetCallingAssembly().GetTypes().Where(
            type => type.IsSubclassOf(typeof(T))).ToList();
    }

    public List<string> GetControllerNames()
    {
        List<string> controllerNames = new List<string>();
        GetSubClasses<Controller>().ForEach(
            type => controllerNames.Add(type.Name));
        return controllerNames;
    }
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (values.ContainsKey(parameterName))
        {
            string stringValue = values[parameterName] as string;
            return !GetControllerNames().Contains(stringValue + "Controller");
        }

        return true;
    }
}

学分:https ://stackoverflow.com/a/1152735/938472

于 2012-05-03T20:36:44.077 回答
2

这是一个 URL 空间问题。你如何区分 accountFriendlyId、campaignFriendlyId 和 controller ?最简单的方法是将它们放在 URL 的不同段中,但是对于您的路由,控制器可以是第二段、第三段或第四段。您必须使用约束来消除歧义,并像这样对它们进行排序:

context.MapRoute(null, "Area/{controller}/{action}",
   new { controller = "Home", action = "Dashboard" },
   new { controller = "Foo|Bar" });

context.MapRoute(null, "Area/{accountFriendlyId}/{controller}/{action}",
   new { controller = "Home", action = "Dashboard" },
   new { controller = "Foo|Bar" });

context.MapRoute(null, "Area/{accountFriendlyId}/{campaignFriendlyId}/{controller}/{action}",
   new { controller = "Home", action = "Dashboard" });

您建议的想法,如果找不到控制器,然后尝试下一个匹配的路由,它不会那样工作,一旦路由匹配,您将不得不修改它UrlRoutingModule以尝试使其工作。

于 2012-05-03T05:04:23.270 回答