2009-05-21 42 views
80

在Jeff的StackOverflow Podcast #54中,Jeff提到他們通過處理路由的方法上方的屬性在StackOverflow代碼庫中註冊了他們的URL路由。聽起來像一個很好的概念(Phil Haack提出關於路線優先權的警告)。通過方法屬性的ASP.NET MVC路由

有人可以提供一些樣品,使這種情況發生?

此外,使用此類路由的任何「最佳實踐」?

回答

62

UPDATE:這已經張貼在codeplex。完整的源代碼以及預編譯的程序集都可以下載。我還沒有時間在網站上發佈文檔,所以這個SO帖子現在已經足夠了。

更新:我添加了一些新的屬性來處理1)路由排序,2)路由參數約束和3)路由參數默認值。以下文字反映了此更新。

我實際上爲我的MVC項目做了這樣的事情(我不知道Jeff是如何用stackoverflow做的)。我定義了一組自定義屬性:UrlRoute,UrlRouteParameterConstraint,UrlRouteParameterDefault。可以將它們附加到MVC控制器操作方法,以使路由,約束和默認值自動綁定到它們。

實例:

(注意這個例子是人爲但它說明的特徵)UrlRouteAttribute的

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

定義:UrlRouteParameterConstraintAttrib的

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

定義UTE:

/// <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:

替換以圖路線的呼叫,與該RouteUtility一個電話。 RegisterUrlRoutesFromAttributes功能:

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

     RouteUtility.RegisterUrlRoutesFromAttributes(routes); 
    } 

RouteUtility.RegisterUrlRoutesFromAttributes的定義:

完整的源代碼可達上codeplex。如果您有任何反饋或錯誤報告,請轉到該網站。

+0

我想這樣做的屬性可以防止使用路由默認值和路由約束... – 2009-05-22 13:39:20

+0

使用這種方法,我從來不需要默認路由,因爲您將每條路由綁定到特定的方法。你對約束是正確的。我研究了能夠將約束添加爲屬性屬性,但遇到了一個障礙,因爲MVC約束是使用匿名對象指定的,屬性屬性只能是簡單類型。我認爲仍然有可能將約束作爲一個屬性(使用更多的編碼),但是我還沒有打擾它,因爲我到目前爲止還沒有真正需要約束我的MVC工作(我傾向於驗證路由值在控制器中)。 – DSO 2009-05-22 15:53:52

+0

我的意思是默認路徑路徑中的項目,如{username},但我也意識到它們通常是基元。 – 2009-05-22 17:06:27

3

這篇文章只是爲了擴展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.RouteName動態構建的。但我的路由名稱是控制器類中的常量字符串,我使用這些常量也調用Url.RouteUrl。這就是爲什麼我真的需要屬性中的路由名稱作爲路由的實際名稱。

我要做的另一件事是將默認屬性和約束屬性轉換爲AttributeTargets.Parameter,以便我可以將它們粘貼到參數中。

9

1.下載RiaLibrary.Web.dll並用[URL]它引用在你的ASP.NET MVC的網站項目

2. Decoreate控制器方法屬性:

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

順便說一句,「? 「登錄'{?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(); 
    } 
} 

如何設置排序?例如:

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

[Url("forums/new", Order = 1)] 
public ActionResult NewThread() 
{ 
    return View(); 
} 
0

我需要得到ITCloud路由使用AsyncController在asp.net mvc的2個工作 - 這樣做,只是在源編輯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) 
{ 
    ... 
} 

。希望幫助有同樣問題的人。

44

您也可以嘗試AttributeRouting,它可從github或通過nuget獲得。

這是一個無恥的插件,因爲我是項目作者。但是,如果我不是很高興使用它。你可能也是。 github存儲庫wiki中有大量文檔和示例代碼。

有了這個庫,你可以做很多事情:

  • 用GET裝飾你的行動,POST,PUT和DELETE屬性。
  • 將多個路線映射到單個動作,使用Order屬性對它們進行排序。
  • 使用屬性指定路由默認值和約束。
  • 用一個簡單的指定可選參數?令牌之前的參數名稱。
  • 指定支持命名路由的路由名稱。
  • 定義控制器或基礎控制器上的MVC區域。
  • 使用應用於控制器或基礎控制器的路由前綴對您的路線進行分組或嵌套。
  • 支持傳統網址。
  • 在爲動作定義的路由,控制器內以及控制器和基礎控制器之間設置路由的優先級。
  • 自動生成小寫出站網址。
  • 定義您自己的自定義路由約定並將它們應用到控制器上,以在控制器內爲沒有樣板屬性(認爲REST風格)的操作生成路由。
  • 使用提供的HttpHandler調試您的路由。

我確定還有一些我忘記的東西。一探究竟。通過nuget安裝是無痛的。

注意:自4/16/12起,AttributeRouting還支持新的Web API基礎結構。以防萬一你正在尋找可以處理的東西。 Thanks subkamran