使用属性和约定路由

时间:2016-05-24 07:26:46

标签: c# asp.net-mvc asp.net-mvc-5 asp.net-mvc-routing

有没有办法一起使用约定和属性路由? 我想在定义属性路由时使用方法和控制器的真实名称调用action方法。

映射方法在启动时调用:

public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.MapMvcAttributeRoutes();///
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

这是控制器:

[RoutePrefix("d")]
[Route("{action=index}")]
public class DefaultController : Controller
{
    [Route]
    public ActionResult Index()
    {
        return View();
    }

    [Route("f")]
    public ActionResult Foo()
    {
        return View();
    }
}

我可以使用/d/f网址访问Foo操作方法。但是当我尝试这个url:/Default/Foo时,会发生404错误。实际上,它会抛出未找到的动作异常,就像A public action method 'Foo' was not found on controller 'Namespace...DefaultController'.

那样

我检查了asp.net mvc的源代码,我看到了这些行:

if (controllerContext.RouteData.HasDirectRouteMatch())
{
    ////////
}
else
{
    ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
    return actionDescriptor;
}

它检查是否存在直接路由,/Default/Foo路由不是直接路由,因此它应该作为在启动时注册为{controller}/{action}/{id}的约定路由。但它没有找到controllerDescriptor.FindAction方法的动作,它会抛出异常。

这是一个错误还是我不能同时使用两种路由方法?或者是否有任何解决方法可以同时使用它们?

修改

我调试了mvc源代码,我看到了这些行:

namespace System.Web.Mvc
{
    // Common base class for Async and Sync action selectors
    internal abstract class ActionMethodSelectorBase
    {
        private StandardRouteActionMethodCache _standardRouteCache;

        protected void Initialize(Type controllerType)
        {
            ControllerType = controllerType;

            var allMethods = ControllerType.GetMethods(BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public);
            ActionMethods = Array.FindAll(allMethods, IsValidActionMethod);

            // The attribute routing mapper will remove methods from this set as they are mapped.
            // The lookup tables are initialized lazily to ensure that direct routing's changes are respected.
            StandardRouteMethods = new HashSet<MethodInfo>(ActionMethods);
        }

关于属性路由的最后评论解释了为什么会出现此问题。当您致电StandardRouteMethods时,属性路由会移除MapMvcAttributeRoutes

我还在寻求解决方法。

1 个答案:

答案 0 :(得分:0)

  

我想在定义属性路由时使用方法和控制器的真实名称调用action方法。

如果你想要的只是调用知道控制器和动作名称的应用程序,你似乎走错了方向。如果您拥有控制器和操作的名称(区域和其他路由值),则可以使用它们来轻松使用URL。

var url = Url.Action("Index", "Default");
// returns /d/f

如果这适用于您的使用,那么您根本不必拥有一组重复的路由映射。

  

注意:为同一页面创建2个网址并非SEO友好(除非您使用canonical tag)。事实上,关于SO的许多问题都是关于从路由表中删除重复路由。看起来他们通过删除重复的路线帮助了我们所有人,所以我们不必手动忽略它们。

替代

一种可能的解决方法是向操作方法添加2个路由属性(我不相信可以在不从控制器中删除RoutePrefix的情况下完成)。

[Route("d/f")]
[Route("Default/Foo")]
public ActionResult Foo()
{
    return View();
}

另一种可能的解决方法 - 不要为全部或部分应用程序使用属性路由。属性路由仅支持基于约定的路由功能的子集,但在某些特定方案中很有用。这似乎不是其中一种情况。