2009-10-25 36 views
1

我的ASP.NET MVC應用程序有一個場景,用戶輸入可以直接影響對RedirectToAction()的調用目標(通過字符串),並有機會如果不正確的輸入導致他們請求不存在的操作,用戶可能會創建運行時錯誤。我想直接防止這個問題,但我希望儘可能以最少的方式這樣做,因爲它必須在大量請求中完成。這就是說,反射將是一個可行的解決方案,用來確認/ Controller/ActionName實際存在,但反射是一個非常繁重的操作。ASP.NET MVC - 驗證路由的存在

什麼是確認ASP.NET MVC應用程序中的給定Url事實上連接到控制器操作的最佳方式?

回答

0

我最終選擇的路線是反射和包含存儲在Application []中的相關控制器中所有有效操作的字典。通過檢查方法的ReturnType並驗證它是(或派生自)ActionResult並且它不是Private來確定有效的Action。我可以做更多的檢查,但現在已經足夠了。

public static bool MethodIsAction(MethodInfo method) 
{ 
    if (method == null) 
     throw new ArgumentNullException("Invalid Parameter: method cannot be null."); 

    if (method.ReturnType != typeof(ActionResult) && method.ReturnType.BaseType != typeof(ActionResult)) 
     return false; 

    if (method.IsPrivate) 
     return false; 

    return true; 
} 

行動的字典是建立與內部的Application_Start下面的方法:

public static Dictionary<string, MethodInfo> GetActionDictionary(Type controller) 
{ 
    Dictionary<string, MethodInfo> dict = null; 

    var methods = controller.GetMethods().Where(MethodIsAction); 
    if (methods.Any()) 
    { 
     dict = new Dictionary<string, MethodInfo>(StringComparer.OrdinalIgnoreCase); 
     foreach (var action in methods) 
      dict.Add(action.Name, action); 
    } 
    return dict; 
} 

當用戶請求一個合格的動作,我只是在字典點動作的名稱,如果一個MethodInfo的存在對於行動名稱我調用它。雖然它仍然需要反思,但至少應該進行優化,以便在應用程序運行時只發生一次。

2

這樣做的一種方法是獲得用戶輸入數據的允許值列表。例如,如果用戶輸入了她最喜歡的顏色:

// userColour = the user set colour 
var allowableColours = new [] { "Red", "Blue", "Green" }; 
if (!allowableColours.Contains(userColour)) 
{ 
    // Set to a default colour. 
    userColour = "Red"; 
} 

return RedirectToAction(userColour, "Colour"); 

雖然沒有動態的看路由表,這將是快,你可以相信,他們的用戶沒有輸入一些惡意的價值,這是擰上你的路由。

+0

不幸的是,這個選項對於我的場景來說並不是真的可行,因爲路由決策是如何實現的。儘管如此,這確實給了我一個處理潛在問題的另一種方法。如果我預先防止了路由錯誤的可能性,那麼我至少可以部分控制手頭的問題。 – 2009-10-25 17:50:38

1

快速和更粗的選擇是剛打的URL,下面的代碼可以幫助你快速測試的東西,

注意:你實際上打你的網站,是什麼知道意味着你的應用程序。

這對我們診斷某些集成測試中的某些環境問題很有幫助。

var urlToExec = "http://yoursite.com/" + controllerAndAction; 

var wr = (HttpWebRequest) WebRequest.Create(urlToExec); 

try 
{ 
    var resp = (HttpWebResponse)wr.GetResponse(); 

    if (resp.StatusCode != HttpStatusCode.OK || resp.StatusCode == HttpStatusCode.NotFound) 
     //it was found 

} 
catch (Exception ex) 
{ 
    //404 or other http error 
    //404 and the like result in GetResponse() throwing an exception 
    //this was verified by having actions return via: 
    //'return new HttpNotFoundResult("This doesn't exist");' 
}