确保特定异常始终导致给定的HTTP响应状态代码

时间:2018-06-28 14:54:02

标签: c# asp.net-mvc exception-handling httpresponse

要求

我有一个ASP.Net MVC应用程序,可与许多不同的库一起使用。与大多数库一样,各种函数调用可能会导致引发许多不同的异常之一。

当前,每当引发任何异常时,MVC应用程序都会“处理”它们并向客户端(例如Web浏览器)返回“内部服务器错误”(代码500)。

这在大多数情况下都很好,但是,我想在响应中发送一种特定的异常类型(在这种情况下为UnauthorizedAccessException),导致“未授权”(代码401)状态被发送,而不是通常的500错误。

当前尝试

我做了相当多的研究,看起来可以使用Application_Error方法来“捕获”所有异常并对其进行处理的赌注方式。因此,我在Application_Error类中尝试了MvcApplication的以下实现:

protected void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();

    if(ex is UnauthorizedAccessException)
    {
        Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
    }
}

问题

这里的问题是,尽管我可以调试并看到Response.StatusCode设置为401,但是客户端/浏览器仍然收到500错误。

我希望这是有很好的原因的,但是我已经筋疲力尽地想着可以找到所需答案的搜索字词。

问题

简而言之,我需要做些什么才能得到想要的行为?


有关其他信息,最终,我希望UnauthorizedAccessException具有与MVC处理未经身份验证的请求(重定向到登录页面)的方式相同的行为。但是,我也需要它来处理AJAX请求,因为我的javascript可以检查401错误并执行一些特定的逻辑(在这种情况下,无法将响应重定向到登录页面)

1 个答案:

答案 0 :(得分:1)

执行此操作的一个聪明方法是创建一个基本控制器,您的控制器将继承该默认控制器。在那里,您将继承默认的Controller类并重写OnException方法。

public abstract class BaseController : Controller
{
    protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
    {
        var responseCode = Response.StatusCode;
        var exception = filterContext.Exception;
        switch (exception.GetType().ToString())
        {
            case "UnauthorizedAccessException":
                responseCode = 401;
                filterContext.ExceptionHandled = true;
                break;
        }

        Response.StatusCode = responseCode;

        base.OnException(filterContext);
    }
}

使其工作的窍门是filterContext.ExceptionHandled = true;,如果您未将其设置为true,则服务器将返回500。

您的控制器将继承BaseController;

public class UserController : BaseController
{
    public ActionResult Index(){
        return View();
    }
}

您需要在此代码中添加的内容是重定向到登录页面,重定向到OnException方法(如果需要)。我会为您完成此操作,但我没有足够的时间为您编写和测试它。.目前正在等待自动化测试完成..:-)

编辑:

我没有意识到您的视图也可能引发错误,显然控制器不会处理该错误。

在这种情况下,我们可以还原到Global.asax上的原始Application_Error方法。

我们需要的是两行代码。

Response.StatusCode = 401;
Response.End();

第一行将状态代码设置为401, 第二行此时结束执行并触发EndRequest事件,因此StatusCode不会修改为500。

如果您想在回复中附加一条消息:

Response.Write("Oops, you're not authorized...");

在开始修改错误处理程序中的响应对象之前,调用Response.Clear();是个好主意。