2013-02-28 45 views
5

我目前工作的一個asp.net的MVC 4應用程序,我有以下類型的URL的需要:ASP.NET MVC 4路線的用戶名/行動問題

的網址需要路由

  1. http://www.mysite.com/foo/user1 < ------- {用戶名}
  2. http://www.mysite.com/foo/edit
  3. http://www.mysite.com/foo/delete/1
  4. http://www.mysite.com/bar/user1 < ------- {用戶名}
  5. http://www.mysite.com/bar/edit
  6. http://www.mysite.com/bar/delete/1

我遇到的問題是,目前{用戶名}被作爲動作這麼處理解決這個問題我實現了以下路線,但是這意味着每次我想實施一個新的操作或者需要一個需要{username}的控制器時,我將不得不更新我的路線:

只有富通路表示

routes.MapRoute("FooSomeAction", "foo/someaction", new { controller = "Food", action = "SomeAction" });    
routes.MapRoute("FooDelete", "foo/delete/{id}", new { controller = "Food", action = "Delete" });    


routes.MapRoute(
    "FooProfile", 
    "foo/{username}", 
    new { controller = "Foo", action = "Index", username = "" } 
); 


// Default route 
routes.MapRoute(
    "Default", // Route name 
    "{controller}/{action}/{id}", 
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
); 

2問題

1)是否有什麼辦法可以實現上面的網址沒有硬編碼的所有路線?

2)處理某人使用的用戶名恰好與控制器或操作名稱相同的用戶名的最佳方式是什麼?

DotnetShadow

+0

據我所知,你的第二個問題是不可能的。在那裏採取行動還有什麼不好? – mattytommo 2013-02-28 12:44:58

+0

在那裏採取行動還有什麼不好? - 對不起,你這是什麼意思? – DotnetShadow 2013-02-28 13:13:00

+0

道歉,如果我含糊不清,我的意思是說你可以讓行動和控制器名稱都出現在鏈接中?像/ User/Edit/User1? – mattytommo 2013-02-28 13:39:22

回答

3

你可以創建一個自定義路由約束如果爲控制器可能採取的行動存在的用戶名,將檢查。如果發現動作匹配,則失敗並將使用默認路由(例如編輯)。出於性能原因,您可能需要緩存該列表,但我會將其保留給您。

private static List<Type> GetSubClasses<T>() 
    { 
     return Assembly.GetCallingAssembly().GetTypes().Where(
      type => type.IsSubclassOf(typeof(T))).ToList(); 
    } 

    public static List<string> GetActionNames(string controllerName) 
    { 
     controllerName = controllerName + "Controller"; 
     var controller = GetSubClasses<Controller>().FirstOrDefault(c => c.Name == controllerName); 

     var names = new List<string>(); 
     if (controller != null) 
     { 
      var methods = controller.GetMethods(BindingFlags.Public | BindingFlags.Instance); 
      foreach (var info in methods) 
      { 
       if (info.ReturnType == typeof(ActionResult)) 
       { 
        names.Add(info.Name); 
       } 
      } 

     } 
     return names; 
    } 


    public class UsernameNotAction : IRouteConstraint 
    { 
     public bool Match 
      (
       HttpContextBase httpContext, 
       Route route, 
       string parameterName, 
       RouteValueDictionary values, 
       RouteDirection routeDirection 
      ) 
     { 
      int i = 0; 
      var username = values["username"]; 
      var actionList = GetActionNames(values["controller"].ToString()); 

      return !actionList.Any(a => a.ToUpper() == username.ToString().ToUpper()); 
     } 
    } 


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

     routes.MapRoute(
      "FooProfile", 
      "{controller}/{username}", 
      new { controller = "Home", action = "Index2", username = "" }, 
      new { IsParameterAction = new UsernameNotAction() } 
     ); 
     // Default route 
     routes.MapRoute(
      "Default", // Route name 
      "{controller}/{action}/{id}", 
      new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
     ); 
    } 
+0

這是一個非常有趣的解決方案。您肯定不希望每次瀏覽時都進行數據庫調用,但他可以在會話中存儲用戶名列表。我不太確定我是否喜歡它,但我會爲原創和一個很酷的想法+1。 – 2013-02-28 13:34:39

+0

好東西馬克,我其實在想着某種約束,但我也擔心表現。感謝替代方法 – DotnetShadow 2013-02-28 13:35:12

+0

它實際上並沒有進行數據庫調用 - 它測試的動作是否在控制器中使用反射(實際上可能會對性能造成更壞的影響,但是誰知道) – 2013-02-28 13:35:34

1

你不能這樣做,除非你路由每一條路線,那不是最好的路線。

有什麼錯誤在其中的操作名稱?

+0

有什麼是錯誤的控制器名稱在它? - 這是什麼意思? – DotnetShadow 2013-02-28 13:12:21

+0

我的意思是操作名稱 這樣做 http://www.mysite.com/bar/user1 這將映射到控制器:酒吧和行動USER1 你想打控制器:巴操作:指數但這不是如何MVC路線工作 你需要做一些事情,如 http://www.mysite.com/bar/ActionName/user1 – 2013-02-28 13:13:40

2

這不是真的你要找的答案,對不起。

1)沒有辦法路由這種方式。除了你所做的之外,沒有什麼可以區分這些路線。我必須質疑爲什麼這是必要的,我相信你有一個很好的理由,但對我來說沒有意義。您仍在使用Index操作,爲什麼不使用/ foo/index/username。我所能想到的是,出於某種原因你無法控制網址。

2)如果使用默認路由,則沒有問題。與您的路由,問題。您唯一真正的選擇是使您的控制器和操作名稱保留字(防止用戶使用數據庫中的這些用戶名創建)。

對不起,我真的不能幫你。

+0

好點關於1)有索引作爲行動,它只是看起來更乾淨有/ foo /用戶名我猜 基本上我的想法是,如果你正在公開查看某人的個人資料,我會: /資料/用戶名 /朋友/用戶名 /畫廊/用戶名 但如果我在自己的個人資料是我只想做 /型材/編輯/ 1 /朋友/列表 /畫廊/刪除/ 1 如果這就說得通了? – DotnetShadow 2013-02-28 13:18:53

+0

我得到你想要做的,但是所有情況下83.57%的默認路由是controller/action/view。如果你想打破這種模式,你就爲自己創造了工作機會,所以只要問問自己是否值得你付出所有的努力。 IMO。 – 2013-02-28 13:21:04

+0

此外,人們不應該通過修改網址來瀏覽您的網站,這些將通過actionlinks等來實現,真的,沒有人看網址或關心它看起來像什麼? http:// mysite/viewusers/index/bob1111 vs http:// mysite/viewusers/bob1111,誰會真的關心? :) – 2013-02-28 13:23:48