Ketika pengguna memuat halaman, itu membuat satu atau lebih permintaan ajax, yang menekan pengontrol ASP.NET Web API 2. Jika pengguna menavigasi ke halaman lain, sebelum permintaan ajax ini selesai, permintaan dibatalkan oleh browser. ELMAH HttpModule kami kemudian mencatat dua kesalahan untuk setiap permintaan yang dibatalkan:
Galat 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()
Kesalahan 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)
Melihat stacktrace, saya melihat bahwa pengecualian dilempar dari sini: https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http.WebHost/HttpControllerHandler.cs# L413
Pertanyaan saya adalah: Bagaimana cara menangani dan mengabaikan pengecualian ini?
Tampaknya di luar kode pengguna ...
Catatan:
- Saya menggunakan ASP.NET Web API 2
- Titik akhir API Web adalah campuran metode asinkron dan non-asinkron.
- Di mana pun saya menambahkan pencatatan kesalahan, saya tidak dapat menangkap pengecualian dalam kode pengguna
- Global.asax
Applicaiton_Error
TaskScheduler.UnobservedTaskException
- Pemfilteran Kesalahan 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
Bates Westmoreland
sumber
sumber
Jawaban:
Ini adalah bug di ASP.NET Web API 2 dan sayangnya, saya rasa tidak ada solusi yang akan selalu berhasil. Kami mengajukan bug untuk memperbaikinya di pihak kami.
Pada akhirnya, masalahnya adalah kita mengembalikan tugas yang dibatalkan ke ASP.NET dalam kasus ini, dan ASP.NET memperlakukan tugas yang dibatalkan seperti pengecualian yang tidak tertangani (itu mencatat masalah di log peristiwa aplikasi).
Sementara itu, Anda dapat mencoba sesuatu seperti kode di bawah ini. Ia menambahkan penangan pesan tingkat atas yang menghapus konten saat token pembatalan diaktifkan. Jika respons tidak memiliki konten, bug tidak boleh dipicu. Masih ada kemungkinan kecil hal itu bisa terjadi, karena klien dapat memutuskan sambungan tepat setelah penangan pesan memeriksa token pembatalan tetapi sebelum kode API Web tingkat yang lebih tinggi melakukan pemeriksaan yang sama. Tapi saya pikir itu akan membantu dalam banyak kasus.
David
sumber
SendAsync
(Anda dapat mensimulasikan ini dengan menahanF5
di browser pada url yang membuat permintaan ke Api Anda. Saya menyelesaikan masalah ini dengan juga menambahkanif (cancellationToken.IsCancellationRequested)
centang di atas panggilan keSendAsync
. Sekarang pengecualian tidak lagi muncul saat browser dengan cepat membatalkan permintaan.Saat mengimplementasikan logger pengecualian untuk WebApi, disarankan untuk memperluas
System.Web.Http.ExceptionHandling.ExceptionLogger
kelas daripada membuat ExceptionFilter. Internal WebApi tidak akan memanggil metode Log ExceptionLoggers untuk permintaan yang dibatalkan (namun, filter pengecualian akan mendapatkannya). Ini memang disengaja.sumber
Berikut solusi lain untuk masalah ini. Cukup tambahkan middleware OWIN khusus di awal pipeline OWIN yang menangkap
OperationCanceledException
:sumber
Anda dapat mencoba mengubah perilaku penanganan pengecualian tugas TPL default melalui
web.config
:Kemudian miliki
static
kelas (denganstatic
konstruktor) di aplikasi web Anda, yang akan menanganiAppDomain.UnhandledException
.Namun, tampaknya itu pengecualian ini sebenarnya ditangani di suatu tempat di dalam runtime API Web ASP.NET , bahkan sebelum Anda memiliki kesempatan untuk menanganinya dengan kode Anda.
Dalam hal ini, Anda harus dapat menangkapnya sebagai pengecualian kesempatan pertama, dengan
AppDomain.CurrentDomain.FirstChanceException
, berikut caranya . Saya mengerti ini mungkin bukan yang Anda cari.sumber
FirstChanceException
? Sudahkah Anda mencoba menanganinya dengan kelas statis yang tetap ada di seluruh permintaan HTTP?AppDomain.UnhandledException
atauAppDomain.CurrentDomain.FirstChanceException
mengizinkan saya untuk memeriksa pengecualian, tetapi tidak menangkap dan mengabaikan. Saya tidak melihat cara untuk menandai pengecualian ini sebagai ditangani menggunakan salah satu dari pendekatan ini. Koreksi saya jika saya salah.Terkadang saya mendapatkan 2 pengecualian yang sama di aplikasi API Web 2 saya, namun saya dapat menangkapnya dengan
Application_Error
metode diGlobal.asax.cs
dan menggunakan filter pengecualian umum .Lucunya, saya memilih untuk tidak menangkap pengecualian ini, karena saya selalu mencatat semua pengecualian yang tidak tertangani yang dapat merusak aplikasi (2 ini, bagaimanapun, tidak relevan bagi saya dan tampaknya tidak atau setidaknya tidak boleh crash itu, tapi saya mungkin salah). Saya menduga kesalahan ini muncul karena beberapa batas waktu kedaluwarsa atau pembatalan eksplisit dari klien, tetapi saya berharap mereka diperlakukan di dalam kerangka ASP.NET dan tidak disebarkan di luar sebagai pengecualian yang tidak tertangani.
sumber
WinHTTP
API, bukan dari browser.Saya telah menemukan sedikit lebih banyak detail tentang kesalahan ini. Ada 2 kemungkinan pengecualian yang dapat terjadi:
OperationCanceledException
TaskCanceledException
Yang pertama terjadi jika koneksi terputus saat kode Anda dalam pengontrol dijalankan (atau mungkin beberapa kode sistem di sekitarnya juga). Sedangkan yang kedua terjadi jika koneksi terputus saat eksekusi berada di dalam atribut (misalnya
AuthorizeAttribute
).Jadi solusi yang disediakan membantu untuk mengurangi sebagian dari pengecualian pertama, tidak ada yang membantu dengan yang kedua. Dalam kasus terakhir,
TaskCanceledException
terjadi selamabase.SendAsync
panggilan itu sendiri daripada token pembatalan yang disetel ke true.Saya dapat melihat dua cara untuk menyelesaikan ini:
TaskCanceledException
yang kita abaikan akan menjadi salah satu yang ingin kita log.Satu-satunya cara saya mengetahui bahwa kita dapat mencoba menunjukkan pengecualian yang salah adalah dengan memeriksa apakah stacktrace berisi beberapa item Asp.Net. Sepertinya tidak terlalu kuat.
NB Beginilah cara saya memfilter kesalahan ini:
sumber
response
variabel di dalam percobaan dan mengembalikannya di luar percobaan. Itu tidak mungkin berhasil, bukan? Juga di mana Anda menggunakan IsAspNetBugException?Kami telah menerima pengecualian yang sama, kami mencoba menggunakan solusi @ dmatson, tetapi kami masih mendapatkan beberapa pengecualian. Kami menanganinya sampai saat ini. Kami melihat beberapa log Windows tumbuh dengan kecepatan yang mengkhawatirkan.
File kesalahan terletak di: C: \ Windows \ System32 \ LogFiles \ HTTPERR
Sebagian besar kesalahan adalah untuk "Timer_ConnectionIdle". Saya mencari-cari dan tampaknya meskipun panggilan web api selesai, koneksi masih bertahan selama dua menit setelah koneksi asli.
Saya kemudian berpikir kita harus mencoba menutup koneksi dalam tanggapan dan melihat apa yang terjadi.
Saya menambahkan
response.Headers.ConnectionClose = true;
ke SendAsync MessageHandler dan dari apa yang saya tahu klien menutup koneksi dan kami tidak mengalami masalah lagi.Saya tahu ini bukan solusi terbaik, tetapi berhasil dalam kasus kami. Saya juga cukup yakin dari segi performa, ini bukan sesuatu yang ingin Anda lakukan jika API Anda mendapatkan banyak panggilan dari klien yang sama secara berurutan.
sumber