とあるコンテンツをリリースした直後に以下のようなエラーがちょいちょい発生していました。
System.OperationCanceledException: 操作は取り消されました。
場所 System.Threading.CancellationToken.ThrowIfCancellationRequested()
場所 System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
場所 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
場所 System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
場所 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
場所 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
場所 System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
場所 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
場所 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
場所 System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()
スタックトレースにコンテンツ側のコード情報が出てなかったり、ネットで調べてもTaskベースの非同期処理がキャンセルされた時に発生するとは出てくるものの、そもそもそのコンテンツでは基本的に非同期処理を使っていなかったので、原因がよくわからない状態でした。
ただ、エラーが発生しているURLを見てみたら全部ASP.NET Web APIでの箇所しか出てなかったので、そこに絞って調べてみたら以下のページにたどり着きました。
要はAjax処理がキャンセルされた時に発生する(ASP.NET Web APIのバグ?な)ようで、独自実装したExceptionFilterAttributeに以下の処理を追加したら出なくなるようになりました。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class ApplicationErrorApiFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext?.Exception == null)
return;
if (actionExecutedContext.Exception is OperationCanceledException)
{
// HttpCode:200を返して何事もなかったようにする
actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse();
return;
}
actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
そのコンテンツの場合はクライアントサイドでAjax処理中に他のアクションも起こせるようになっていため、↑のような処理を記述して対応せざるをえませんでしたが、サービスやアプリケーションによってはAjax処理中は他のアクションをブロックするなどの対応が必要になります。
その辺はアプリケーションの非機能要件次第なので、各担当者に確認して適した対応を行う必要があります。