我有一个ASP.NET Web API 2控制器操作,它使用HttpClient.PostAsync()
来发出上游HTTP请求。如果在控制器操作中等待的上游请求超时,则从控制器操作抛出TaskCanceledException
。在这一点上,我看到了一些我无法解释的事情,可以使用一些帮助:
PostAsync()
调用,我可以捕获TaskCanceledException
。但是,如果没有try / catch,则不会出现此异常:
Application_Error
方法IExceptionLogger
或IExceptionHandlers
添加到HttpConfiguration.Services
WebApiConfig.cs
TaskCanceledException
和,直到客户端(Fiddler,浏览器等)断开连接为止试图调用我的控制器动作。此时我知道我可以通过使用try / catch并抛出TaskCanceledException
或其他东西来阻止重新尝试该操作,但我特别感兴趣的是为什么我无法抓住使用常规方法的这个例外,以及为什么我看到这种明显的重试行为。欢迎任何意见!
将此Web API Controller添加到项目中:
HttpResponseException
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;
}
}
}
http://localhost:xxxxx/api/values
语句的输出是否出现两次。在我的测试中,我看到这样的事情:
Debug.WriteLine()