简体   繁体   English

.NET HttpClient - 取消了CancellationToken而不取消请求

[英].NET HttpClient - cancelled CancellationToken not cancelling request

I'm running into an issue with the .NET HttpClient class (.NET 4.5.1, System.Net.Http v4.0.0.0). 我遇到了.NET HttpClient类(.NET 4.5.1,System.Net.Http v4.0.0.0)的问题。 I'm calling HttpClient.GetAsync , passing in a CancellationToken (as part of a Nuget package that abstracts calls between webservices). 我正在调用HttpClient.GetAsync ,传入一个CancellationToken (作为Nuget包的一部分,用于抽象webservices之间的调用)。 If the token has been cancelled before the call is made, the request goes through without throwing an exception. 如果在进行调用之前已取消令牌,则请求将在不抛出异常的情况下通过。 This behavior doesn't seem correct. 这种行为似乎不正确。

My test (incomplete, not fully written - no exception check): 我的测试(不完整,未完全编写 - 无异常检查):

[TestMethod]
public async Task Should_Cancel_If_Cancellation_Token_Called()
{
    var endpoint = "nonexistent";
    var cancellationTokenSource = new CancellationTokenSource();

    var _mockHttpMessageHandler = new MockHttpMessageHandler();
    _mockHttpMessageHandler
        .When("*")
        .Respond(HttpStatusCode.OK);

    var _apiClient = new ApiClientService(new HttpClient(_mockHttpMessageHandler));
    cancellationTokenSource.Cancel();

    var result = await _apiClient.Get<string>(endpoint, null, cancellationTokenSource.Token);
}

The method I'm testing: 我正在测试的方法:

public async Task<T> Get<T>(string endpoint, IEnumerable<KeyValuePair<string, string>> parameters = null, CancellationToken cancellationToken = default(CancellationToken))
{
    var builder = new UriBuilder(Properties.Settings.Default.MyEndpointHost + endpoint);
    builder.Query = buildQueryStringFromParameters(parameters);

    _httpClient.DefaultRequestHeaders.Accept.Clear();
    _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    try
    {
        // After this, we really shouldn't continue.
        var request = await _httpClient.GetAsync(builder.Uri, cancellationToken);

        if (!request.IsSuccessStatusCode)
        {
            if (request.StatusCode >= HttpStatusCode.BadRequest && request.StatusCode < HttpStatusCode.InternalServerError)
            {
                throw new EndpointClientException("Service responded with an error message.", request.StatusCode, request.ReasonPhrase);
            }

            if (request.StatusCode >= HttpStatusCode.InternalServerError && (int)request.StatusCode < 600)
            {
                throw new EndpointServerException("An error occurred in the Service endpoint.", request.StatusCode, request.ReasonPhrase);
            }
        }

        var json = await request.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(json);
    }
    catch (Exception ex)
    {
        throw;
    }
}

I know that I can check the status of the cancellation token before calling HttpClient.GetAsync and throw if cancellation has been requested. 我知道我可以在调用HttpClient.GetAsync之前检查取消令牌的状态,并在请求取消时抛出。 I know that I can also register a delegate to cancel the HttpClient request. 我知道我也可以注册一个委托来取消HttpClient请求。 However, it seems as though passing the token to the HttpClient method should take care of this for me (or, else, what's the point?) so I'm wondering if I'm missing something. 然而,似乎将令牌传递给HttpClient方法应该为我处理这个问题(或者,除此之外,重点是什么?)所以我想知道我是否遗漏了一些东西。 I don't have access to the HttpClient source code. 我无权访问HttpClient源代码。

Why is HttpClient.GetAsync not checking my cancellation token and aborting its process when I pass it in? 为什么HttpClient.GetAsync在我传递它时不检查我的取消令牌并中止其进程?

HttpClient doesn't check the cancellation token itself, it passes it on to the message handler when it calls its SendAsync method. HttpClient不检查取消令牌本身,它在调用其SendAsync方法时将其传递给消息处理程序。 It then registers to the continuation on the task returned from SendAsync and will set its own task as cancelled if the task returned from the message handler was cancelled. 然后它注册到SendAsync返回的任务的延续,如果从消息处理程序返回的任务被取消,它将自己的任务设置为取消。

So the problem in your scenario is in your implementation of MockHttpMessageHandler which seems doesn't check the cancellation token. 所以你的场景中的问题在于你的MockHttpMessageHandler的实现,它似乎没有检查取消令牌。

Note, that if HttpClient is called via its empty constructor, it internally uses HttpClientHandler which registers a delegate on the cancellation token that aborts the request and cancels the task. 注意,如果通过其空构造函数调用HttpClient ,它会在内部使用HttpClientHandler ,它会在取消令牌上注册一个委托,该委托取消该请求并取消该任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 取消HttpClient请求 - 为什么TaskCanceledException.CancellationToken.IsCancellationRequested为false? - Cancelling an HttpClient Request - Why is TaskCanceledException.CancellationToken.IsCancellationRequested false? 传入已取消的CancellationToken会导致HttpClient挂起 - Passing in an already cancelled CancellationToken causes HttpClient to hang 正确取消和清除CancellationToken - Correctly cancelling and clearing a CancellationToken CancellationToken不取消所有任务 - CancellationToken is not cancelling all tasks 如何在 C# 3.1 网络核心中测试用户请求取消(HttpClient CancellationToken 似乎总是从 3.1 开始抛出) - How to test user request cancellation in C# 3.1 net core (HttpClient CancellationToken seems to be always throwing since 3.1) 取消CancellationToken会导致CancellationToken异常吗? - Does cancelling a CancellationToken cause a CancellationToken Exception? 检查 CancellationToken 是否已被取消 - Check if CancellationToken has been cancelled Nancy的CancellationToken来自异步请求处理程序来自何时取消? - Where is Nancy's CancellationToken for async Request Handlers coming from and when is it cancelled? .NET中终结器的HttpClient请求 - HttpClient request in finalizer in .NET 使用方法使用CancellationToken取消Parallel.For - Cancelling Parallel.For with CancellationToken using method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM