Когда пользователь загружает страницу, он выполняет один или несколько запросов ajax, которые попадают в контроллеры ASP.NET Web API 2. Если пользователь переходит на другую страницу до того, как эти запросы ajax завершатся, запросы отменяются браузером. Затем наш ELMAH HttpModule регистрирует две ошибки для каждого отмененного запроса:
Ошибка 1:
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()
Ошибка 2:
System.OperationCanceledException: The operation was canceled.
at System.Threading.CancellationToken.ThrowIfCancellationRequested()
at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.WebHost.HttpControllerHandler.<CopyResponseAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.WebHost.HttpControllerHandler.<ProcessRequestAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.TaskAsyncHelper.EndTask(IAsyncResult ar)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Глядя на stacktrace, я вижу, что исключение генерируется отсюда: https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http.WebHost/HttpControllerHandler.cs# L413
Мой вопрос: как я могу обрабатывать и игнорировать эти исключения?
Похоже, что это вне кода пользователя ...
Ноты:
- Я использую веб-API ASP.NET 2
- Конечные точки веб-API представляют собой сочетание асинхронных и неасинхронных методов.
- Независимо от того, где я добавляю регистрацию ошибок, я не могу поймать исключение в пользовательском коде
- Global.asax
Applicaiton_Error
TaskScheduler.UnobservedTaskException
- Фильтрация ошибок ELMAH
void ErrorLog_Filtering
( https://code.google.com/p/elmah/wiki/ErrorFiltering )
- Global.asax
asp.net
iis
asp.net-web-api
task-parallel-library
async-await
Бейтс Вестморленд
источник
источник
Ответы:
Это ошибка в ASP.NET Web API 2, и, к сожалению, я не думаю, что есть обходной путь, который всегда будет успешным. Мы зарегистрировали ошибку, чтобы исправить это на нашей стороне.
В конечном итоге проблема заключается в том, что в этом случае мы возвращаем отмененную задачу в ASP.NET, а ASP.NET обрабатывает отмененную задачу как необработанное исключение (регистрирует проблему в журнале событий приложения).
А пока вы можете попробовать что-то вроде приведенного ниже кода. Он добавляет обработчик сообщений верхнего уровня, который удаляет содержимое при срабатывании токена отмены. Если в ответе нет содержимого, ошибка не должна запускаться. По-прежнему существует небольшая вероятность, что это может произойти, потому что клиент может отключиться сразу после того, как обработчик сообщений проверит токен отмены, но до того, как код веб-API более высокого уровня выполнит ту же проверку. Но я думаю, что в большинстве случаев это поможет.
Дэвид
источник
SendAsync
(вы можете смоделировать это, удерживаяF5
в браузере URL-адрес, который отправляет запросы к вашему Api. Я решил эту проблему также добавлениеif (cancellationToken.IsCancellationRequested)
проверки над вызовомSendAsync
. Теперь исключения больше не отображаются, когда браузер быстро отменяет запросы.При реализации регистратора исключений для WebApi рекомендуется расширять
System.Web.Http.ExceptionHandling.ExceptionLogger
класс, а не создавать ExceptionFilter. Внутренние компоненты WebApi не будут вызывать метод журнала ExceptionLoggers для отмененных запросов (однако фильтры исключений получат их). Это сделано намеренно.источник
Вот другой способ решения этой проблемы. Просто добавьте настраиваемое промежуточное ПО OWIN в начало конвейера OWIN, которое улавливает
OperationCanceledException
:источник
Вы можете попытаться изменить по умолчанию TPL задач обработки исключений поведения с помощью
web.config
:Затем в вашем веб-приложении есть
static
класс (сstatic
конструктором), который будет обрабатыватьAppDomain.UnhandledException
.Однако похоже, что это исключение фактически обрабатывается где-то внутри среды выполнения веб-API ASP.NET , прежде чем вы даже сможете обработать его с помощью своего кода.
В этом случае, вы должны быть в состоянии поймать его как 1 шанс исключением, с
AppDomain.CurrentDomain.FirstChanceException
, вот как . Я понимаю, что это может быть не то, что вы ищете.источник
FirstChanceException
? Вы пробовали обрабатывать его с помощью статического класса, который сохраняется в HTTP-запросах?AppDomain.UnhandledException
илиAppDomain.CurrentDomain.FirstChanceException
может позволить мне проверить исключение, но не поймать и игнорировать. Я не видел способа пометить эти исключения как обработанные с использованием любого из этих подходов. Поправьте меня, если я ошибаюсь.Иногда я получаю те же 2 исключения в моем приложении Web API 2, однако я могу поймать их с помощью
Application_Error
методаGlobal.asax.cs
и общего фильтра исключений .Однако забавно то, что я предпочитаю не улавливать эти исключения, потому что я всегда регистрирую все необработанные исключения, которые могут привести к сбою приложения (эти 2, однако, для меня не имеют значения и, по-видимому, не приводят к сбою или, по крайней мере, не должны сбой это, но я могу ошибаться). Я подозреваю, что эти ошибки появляются из-за истечения тайм-аута или явной отмены со стороны клиента, но я ожидал, что они будут обрабатываться внутри платформы ASP.NET, а не распространяться за ее пределы как необработанные исключения.
источник
WinHTTP
API, а не из браузера.Я нашел более подробную информацию об этой ошибке. Возможны 2 исключения:
OperationCanceledException
TaskCanceledException
Первый происходит, если соединение разрывается во время выполнения вашего кода в контроллере (или, возможно, некоторого системного кода вокруг этого). В то время как второй происходит, если соединение разрывается, когда выполнение находится внутри атрибута (например
AuthorizeAttribute
).Таким образом, предоставленный обходной путь помогает частично смягчить первое исключение, но не помогает со вторым. В последнем случае это
TaskCanceledException
происходит во времяbase.SendAsync
самого вызова, а для токена отмены устанавливается значение true.Я вижу два пути решения этих проблем:
TaskCanceledException
что мы проигнорируем тот, который мы хотим зарегистрировать.Единственный способ, которым я понял, что мы можем попытаться определить неправильные исключения, - это проверить, содержит ли stacktrace какой-либо материал Asp.Net. Однако не кажется очень надежным.
PS Вот как я отфильтровываю эти ошибки:
источник
response
переменную внутри попытки и возвращаете ее вне попытки. Это не может работать, не так ли? Также где вы используете IsAspNetBugException?Мы получали то же исключение, мы пытались использовать обходной путь @dmatson, но мы все равно получали какое-то исключение. Мы занимались этим до недавнего времени. Мы заметили, что некоторые журналы Windows растут с угрожающей скоростью.
Файлы ошибок расположены в: C: \ Windows \ System32 \ LogFiles \ HTTPERR
Большинство ошибок было связано с "Timer_ConnectionIdle". Я поискал все вокруг, и мне показалось, что, хотя вызов веб-API был завершен, соединение все еще сохранялось в течение двух минут после исходного соединения.
Затем я решил, что мы должны попытаться закрыть соединение в ответе и посмотреть, что произойдет.
Я добавил
response.Headers.ConnectionClose = true;
в SendAsync MessageHandler и, насколько я могу судить, клиенты закрывают соединения, и мы больше не сталкиваемся с этой проблемой.Я знаю, что это не лучшее решение, но в нашем случае оно работает. Я также уверен, что с точки зрения производительности это не то, что вы хотели бы делать, если ваш API получает несколько вызовов от одного и того же клиента подряд.
источник