动态更改.NET中的HttpClient.Timeout

问题描述 投票:0回答:4

我需要在发出请求后更改

HttpClient.Timeout
属性。当我尝试时,我遇到了异常:

该实例已启动一个或多个请求。属性只能在发送第一个请求之前修改。

有什么办法可以避免这种情况吗?

c# .net timeout dotnet-httpclient
4个回答
19
投票

在内部,

Timeout
属性用于设置
CancellationTokenSource
,当达到超时时,它将中止异步操作。由于
HttpClient
方法的某些重载接受
CancellationTokens
,我们可以创建辅助方法来为特定操作设置自定义超时:

public async Task<string> GetStringAsync(string requestUri, TimeSpan timeout)
{
    using (var cts = new CancellationTokenSource(timeout))
    {
        HttpResponseMessage response = await _httpClient.GetAsync(requestUri, cts.Token)
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsStringAsync();
    }
}

12
投票

你无能为力改变这一点。这只是 HttpClient 实现中的默认行为。

在调用 GetRequestStream 或 GetResponse 方法之前必须设置 Timeout 属性。 来自 HttpClient.Timeout 备注部分

为了更改超时,最好创建 HttpClient 的新实例。

client = new HttpClient();
client.Timeout = 20; //set new timeout

6
投票

缺乏对自定义请求级别超时的支持一直是我心目中

HttpClient
的缺点。如果您不介意小的库依赖,Flurl.Http [免责声明:我是作者] 直接支持此:

"http://api.com/endpoint".WithTimeout(30).GetJsonAsync<T>();

这是真正的请求级设置;对同一主机的所有调用都在底层使用共享的

HttpClient
实例,并且具有不同超时的并发调用不会发生冲突。有一个可配置的全局默认值(最初为 100 秒,与
HttpClient
相同)。


0
投票

扩展@Monsignor的答案和@andrew-bennet的回复,这就是我解决它的方法:

  • 单独保留
    HTTPClient
    的超时(默认为 100 秒)或将其设置为比您需要的更大的值,因为它无法更改。
  • 使用
    HTTPClient
    和自定义
    CancellationToken
    以及您想要的超时来拨打所有电话。
public class RestService : IRestService
{
    protected readonly HttpClient Client;
    protected static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(5);

    public async Task<T> GetAsync<T>(string uri, TimeSpan? customTimeOut = null)
    {
[...]
        CancellationToken cancellationToken = GetCancellationToken(customTimeOut);

        try
        {
                response = await Client.GetAsync(uri, cancellationToken);
        }
[...]
        return result;
    }
[...]
    private static CancellationToken GetCancellationToken(TimeSpan? customTimeOut)
    {
        CancellationTokenSource cts = customTimeOut.HasValue
            ? new CancellationTokenSource(customTimeOut.Value)
            : new CancellationTokenSource(DefaultTimeout);
        CancellationToken cancellationToken = cts.Token;
        return cancellationToken;
    }
}

也许您可以重复使用

CancellationTokenSource
,但我不想让示例进一步复杂化。

© www.soinside.com 2019 - 2024. All rights reserved.