使用属性和约定路由
Using Both of Attribute and Convention 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
url 访问 Foo 操作方法。但是当我尝试 url: /Default/Foo
时,会出现 404 错误。实际上它会抛出 action not found 异常,它表示 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);
}
关于属性路由的最后评论解释了为什么会出现这个问题。当您调用 MapMvcAttributeRoutes
时,属性路由会删除 StandardRouteMethods
。
我仍在寻找解决方法。
I want to call an action method with the real name of method and controller when I defined the attribute routing.
如果您只想调用知道控制器和动作名称的应用程序,那么您似乎在错误的方向上走得太远了。如果您有控制器的名称和操作(区域和其他路线值),您可以使用它们来轻松使用 URL。
var url = Url.Action("Index", "Default");
// returns /d/f
如果这适合您的使用,那么您根本不需要重复的一组路由映射。
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
就无法完成)。
[Route("d/f")]
[Route("Default/Foo")]
public ActionResult Foo()
{
return View();
}
另一种可能的解决方法 - 不要对应用程序的全部或部分使用属性路由。属性路由仅支持基于约定的路由功能的一个子集,但在某些特定场景下很有用。这似乎不是其中一种情况。
有没有办法同时使用约定和属性路由? 我想在定义属性路由的时候调用一个方法和控制器真实名称的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
url 访问 Foo 操作方法。但是当我尝试 url: /Default/Foo
时,会出现 404 错误。实际上它会抛出 action not found 异常,它表示 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);
}
关于属性路由的最后评论解释了为什么会出现这个问题。当您调用 MapMvcAttributeRoutes
时,属性路由会删除 StandardRouteMethods
。
我仍在寻找解决方法。
I want to call an action method with the real name of method and controller when I defined the attribute routing.
如果您只想调用知道控制器和动作名称的应用程序,那么您似乎在错误的方向上走得太远了。如果您有控制器的名称和操作(区域和其他路线值),您可以使用它们来轻松使用 URL。
var url = Url.Action("Index", "Default");
// returns /d/f
如果这适合您的使用,那么您根本不需要重复的一组路由映射。
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
就无法完成)。
[Route("d/f")]
[Route("Default/Foo")]
public ActionResult Foo()
{
return View();
}
另一种可能的解决方法 - 不要对应用程序的全部或部分使用属性路由。属性路由仅支持基于约定的路由功能的一个子集,但在某些特定场景下很有用。这似乎不是其中一种情况。