如何直接从特定于应用程序的异常映射到Http Exceptions?

时间:2012-09-19 12:37:28

标签: c# asp.net-mvc action-filter custom-error-pages handleerror

我正在研究ASP.NET MVC 3应用程序。在我们的应用程序的所谓“业务层”中,我们决定总是抛出一些特定类型的异常,具体取决于具体情况。当用户尝试执行未经授权的操作时,我们有一个Exception类型层次结构,当应用程序无法找到给定项目时(通过Id或名称或其他任何内容),我们有一些特殊例外。

在我们的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
    // ...
}

...其中SomethingNotFoundExceptionNotAuthorizedException是自定义Exception s。

在这种异常与Http状态代码(404 Not Found / 403 Forbidden)之间存在直接映射,我们希望我们的Controller方法能够相应地处理这些错误(显示404/403 CustomError页面和类似的东西)。现在,我们想要的是避免在我们的控制器操作中执行此操作:

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

}

...并将其添加到Global.asax中的GlobalFilterCollection ...但它仍然被处理,就好像它是通常的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 个答案:

答案 0 :(得分:0)

有一些选择。

您可能需要:This guys解决方案

你可以这样做This guy

您可以拥有一个所有类继承的基本Controller类,并使用以下方法。这就是我上一家公司解决这个问题的方法。

protected override void OnException(ExceptionContext filterContext)
{
       Console.WriteLine(filterContext.Exception.ToString());
}