Как я могу сопоставить напрямую из моих специфичных для приложения исключений в Http Exceptions?

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

Это выглядит так в нашем коде C#:

// ... more stuff
public Something GetSomething(int id, User currentUser){
    var theSomething = SomethingRepository.Get(id);
    if(theSomething == null){
        throw new SomethingNotFoundException(id, "more details");
    }

    if(!PermissionService.CanLoadSomething(currentUser)){
        throw new NotAuthorizedException("You shall not pass");
    }

    // the rest of the method etc etc
    // ...
}

... где SomethingNotFoundException а также NotAuthorizedException обычай Exception с.

Каким-то образом существует прямое сопоставление между такого рода исключениями и кодом статуса Http (404 Not Found / 403 Forbidden), и мы хотели бы, чтобы наши методы Controller обрабатывали эти ошибки соответствующим образом (показывая страницы CustomError 404/403 и тому подобное), Теперь мы хотим избежать того, чтобы делать это в наших действиях контроллера:

public ViewResult Get(int id){
    try{
        var theSomething = MyService.GetSomething(id, theUser);
    }
    catch(SomethingNotFoundException ex){
        throw new HttpException(404, ex);
    }
    catch(NotAuthorizedExceptionex){
        throw new HttpException(403, ex);
    }
}

Я почти уверен, что должен быть способ использовать либо собственный HandleErrorAttribute, либо собственный ActionFilterAttribute и зарегистрировать его в Global.asax, но я не могу понять, как это работает.

Попытка 1: HandleErrorAttribute

Сначала я попытался создать подкласс HandleErrorAttribute, переопределив OnException метод как таковой:

public override void OnException(ExceptionContext filterContext)
{
    if (filterContext == null)
    {
        throw new ArgumentNullException("filterContext");
    }

    Exception exception = filterContext.Exception;
    // Map some of the Business Exception to correspounding HttpExceptions !
    if (exception is ObjectNotFoundException)
    {
        // consider it as a NotFoundException !
        exception = new HttpException((int)HttpStatusCode.NotFound, "Not found", exception);
        filterContext.Exception = exception;

    }
    else if (exception is NotAuthorizedException)
    {
        // consider it as a ForbiddenException 
        exception = new HttpException((int)HttpStatusCode.Forbidden, "Forbidden", exception);
        filterContext.Exception = exception;
    }

    base.OnException(filterContext);

}

... и добавив его в GlobalFilterCollection в Global.asax ... но он по-прежнему обрабатывается так, как если бы это была обычная ошибка 500, вместо отображения пользовательских страниц ошибок 404/403 ...

Попытка 2: ActionFilterAttribute

Я также попытался сделать это ActionFilterAttribute и переопределяя OnActionExecuted метод как это:

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    if (filterContext == null)
    {
        throw new ArgumentNullException("filterContext");
    }
    Exception exception = filterContext.Exception;
    if(exception!=null)
    {
        // Map some of the Business Exception to correspounding HttpExceptions !
        if (exception is ObjectNotFoundException)
        {
            // consider it as a NotFoundException !
            var wrappingException = new HttpException((int)HttpStatusCode.NotFound, "Not found", exception);
            exception = wrappingException;
            filterContext.Exception = exception;
        }
        else if (exception is NotAuthorizedException)
        {
            // consider it as a ForbiddenException 
            var wrappingException = new HttpException((int)HttpStatusCode.Forbidden, "Forbidden", exception);
            exception = wrappingException;
            filterContext.Exception = exception;
        }
    }

    base.OnActionExecuted(filterContext);
}

... но все равно я получаю страницу с ошибкой 500 вместо 404 или 403 ...

Я делаю что-то неправильно? Возможно, есть лучший способ?

1 ответ

Ну, есть несколько вариантов.

Вы, вероятно, хотите: это решение, ребята

Вы можете сделать это так Этот парень.

Вы можете иметь базовый класс Controller, от которого наследуются все ваши классы, и использовать метод ниже. Вот как моя последняя компания решила эту проблему.

protected override void OnException(ExceptionContext filterContext)
{
       Console.WriteLine(filterContext.Exception.ToString());
}
Другие вопросы по тегам