通过方法属性ASP.NET MVC路由

在StackOverflow Podcast#54中 ,Jeff提到他们通过处理路由的方法上面的一个属性在StackOverflow代码库中注册他们的URL路由。 听起来像一个很好的概念(与Phil Haack提出的有关路线优先权的警告)。

有人可以提供一些样本来实现这个目标吗?

另外,使用这种风格的路由的任何“最佳做法”?

更新 :这已经发布在codeplex上 。 完整的源代码以及预编译的程序集都可以下载。 我还没有时间在网站上发布文档,所以这个SOpost现在就足够了。

更新 :我添加了一些新的属性来处理1)路由sorting,2)路由参数约束,3)路由参数默认值。 下面的文本反映了这个更新。

我实际上已经为我的MVC项目做了这样的事情(我不知道杰夫如何使用stackoverflow)。 我定义了一组自定义属性:UrlRoute,UrlRouteParameterConstraint,UrlRouteParameterDefault。 可以将它们附加到MVC控制器的操作方法,以使路由,约束和默认值自动绑定到它们。

用法示例:

(注意这个例子有点人为,但是它演示了这个function)

public class UsersController : Controller { // Simple path. // Note you can have multiple UrlRoute attributes affixed to same method. [UrlRoute(Path = "users")] public ActionResult Index() { return View(); } // Path with parameter plus constraint on parameter. // You can have multiple constraints. [UrlRoute(Path = "users/{userId}")] [UrlRouteParameterConstraint(Name = "userId", Regex = @"\d+")] public ActionResult UserProfile(int userId) { // ...code omitted return View(); } // Path with Order specified, to ensure it is added before the previous // route. Without this, the "users/admin" URL may match the previous // route before this route is even evaluated. [UrlRoute(Path = "users/admin", Order = -10)] public ActionResult AdminProfile() { // ...code omitted return View(); } // Path with multiple parameters and default value for the last // parameter if its not specified. [UrlRoute(Path = "users/{userId}/posts/{dateRange}")] [UrlRouteParameterConstraint(Name = "userId", Regex = @"\d+")] [UrlRouteParameterDefault(Name = "dateRange", Value = "all")] public ActionResult UserPostsByTag(int userId, string dateRange) { // ...code omitted return View(); } 

UrlRouteAttribute的定义:

 /// <summary> /// Assigns a URL route to an MVC Controller class method. /// </summary> [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class UrlRouteAttribute : Attribute { /// <summary> /// Optional name of the route. If not specified, the route name will /// be set to [controller name].[action name]. /// </summary> public string Name { get; set; } /// <summary> /// Path of the URL route. This is relative to the root of the web site. /// Do not append a "/" prefix. Specify empty string for the root page. /// </summary> public string Path { get; set; } /// <summary> /// Optional order in which to add the route (default is 0). Routes /// with lower order values will be added before those with higher. /// Routes that have the same order value will be added in undefined /// order with respect to each other. /// </summary> public int Order { get; set; } } 

UrlRouteParameterConstraintAttribute的定义:

 /// <summary> /// Assigns a constraint to a route parameter in a UrlRouteAttribute. /// </summary> [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class UrlRouteParameterConstraintAttribute : Attribute { /// <summary> /// Name of the route parameter on which to apply the constraint. /// </summary> public string Name { get; set; } /// <summary> /// Regular expression constraint to test on the route parameter value /// in the URL. /// </summary> public string Regex { get; set; } } 

UrlRouteParameterDefaultAttribute的定义:

 /// <summary> /// Assigns a default value to a route parameter in a UrlRouteAttribute /// if not specified in the URL. /// </summary> [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class UrlRouteParameterDefaultAttribute : Attribute { /// <summary> /// Name of the route parameter for which to supply the default value. /// </summary> public string Name { get; set; } /// <summary> /// Default value to set on the route parameter if not specified in the URL. /// </summary> public object Value { get; set; } } 

对Global.asax.cs的更改:

将调用replace为MapRoute,并对RouteUtility.RegisterUrlRoutesFromAttributes函数进行一次调用:

  public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); RouteUtility.RegisterUrlRoutesFromAttributes(routes); } 

RouteUtility.RegisterUrlRoutesFromAttributes的定义:

完整的源代码是在codeplex上 。 如果您有任何反馈或错误报告,请访问网站。

你也可以尝试AttributeRouting ,它可以从github或nuget获得 。

这是一个无耻的插件,因为我是项目的作者。 但是,如果我不是很高兴使用它。 你可能也是。 github存储库wiki中有大量的文档和示例代码。

有了这个库,你可以做很多事情:

  • 使用GET,POST,PUT和DELETE属性来装饰你的动作。
  • 将多个路线映射到单个操作,使用Order属性对它们进行sorting。
  • 使用属性指定路由默认值和约束。
  • 用一个简单的指定可选参数? 令牌之前的参数名称。
  • 指定支持命名路由的路由名称。
  • 在控制器或基础控制器上定义MVC区域。
  • 使用应用于控制器或基本控制器的路由前缀将您的路由分组或嵌套在一起。
  • 支持传统的url。
  • 在为动作定义的路由,控制器内以及控制器和基础控制器之间设置路由的优先级。
  • 自动生成小写出站url。
  • 定义您自己的自定义路由约定,并将其应用于控制器,以在控制器内为没有样板属性的行为生成path(认为REST风格)。
  • 使用提供的HttpHandler来debugging你的路由。

我确定还有一些我忘记的东西。 一探究竟。 通过nuget安装是无痛的。

注意:截至4/16/12,AttributeRouting还支持新的Web API基础结构。 以防万一你正在寻找可以处理的事情。 感谢subkamran !

1.下载RiaLibrary.Web.dll ,并在您的ASP.NET MVC网站项目中引用它

2.使用[Url]属性对控制器方法进行Decore:

 public SiteController : Controller { [Url("")] public ActionResult Home() { return View(); } [Url("about")] public ActionResult AboutUs() { return View(); } [Url("store/{?category}")] public ActionResult Products(string category = null) { return View(); } } 

顺便说一下,'?' login'{?category}'参数意味着它是可选的。 您不需要在路由默认值中明确指定,这与此相同:

 routes.MapRoute("Store", "store/{category}", new { controller = "Store", action = "Home", category = UrlParameter.Optional }); 

3.更新Global.asax.cs文件

 public class MvcApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoutes(); // This does the trick } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } } 

如何设置默认值和约束? 例:

 public SiteController : Controller { [Url("admin/articles/edit/{id}", Constraints = @"id=\d+")] public ActionResult ArticlesEdit(int id) { return View(); } [Url("articles/{category}/{date}_{title}", Constraints = "date=(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])")] public ActionResult Article(string category, DateTime date, string title) { return View(); } } 

如何设置sorting? 例:

 [Url("forums/{?category}", Order = 2)] public ActionResult Threads(string category) { return View(); } [Url("forums/new", Order = 1)] public ActionResult NewThread() { return View(); } 

这篇文章只是为了扩展DSO的答案。

在将我的路由转换为属性时,我需要处理ActionName属性。 所以在GetRouteParamsFromAttribute:

 ActionNameAttribute anAttr = methodInfo.GetCustomAttributes(typeof(ActionNameAttribute), false) .Cast<ActionNameAttribute>() .SingleOrDefault(); // Add to list of routes. routeParams.Add(new MapRouteParams() { RouteName = routeAttrib.Name, Path = routeAttrib.Path, ControllerName = controllerName, ActionName = (anAttr != null ? anAttr.Name : methodInfo.Name), Order = routeAttrib.Order, Constraints = GetConstraints(methodInfo), Defaults = GetDefaults(methodInfo), }); 

我还发现路线的命名不合适。 该名称是使用controllerName.RouteNamedynamic构build的。 但我的路由名称是控制器类中的常量string,我使用这些常量也调用Url.RouteUrl。 这就是为什么我真的需要属性中的路由名称作为路由的实际名称。

我要做的另一件事是将默认属性和约束属性转换为AttributeTargets.Parameter,以便我可以将它们粘贴到参数中。

我已经将这两种方法结合成了一个Frankensteinian版本,供任何想要的人使用。 (我喜欢可选的参数符号,但也认为它们应该是与默认/约束不同的属性,而不是全部混合成一个)。

http://github.com/djMax/AlienForce/tree/master/Utilities/Web/

我需要使用AsyncController来获取在asp.net mvc 2中工作的ITCloud路由 – 只需编辑源代码中的RouteUtility.cs类并重新编译即可。 您必须从第98行的动作名称中删除“已完成”

 // Add to list of routes. routeParams.Add(new MapRouteParams() { RouteName = String.IsNullOrEmpty(routeAttrib.Name) ? null : routeAttrib.Name, Path = routeAttrib.Path, ControllerName = controllerName, ActionName = methodInfo.Name.Replace("Completed", ""), Order = routeAttrib.Order, Constraints = GetConstraints(methodInfo), Defaults = GetDefaults(methodInfo), ControllerNamespace = controllerClass.Namespace, }); 

然后,在AsyncController中,用熟悉的UrlRouteUrlRouteParameterDefault属性修饰XXXXCompleted ActionResult:

 [UrlRoute(Path = "ActionName/{title}")] [UrlRouteParameterDefault(Name = "title", Value = "latest-post")] public ActionResult ActionNameCompleted(string title) { ... } 

希望能帮助有同样问题的人。