Как мне вернуть статус 404, когда недопустимые параметры передаются на мой MVC-контроллер ASP.NET? - программирование
Подтвердить что ты не робот

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

Я хочу вернуть HTTP-статус 404, если неверные аргументы передаются моему контроллеру. Например, если у меня есть контроллер, который выглядит так:

public ActionResult GetAccount(int id)
{
   ...
}

Затем я хочу вернуть 404, если говорят, что такие URL-адреса встречаются:

/GetAccount
/GetAccount/notanumber

то есть. Я хочу захватить ArgumentException, который был брошен.

Я знаю, что могу использовать тип с нулевым значением:

public ActionResult GetAccount(int? id)
{
  if(id == null) throw new HttpException(404, "Not found");
}

Но это довольно нехорошее и повторяющееся.

Я надеялся, что смогу добавить это к моим контроллерам там, где это необходимо:

[HandleError(View="Error404", ExceptionType = typeof(ArgumentException))]
public class AccountsController : Controller
{
  public ActionResult GetAccount(int id)
  {
    ...
  }
}

Но это не работает хорошо.

Я видел этот пост и этот ответ, который почти решает мою проблему:

В этом ответе создается абстрактный BaseController, из которого вы выводите все остальные контроллеры из:

public abstract class MyController : Controller
{
    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        // If controller is ErrorController dont 'nest' exceptions
        if (this.GetType() != typeof(ErrorController))
            this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

Это отлично работает при обработке неизвестных действий с помощью 404, но не позволяет обрабатывать недопустимые данные как 404.

Можно ли безопасно переопределить Controller.OnException(ExceptionContext filterContext) следующим образом:

protected override void OnException(ExceptionContext filterContext)
{
  if(filterContext.Exception.GetType() == typeof(ArgumentException))
  {
    filterContext.ExceptionHandled = true;
    this.InvokeHttp404(filterContext.HttpContext);
  }
  else
  {
    base.OnException(filterContext);
  }
}

На первый взгляд кажется, что это работает, но я сохраняю какие-либо проблемы, делая это?

Это семантически правильная вещь?

4b9b3361

Ответ 1

Лучший способ? Атрибут выбора метода действий!

Чтобы фактически избежать аргументов метода с нулевым значением, я предлагаю вам написать атрибут Action Method Selector, который фактически будет соответствовать вашему методу действий, когда id в комплект поставки. Он не будет говорить, что аргумент не был предоставлен, но он не может соответствовать любым методам действий для данного запроса.

Я бы назвал этот селектор действий RequireRouteValuesAttribute и будет работать следующим образом:

[RequireRouteValues("id")]
public ActionResult GetAccount(int id)
{
    ...
}

Почему это лучшее решение для вашей проблемы?

Если вы посмотрите на свой код, вы хотели бы вернуть 404 на действия, которые соответствуют имени, но сбой привязки к параметрам (либо потому, что он не был предоставлен, либо по какой-либо другой причине). Ваше действие, так сказать требует конкретного параметра действия, в противном случае возвращается 404.

Поэтому, добавляя атрибут селектора действий, добавляется требование к действию, поэтому он должен соответствовать имени (это задается MVC), а также требует определенных параметров действия. Всякий раз, когда id не поставляется, это действие не сопоставляется. Если другое действие, которое соответствует, не является проблемой, потому что это конкретное действие будет выполнено. Главное. Действие не соответствует неверному запросу маршрута, и вместо него возвращается значение 404.

Там код приложения для этого!

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

Ответ 2

Отказ от ответственности: это не распространяется на все случаи

Для URL-адресов в ваших примерах возвращение 404 может выполняться в одной строке. Просто добавьте ограничение маршрута для параметра id.

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index" }, // Parameter defaults
    new { id = @"\d+" } // restrict id to be required and numeric
);

И это все. Теперь любой соответствующий URL-адрес, который не имеет id или id, не является числовым, автоматически запускает не найденную ошибку (для которой существует множество способов обращения, один в вашем примере, другой с помощью пользовательских HandleErrorAttribute и т.д.). И вы можете использовать недействительные параметры int для своих действий.

Ответ 3

Мне удалось получить эту работу, добавив этот маршрут в конце всех маршрутов:

routes.MapRoute("CatchAllErrors", "{*url}",
    new { controller = "Error", action = "NotFound" }
);

Примечание. Сначала я последовал за этим: Как я могу правильно обрабатывать 404 в ASP.NET MVC?