我正在使用静态HttpClient(出于可扩展性原因 - 请参阅What is the overhead of creating a new HttpClient per call in a WebAPI client?),并希望能够取消花费太长时间的个别请求。 SendAsync
上的重载需要CancellationToken
- 但我不知道它是否是线程安全的,因为我的HttpClient
实例是static
。例如,如果我同时通过HttpClient
发送了多个请求,并尝试取消一个请求,是否取消了正确的请求?
我通过HttpClient
代码看了一下,乍看起来它看起来不是线程安全的,因为取消发送到HttpClientHandler
(这对所有人来说都是一样的)要求)。但我可能会遗漏一些东西。所以我的问题是:
注意: 自测试以来,需要一种方法可靠创建竞争条件,在我无法控制的代码中,我没有看到测试方法。
答案 0 :(得分:4)
每个SendAsync
调用完全相互独立,取消一个请求的令牌不会取消其他未完成的请求。
您的假设是因为所有请求共享HttpClientHandler
,这意味着所有请求都被取消,这是不正确的。如果你查看HttpClientHandler
的反编译来源,你会看到
[__DynamicallyInvokable]
protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request == null)
throw new ArgumentNullException(nameof (request), SR.net_http_handler_norequest);
this.CheckDisposed();
if (Logging.On)
Logging.Enter(Logging.Http, (object) this, nameof (SendAsync), (object) request);
this.SetOperationStarted();
TaskCompletionSource<HttpResponseMessage> completionSource = new TaskCompletionSource<HttpResponseMessage>();
HttpClientHandler.RequestState state = new HttpClientHandler.RequestState();
state.tcs = completionSource;
state.cancellationToken = cancellationToken;
state.requestMessage = request;
try
{
HttpWebRequest prepareWebRequest = this.CreateAndPrepareWebRequest(request);
state.webRequest = prepareWebRequest;
cancellationToken.Register(HttpClientHandler.onCancel, (object) prepareWebRequest);
if (ExecutionContext.IsFlowSuppressed())
{
IWebProxy webProxy = (IWebProxy) null;
if (this.useProxy)
webProxy = this.proxy ?? WebRequest.DefaultWebProxy;
if (this.UseDefaultCredentials || this.Credentials != null || webProxy != null && webProxy.Credentials != null)
this.SafeCaptureIdenity(state);
}
Task.Factory.StartNew(this.startRequest, (object) state);
}
catch (Exception ex)
{
this.HandleAsyncException(state, ex);
}
if (Logging.On)
Logging.Exit(Logging.Http, (object) this, nameof (SendAsync), (object) completionSource.Task);
return completionSource.Task;
}
每次调用HttpClientHandler.RequestState state
时,取消令牌都会被包含在新的SendAsnyc
对象中,当取消该令牌时,只有与该状态对象关联的state.webRequest
才会被取消被取消。
答案 1 :(得分:0)
刚收到Microsoft产品团队的确认:
是的,使用支持取消个人请求是完全安全的 取消令牌传递到各种
HttpClient.SendAsync
, 。GetAsync
等方法。HttpClient
是无关紧要的 &#34;static
&#34 ;.传递给方法的取消令牌用于 那个特殊的要求。