Как я могу сопоставить напрямую из моих специфичных для приложения исключений в 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());
}