TaskCanceledException导致再次调用Controller操作

时间:2014-11-07 20:19:49

标签: asp.net asp.net-mvc asp.net-web-api task-parallel-library

我有一个ASP.NET Web API 2控制器操作,它使用HttpClient.PostAsync()来发出上游HTTP请求。如果在控制器操作中等待的上游请求超时,则从控制器操作抛出TaskCanceledException。在这一点上,我看到了一些我无法解释的事情,可以使用一些帮助:

  1. 全局异常处理无法捕获此异常如果我使用try / catch包围等待的PostAsync()调用,我可以捕获TaskCanceledException。但是,如果没有try / catch,则不会出现此异常:
    • Global.asax.cs Application_Error方法
    • IExceptionLoggerIExceptionHandlers添加到HttpConfiguration.Services
    • 中的WebApiConfig.cs
  2. 再次调用控制器操作 - 正如我在Fiddler中观察的那样,只有一个服务请求,但在控制器操作开始时设置的断点被多次命中,每个{ {1}} 直到Fiddler停止等待响应并返回504网关错误似乎 ASP.NET或Web API管道中的某些内容正在处理TaskCanceledException,直到客户端(Fiddler,浏览器等)断开连接为止试图调用我的控制器动作。
  3. 此时我知道我可以通过使用try / catch并抛出TaskCanceledException或其他东西来阻止重新尝试该操作,但我特别感兴趣的是为什么我无法抓住使用常规方法的这个例外,以及为什么我看到这种明显的重试行为。欢迎任何意见!

    Minimal Repro

    1. 将此Web API Controller添加到项目中:

      HttpResponseException
    2. 清除调试控制台
    3. 在浏览器中或通过Fiddler向api操作发出 SINGLE 请求,例如:获取namespace TaskRetryRepro.Controllers { using System; using System.Diagnostics; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Web; using System.Web.Http; public class ValuesController : ApiController { public async Task<IHttpActionResult> Get() { // I see two lines output in my debug console per single request to this API action Debug.WriteLine( "Get called with HttpRequestMessage: {0} and HttpContext.Current.Request: {1}", this.Request.GetHashCode(), HttpContext.Current.Request.GetHashCode()); var httpClient = new HttpClient(new TimeoutHandler()); // NOTE: No try/catch here await httpClient.GetAsync("http://www.google.com"); return this.Ok(new[] { "value1", "value2" }); } } /// <summary>The timeout handler.</summary> public class TimeoutHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // in my scenario calling another service it's an actual upstream service timeout but // it throws the TaskCanceledException just the same Thread.Sleep(TimeSpan.FromSeconds(5)); var tcs = new TaskCompletionSource<HttpResponseMessage>(); tcs.SetCanceled(); return tcs.Task; } } }
    4. 验证http://localhost:xxxxx/api/values语句的输出是否出现两次。在我的测试中,我看到这样的事情: Debug.WriteLine()

0 个答案:

没有答案