同时使用属性路由和约定路由 [英] Using Both of Attribute and Convention Routing
问题描述
是否可以同时使用约定和属性路由? 定义属性路由时,我想使用方法和控制器的真实名称来调用操作方法.
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.
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屋!