ASP.NET MVC - 验证路由的存在性

时间:2009-10-25 15:44:03

标签: asp.net asp.net-mvc error-handling routing

我的ASP.NET MVC应用程序有一个场景,用户输入可以直接影响对RedirectToAction()的调用目标(通过字符串),如果用户有可能创建运行时错误,不正确的输入导致他们请求不存在的动作。我想彻底防止这个问题,但我想以最少的方式这样做,因为它必须在大量的请求上完成。话虽这么说,反射将是一个可行的解决方案,用于确认/ Controller / ActionName实际存在,但反射是一个非常繁重的操作。

确认ASP.NET MVC应用程序中的给定Url实际连接到控制器操作的最佳方法是什么?

3 个答案:

答案 0 :(得分: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");

虽然没有像查看路由表那样动态,但速度很快,您可以确信用户没有输入一些与您的路由相关的恶意值。

答案 1 :(得分:1)

快速而粗略的选择就是点击网址,以下代码可以帮助您快速测试一些内容,

  

注意:您实际上已经访问了自己的网站并了解了解您的应用程序的含义。

这有助于我们在某些集成测试中诊断某些环境问题。

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");'
}

答案 2 :(得分: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,则调用它。虽然它仍然需要反射,但它至少是经过优化的,因此在应用程序运行时它只会发生一次。