ASP .NET MVC 5.2继承路由:找到了与URL匹配的多个控制器类型

时间:2018-02-12 05:32:21

标签: asp.net-mvc asp.net-mvc-5 routes asp.net-mvc-5.2 attributerouting

我尝试使用具有[InheritedRoute]属性的基本控制器。基类和控制器的创建方式如下:

[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类和东西:

[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中,则单词&#34;默认&#34;被删除的URL;否则,请使用标准惯例,前缀为&#34; app&#34;。如果我删除默认值(通过取出{controller} /),那么每当我转到另一个URL时,我都会收到多个控制器类型错误。但是,如果我离开它,一切都很好,除了URL不是我想要的。

我正在看RouteDebugger并看到注册的路线是什么,我看到了(正如我所料):

  • 应用程序/凯尔/ {动作} / {ID}
  • 应用程序/支持/ {行动} / {ID}
  • 应用程序/ {动作} / {ID}

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

1 个答案:

答案 0 :(得分:1)

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

  • 应用程序/支持/ {行动=索引} / {ID?}
  • 应用程序/ {行动=索引} / {ID?}

如果您访问app/support,则两者都匹配:

  • app / support / {action = Index} / {id?} - 默认情况下,操作为“索引”,ID丢失(可选)。
  • app / {action = index} / {id?} - 操作是'支持'(!),ID丢失(可选)。

如果您访问app/support/something

,这两条路线也会匹配
  • app / support / {action = Index} / {id?} - 操作是'某事',ID丢失(可选)。
  • app / {action = index} / {id?} - 操作是'支持',ID是'某事'。

因此,具有2个或3个细分的“app / support”下的任何网址都会匹配这两个网址。

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

  • 应用程序/支持/ {动作}
  • 应用程序/ {动作}

选择满足您要求的解决方案。但请确保一条路线的“支持”段与当前路线中的另一条路线的行动部分不匹配。