同时使用属性路由和约定路由 [英] Using Both of Attribute and Convention Routing

查看:148
本文介绍了同时使用属性路由和约定路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以同时使用约定和属性路由? 定义属性路由时,我想使用方法和控制器的真实名称来调用操作方法.

Is there a way to use Convention and Attribute Routing together? I want to call an action method with the real name of method and controller when I defined the attribute routing.

映射方法在启动时调用:

The mapping method is calling at startup:

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'.

I can reach to Foo action method with /d/f url. But when I try this url: /Default/Foo, the 404 error occurs. Actually it throws the action not found exception which it says like A public action method 'Foo' was not found on controller 'Namespace...DefaultController'.

我检查了asp.net mvc的源代码,并且看到了以下几行:

I checked the source code of asp.net mvc and I saw these lines:

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

它检查是否存在直接路由,而/Default/Foo路由不是直接路由,因此它应充当约定路由,并在启动时注册为{controller}/{action}/{id}.但是它没有通过controllerDescriptor.FindAction方法找到动作,并且抛出了异常.

It checks if there is a direct route or not, which the /Default/Foo route is not a direct route so it should act as convention routing which is registered at startup as {controller}/{action}/{id}. But it doesn't find the action with controllerDescriptor.FindAction method and it throws the exception.

这是错误还是不能同时使用两种路由方法?还是有两种方法都可以使用?

Is this a bug or cant I use both routing methods together? Or are there any workaround to use both?

我调试了mvc源代码,并且看到了以下几行:

I debugged into mvc source code, and I saw these lines:

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);
        }

有关属性路由的最后一条注释说明了为什么会发生此问题.调用MapMvcAttributeRoutes时,属性路由将删除StandardRouteMethods.

The last comments about attribute routing explains why this problem happens. The Attribute routing removes StandardRouteMethods when you call MapMvcAttributeRoutes.

我仍在寻找解决方法.

推荐答案

在定义属性路由时,我想使用方法和控制器的真实名称来调用操作方法.

I want to call an action method with the real name of method and controller when I defined the attribute routing.

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

It seems like you are going pretty far in the wrong direction if all you want is to call the application knowing the controller and action names. If you have the name of the controller and action (area and other route values) you can use them to get the URL to use quite easily.

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

如果这适合您的使用,那么您根本不需要重复的一组路由映射.

If this works for your usage, then you don't have to have a duplicate set of route mappings at all.

注意::创建2个指向同一页面的URL不适合SEO(除非您使用

NOTE: Creating 2 URLs to the same page is not SEO friendly (unless you use the canonical tag). In fact, many question here on SO are about removing the duplicate routes from the route table. It seems like they did us all a favor by removing the duplicate routes so we don't have to ignore them all manually.

替代项

一种可能的解决方法是将2个路由属性添加到操作方法中(我认为不将RoutePrefix从控制器中移除就无法实现.)

Alternatives

One possible workaround is to add 2 route attributes to the action method (I don't believe it can be done without removing the RoutePrefix from the controller).

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

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

Another possible workaround - don't use attribute routing for all or part of your application. Attribute routing only supports a subset of convention-based routing features, but is useful in some specific scenarios. This does not appear to be one of those scenarios.

这篇关于同时使用属性路由和约定路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆