Пользовательская обработка исключений во время запроса AJAX вызывает HttpException

Когда мое приложение встречает исключение типа UnauthorizedAccessExceptionво время запроса AJAX, я хочу сам обработать поведение и вернуть пользовательский ответ JSON.

Поэтому я переопределил OnExceptionметод в базовом контроллере, который наследует все мои conrtollers, например:

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 (String url, Boolean endResponse, Boolean constant) в System.Web.Security.FormsAuthenticationModule.OnLeave (источник объекта, EventArgs eventArgs) в System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication. IExecutionStep.Execute () на System.Web.HttpApplication.ExecuteStepImpl (шаг IExecutionStep) в System.Web.HttpApplication.ExecuteStep (шаг IExecutionStep, логический и завершенный синхронно)

Я получаю эту информацию об исключениях при добавлении точки останова к Application_Errorметоду MvcApplicationвроде этого:

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

Поэтому, хотя моя заявка производит результат точно так же, как я хочу с точки зрения пользователя. У меня есть это «за кулисами» исключение, которое я действительно не хочу.

Что здесь происходит? И что я могу сделать, чтобы предотвратить возникновение исключения?

c#,asp.net-mvc,exception-handling,

0

Ответов: 2


1 принят

Продолжая из комментариев, я решил, что лучше всего разместить его в качестве ответа из-за ограничения персонажа. Это отчасти ответ, потому что у меня нет подходящего проекта для проверки.

Когда я сказал в комментарии, что я не могу реплицировать, это было потому, что я запускал те тесты в проекте, над которым я работаю, который является WebApi2, и у меня не будет такого же поведения.

Если мой разум помогает мне, ваша проблема заключается в том, что вы реализуете API как функциональность в проекте MVC, и, конечно же, то, что вы видите, - это ожидаемое поведение.

Когда вы получите UnauthorizedException, структура попытается автоматически перенаправить вас на экран входа в систему (или страницу с ошибкой). Вы должны отключить это поведение (очевидно).

То, что вы можете попробовать, это подавить его в обработчике, используя ниже:

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

Конечный результат должен быть чем-то вроде:

if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
    filterContext.HttpContext.Response.StatusCode = 
    (int)System.Net.HttpStatusCode.Unauthorized;

    filterContext.HttpContext.Response.ContentType = "application/json";



    filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

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

    filterContext.HttpContext.Response.End();
}

Если это не сработает; ваше связующее ПО для проверки подлинности также может отвечать за настройку этого перенаправления, и это, к сожалению, будет установлено в другом месте.


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-страницы по умолчанию. :-)

C #, asp.net-MVC, обработки исключений,
Похожие вопросы