要求
我有一个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
错误并执行一些特定的逻辑(在这种情况下,无法将响应重定向到登录页面)
答案 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();
是个好主意。