2012-11-16 59 views
3

作爲this question的後續,我試圖實現自定義路由約束,以動態修改特定路由的RouteValueDictionary動態修改RouteValueDictionary

我95%的方式:我可以匹配任何路線基於提供的參數模式匹配在URL中指定的操作。此過程的最後一步是重寫RouteValueDictionary以將鍵重命名爲控制器操作的適當參數。

這裏是我的代碼的相關片段(整個班級幾乎是300線,所以我不希望添加所有的,但如果需要的話我):

public class CustomRouteConstraint : IRouteConstraint 
{ 
    public bool Match(HttpContextBase httpContext, Route route, string paramName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
     if (routeDirection.Equals(RouteDirection.UrlGeneration)) { 
      return false; 
     } 

     //this will grab all of the "actual" parameters out of the RVD, excluding action and controller 
     Dictionary<string, object> unMappedList = values.Where(x => x.Key.Contains("param")).OrderBy(xi => xi.Key).ToDictionary(
      kvp => kvp.Key, kvp => kvp.Value); 

     string controller = values["controller"] as string; 
     string action = values["action"] as string; 

     //this method tries to find the controller using reflection 
     Type cont = TryFindController(controller); 

     if (cont != null) { 
      MethodInfo actionMethod = cont.GetMethod(action); 

      if (actionMethod != null) { 
       ParameterInfo[] methodParameters = actionMethod.GetParameters(); 

       //this method validates that the parameters of the action that was found match the expected parameters passed in the custom constraint; it also performs type conversion 
       if (validateParameters(methodParameters, unMappedList)) { 
        for (int i = 0; i < methodParameters.Length; i++) { 
         values.First(x => x.Key == unMappedList.ElementAt(i).Key).Key = methodParameters.ElementAt(i).Name; 
         //above doesn't work, but even if it did it wouldn't do the right thing 

         return true; 
        } 
       } 
      } 
     } 

     return false; 
    } 
} 

這裏就是我如何使用自定義的約束:

routes.MapRoute(
    name: "Default2", 
    url: "{controller}/{action}/{param1}-{param2}", 
    defaults: new { controller = "Admin", action = "Index" }, 
    constraints: new { lang = new CustomRouteConstraint(new RoutePatternCollection(new List<ParamType> { ParamType.INT, ParamType.INT })) } 
); 

(什麼我傳遞到構造基本上是說「參數模式是尋找兩個整數」所以,當Match方法被調用,它將如果動作返回true。在url中指定有兩個兩個整數參數,無論o f實際參數名稱。)

那麼,有沒有一種方法可以覆蓋RouteValueDictionary的這個請求?或者有沒有其他方法可以做到這一點,我錯過了?

+1

不是ASP的專家。NET MVC,但我不知道路由字典是否是共享資源,無論是C#中的static或VB.NET中的Shared?如果是這樣,那麼當您修改它時,您可能需要使用鎖定,因爲其他請求可能會在您更改它的同時嘗試讀取它。 –

回答

3

如果我理解正確的是這樣一個問題:

那麼,有沒有一種方法,我可以覆蓋RouteValueDictionary此 要求?或者有沒有其他方法可以做到這一點,我錯過了?

我已經採取的解決方案,改變了這些線路更換參數名:

for (int i = 0; i < methodParameters.Length; i++) 
{ 
    // I. instead of this 

    //values.First(x => x.Key == unMappedList.ElementAt(i).Key) 
    // .Key = methodParameters.ElementAt(i).Name; 
    //above doesn't work, but even if it did it wouldn't do the right thing 

    // II. do this (not so elegant but working;) 
    var key = unMappedList.ElementAt(i).Key; 
    var value = values[key]; 
    values.Remove(key); 
    values.Add(methodParameters.ElementAt(i).Name, value); 

    // III. THIS is essential! if statement must be moved after the for loop 
    //return true; 
} 
return true; // here we can return true 

注:我喜歡你的方法。有時候,擴展/調整路由,然後轉到代碼並「修復不正確的參數名稱」更重要。當然,他們很可能不是不正確的。

這裏是分離關注的力量。

  • Url地址是一個地方。
  • 控制器,動作和參數名稱另一個。
  • 和路由具有強大的自定義...

...是唯一的正確的地方來處理。這是關心的分離。不調整動作名稱來服務Url ...

+0

啊......我不知道這是那麼簡單!我收到的錯誤是「收集只讀」,所以我認爲任何修改都行不通=顯然是一個錯誤的假設。無論如何,它的功能就像一個魅力 - 我會在我的另一個問題上將整個代碼發佈到我的解決方案。謝謝你的幫助! – Mansfield

1

您可以輕鬆地限制參數,以正整數使用正則表達式:

private const string IdRouteConstraint = @"^\d+$"; 

routes.MapRoute(
    name: "Default2", 
    url: "{controller}/{action}/{param1}-{param2}", 
    defaults: new { controller = "Admin", action = "Index" }, 
    constraints: new { param1 = IdRouteConstraint, param2 = IdRouteConstraint}); 

正如我在回答說你earlier question,你不應該擔心在控制器操作的參數名稱。給那些過於有意義的名字會把你打結。