c# - .NET HttpClient - 取消 CancellationToken 不取消请求

原文 标签 c# .net dotnet-httpclient cancellation

我遇到了 .NET HttpClient 的问题类(.NET 4.5.1,System.Net.Http v4.0.0.0)。我调用 HttpClient.GetAsync ,传入 CancellationToken (作为抽象 Web 服务之间调用的 Nuget 包的一部分)。如果在进行调用之前 token 已被取消,则请求将通过而不会引发异常。这种行为似乎不正确。

我的测试(不完整,未完全编写 - 无异常检查):

[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);
}

我正在测试的方法:
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;
    }
}

我知道我可以在调用 HttpClient.GetAsync 之前检查取消 token 的状态如果已请求取消,则抛出。我知道我也可以注册一个委托(delegate)来取消 HttpClient 请求。但是,似乎将 token 传递给 HttpClient 方法应该为我解决这个问题(或者,否则,有什么意义?)所以我想知道我是否遗漏了一些东西。我无权访问 HttpClient源代码。

为什么是 HttpClient.GetAsync不检查我的取消 token 并在我传递它时中止它的过程?

最佳答案

HttpClient不检查取消 token 本身,它在调用它的 SendAsync 时将其传递给消息处理程序方法。然后它注册到从 SendAsync 返回的任务的延续。如果从消息处理程序返回的任务被取消,则将其自己的任务设置为已取消。

因此,您的方案中的问题在于您对 MockHttpMessageHandler 的实现。这似乎没有检查取消 token 。

请注意,如果 HttpClient通过它的空构造函数调用,它在内部使用 HttpClientHandler它在取消 token 上注册一个委托(delegate),以中止请求并取消任务。

关于c# - .NET HttpClient - 取消 CancellationToken 不取消请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34073104/

相关文章:

c# - MVC4 - Razor - 动态模块内容?

c# - 无法将Log4Net与.net Framework 4一起使用

c# - 为什么代码会生成称为<> c__DisplayClass1的MSIL类

c# - HttpClient.Timeout 和使用 WebRequestHandler 超时属性有什么区别?

c# - 不等待 HttpClient 使用时会发生什么

c# - 基于列内容和标题的ListView AutoResizeColumns

C#图表显示所有标签

c# - 从asp.net核心应用程序启动Linux进程失败(找不到文件)

c# - App.config 文件中的连接字符串,用于从本地计算机连接到 EC2 SQL Server 2008 R2

c# - ASP.NET Core 类型化客户端中的 IHttpClientFactory