有没有办法一起使用约定和属性路由? 我想在定义属性路由时使用方法和控制器的真实名称调用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
。
我还在寻求解决方法。
答案 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();
}
另一种可能的解决方法 - 不要为全部或部分应用程序使用属性路由。属性路由仅支持基于约定的路由功能的子集,但在某些特定方案中很有用。这似乎不是其中一种情况。