在AJAX请求期间对异常的自定义处理导致HttpException

时间:2018-06-29 14:07:21

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

当我的应用程序在AJAX请求期间遇到类型UnauthorizedAccessException的异常时,我想自己处理该行为并返回自定义JSON响应。

因此,我在基本控制器中重写了OnException方法,我的所有控制器都继承了该方法,如下所示:

protected override void OnException(ExceptionContext filterContext)
{
    var exception = filterContext.Exception;

    if (exception is UnauthorizedAccessException)
    {
        filterContext.ExceptionHandled = true;

        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
            filterContext.HttpContext.Response.ContentType = "application/json";

            JavaScriptSerializer serializer = new JavaScriptSerializer();
            string json = serializer.Serialize(new { IsUnauthenticated = true });
            filterContext.HttpContext.Response.Write(json);

            filterContext.HttpContext.Response.End();
        }
        else
        {
            filterContext.Result = RedirectToAction("LogOut", "Account");
        }
    }
    else
    {
        // Allow the exception to be processed as normal.
        base.OnException(filterContext);
    }
}

现在,这几乎可以完全满足我的要求。如果在AJAX请求期间发生异常,我的JavaScript将根据需要获取正确的JSON对象。

但是,问题是应用程序随后在内部遭受HttpException的影响,并显示以下消息:

  

发送HTTP标头后无法重定向。

以及来自异常的堆栈跟踪:

  

在System.Web.HttpResponse.Redirect(字符串url,布尔值endResponse,布尔值永久性)      在System.Web.Security.FormsAuthenticationModule.OnLeave(Object source,EventArgs eventArgs)      在System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()      在System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep步骤)      在System.Web.HttpApplication.ExecuteStep(IExecutionStep步骤,布尔值并已完成)

将断点添加到Application_Error的{​​{1}}方法中时,会得到以下异常信息:

MvcApplication

因此,尽管我的应用程序产生的结果完全符合我的用户体验。我有一个“幕后”异常,我真的不想发生。

这是怎么回事?我该怎么做才能防止异常发生?

2 个答案:

答案 0 :(得分:1)

从评论继续,我认为由于字符限制,最好将其发布为答案。这部分是答案,因为我前面没有合适的项目要测试。

当我在评论中说我无法复制时,那是因为我在我正在处理的项目中运行了那些测试,这些项目是WebApi2,并且我不会有相同的行为。

如果我的想法正确,那么您的问题就在于您正在将类似API的功能实现到MVC项目中,当然,您所看到的只是预期的行为。

当您收到UnauthorizedException时,框架将尝试自动将您重定向到登录屏幕(或错误页面)。您需要(显然)禁用该行为。

您可以尝试使用以下方法在处理程序中将其抑制:

con = sqlite3.connect('databaseTest.db')
cur = con.cursor()
cur.execute("SELECT LOAN_AMOUNT FROM funded")
loan_amount = cur.fetchall()
loan_amount_list = [i[0] for i in loan_amount]

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
x = loan_amount_list

最终结果应该类似于:

filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
filterContext.HttpContext.Response.Redirect(null);

如果这不起作用;您的身份验证中间件也可能负责设置此重定向,但很遗憾,该重定向将在其他地方设置。

答案 1 :(得分:0)

我的其他答案是错误的,我刚刚对其进行了测试。

该问题的解决方案与我之前给您的解决方案略有不同。您的中间件就是导致问题的原因。

我怀疑您正在使用我正在使用的东西; Microsoft.ASPNET.Identity。

在Startup.cs内部,您需要添加OnApplyRedirect委托。

您的代码应类似于我的代码:

app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)),
                     OnApplyRedirect = ctx =>
                     {
                         // add json response here...
                         ctx.RedirectUri = null;

                     }
                }
            });

从原始处理程序中移出响应,并将其添加到ctx.Response ...

希望这将使其重回正轨。在OnApplyRedirect内部,您可能需要检查它是否是ajax请求,然后禁用重定向,否则您将获得难看的asp默认错误页面。.:-)