ASP .NET MVC 5.2 继承路由:发现多个控制器类型匹配 URL

ASP .NET MVC 5.2 Inherited Route: Multiple controller types were found that match the URL

我正在尝试使用具有 [InheritedRoute] 属性的基础控制器。基础 class 和控制器是这样创建的:

[InheritedRoute("app/{controller}/{action=index}/{id?}")]
public abstract class MyBaseController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

public class DefaultController : MyBaseController { }

public class KyleController : MyBaseController { }

[RoutePrefix("app/support")]
[Route("{action=Index}/{id?}")]
public class SupportController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

InheritedRouteAttribute class 和东西:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class InheritedRouteAttribute : Attribute, IDirectRouteFactory
{
    public string Name { get; set; }
    public int Order { get; set; }
    public string Template { get; }

    public InheritedRouteAttribute(string template)
    {
        this.Template = template;
    }

    public RouteEntry CreateRoute(DirectRouteFactoryContext context)
    {
        var controllerDescriptor = context.Actions.First().ControllerDescriptor;
        var controllerName = controllerDescriptor.ControllerName;
        string template;
        if (string.Equals(controllerName, "Default", StringComparison.OrdinalIgnoreCase))
        {
            template = this.Template.Replace("{controller}/", string.Empty);
        }
        else
        {
            template = this.Template.Replace("{controller}", controllerName);
        }

        IDirectRouteBuilder builder = context.CreateBuilder(template);
        builder.Name = this.Name ?? controllerName + "_Route";
        builder.Order = this.Order;

        return builder.Build();
    }
}

public class InheritedDirectRouteProvider : DefaultDirectRouteProvider
{
    protected override IReadOnlyList<IDirectRouteFactory> GetControllerRouteFactories(ControllerDescriptor controllerDescriptor)
    {
        return controllerDescriptor.GetCustomAttributes(typeof(IDirectRouteFactory), true).Cast<IDirectRouteFactory>().ToArray();
    }
}

在我的 RouteConfig.cs 中,我没有使用常规路线:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.MapMvcAttributeRoutes(new InheritedDirectRouteProvider());
}

本质上,我想做的是,如果用户在 DefaultController 中,单词 "Default" 会从 URL 中删除;否则,使用标准约定,前缀为 "app"。如果我删除默认值(通过删除 {controller}/),那么每当我转到另一个 URL 时,我都会收到 Multiple controller types 错误。但是,如果我离开它,一切都很好,除了 URL 不是我想要的。

我正在查看 RouteDebugger 并查看注册为我的路由的内容,我看到(如我所料):

我错过了什么?为什么它认为我有一条重复的路线,特别是在 SupportControllerDefaultController 上?

让我们看看这两个路由模板:

  • app/support/{action=Index}/{id?}
  • 应用程序/{action=index}/{id?}

如果您访问 app/support,它们将匹配:

  • app/support/{action=Index}/{id?} - 动作默认为 'Index',缺少 id(可选)。
  • app/{action=index}/{id?} - 操作是 'support' (!),缺少 id(可选)。

如果您访问 app/support/something:

,两条路线也匹配
  • app/support/{action=Index}/{id?} - 操作是 'something',缺少 id(可选)。
  • app/{action=index}/{id?} - 操作是 'support',id 是 'something'。

因此 'app/support' 下具有 2 或 3 个路段的任何 url 都将匹配两条路线。

现在,当您了解会发生什么时,您可能可以自己找出解决方法。最简单的解决方法可能是让这些路由匹配不同数量的路段。可能的选择是删除两个路由的默认操作并删除可选的 id 参数:

  • app/support/{动作}
  • 应用程序/{操作}

选择满足您要求的解决方案。但是请确保来自一条路线的 'support' 段与您当前路线中来自另一条路线的动作部分不匹配。