ASP.NET MVC - проверка существования маршрута

В моем приложении ASP.NET MVC есть сценарий, в котором пользовательский ввод может напрямую влиять на цель вызова RedirectToAction () (посредством строки), и есть вероятность, что пользователь может создать ошибку времени выполнения, если неправильный ввод приводит им, чтобы запросить действие, которого не существует. Я хотел бы полностью предотвратить эту проблему, но я хотел бы сделать это с наименьшими затратами, поскольку это должно выполняться при большом количестве запросов. При этом отражение было бы жизнеспособным решением для подтверждения того, что / Controller / ActionName действительно существует, но отражение - довольно сложная операция.

Как лучше всего подтвердить, что данный URL-адрес в приложении ASP.NET MVC действительно связан с действием контроллера?


person Nathan Taylor    schedule 25.10.2009    source источник


Ответы (3)


Один из способов сделать это - иметь список допустимых значений для вводимых пользователем данных. Например, если пользователь ввел свой любимый цвет:

// 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");

Хотя это не так динамично, как просмотр таблицы маршрутизации, это будет быстро, и вы можете быть уверены, что пользователь не вводил какое-то злонамеренное значение, которое мешало вашей маршрутизации.

person cdmckay    schedule 25.10.2009
comment
К сожалению, этот вариант не подходит для моего сценария из-за того, как принимается решение о маршрутизации. Хотя это дает мне представление о другом способе решения потенциальной проблемы. Если я упреждающе предотвращу возможность ошибки маршрутизации, я смогу хотя бы частично решить проблему. - person Nathan Taylor; 25.10.2009

Быстрый и более грубый вариант - просто нажать на 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");'
}
person Nick Josevski    schedule 08.01.2012

Маршрут, который я выбрал здесь, - это отражение и Словарь, содержащий все допустимые действия в соответствующем Контроллере, который хранится в Application []. Допустимое действие определяется путем проверки ReturnType метода и подтверждения того, что он является (или является производным от) ActionResult и не является частным. Я мог бы сделать еще несколько проверок, но пока этого достаточно.

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, я вызываю его. Хотя он все еще требует отражения, он, по крайней мере, оптимизирован так, чтобы это происходило только один раз во время работы приложения.

person Nathan Taylor    schedule 29.10.2009