【问题标题】:Using Both of Attribute and Convention Routing同时使用属性和约定路由
【发布时间】:2016-05-24 07:26:46
【问题描述】:

有没有办法同时使用约定和属性路由? 我想在定义属性路由的时候,用方法和控制器的真实名称调用一个动作方法。

映射方法在启动时调用:

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 url 访问 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);
        }

关于属性路由的最后一个 cmets 解释了为什么会出现这个问题。当您调用MapMvcAttributeRoutes 时,属性路由会删除StandardRouteMethods

我仍在寻找解决方法。

【问题讨论】:

  • 你找到解决办法了吗?

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


【解决方案1】:

我想在定义属性路由的时候用方法和控制器的真实名称调用一个动作方法。

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

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

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

注意:创建 2 个指向同一页面的 URL 对 SEO 不友好(除非您使用 canonical tag)。事实上,这里关于 SO 的许多问题都是关于从路由表中删除重复的路由。似乎他们通过删除重复的路线为我们所有人提供了帮助,因此我们不必手动忽略它们。

替代方案

一种可能的解决方法是向操作方法添加 2 个路由属性(我认为如果不从控制器中删除 RoutePrefix 就无法做到)。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-11
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 1970-01-01
    • 1970-01-01
    • 2013-06-11
    相关资源
    最近更新 更多