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

Ask*_*Ask 13 c# asp.net httpclient dotnet-httpclient asp.net-core-2.0

我正在.Net Core 2.1中创建一个应用程序,我正在使用http客户端进行Web请求.问题是我必须发送并行调用来节省时间,为此我使用的是Task.WhenAll()方法但是当我点击这个方法时,我得到错误"这个实例已经启动了一个或多个请求.属性只能被修改在发送第一个请求之前"以前我使用的是RestSharp,一切都很好,但我想使用httpclient.这是代码:

public async Task<User> AddUser(string email)
{
    var url = "user/";
    _client.BaseAddress = new Uri("https://myWeb.com/");
    _client.DefaultRequestHeaders.Accept.Clear();
    _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(Constants."application/json"));
    _client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
    var json = new {email = email }
    var response = await _client.PostAsJsonAsync(url,json);
    if (response .IsSuccessStatusCode)
    { ....
Run Code Online (Sandbox Code Playgroud)

这是构造函数:

private readonly HttpClient _httpClient;

public UserRepository(HttpClient httpClient)
{         
    _httpClient = httpClient;
}
Run Code Online (Sandbox Code Playgroud)

方法调用:

var user1 = AddUser("user@user.com");
var user2 = AddUser("test@test.com");

await Task.WhenAll(user1, user2);
Run Code Online (Sandbox Code Playgroud)

这是启动配置:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Run Code Online (Sandbox Code Playgroud)

那么我做错了什么?我是否需要使用AddTransient()更改AddSingleton,还是有任何其他问题.还有一个问题我需要在响应之后使用_client.Dispose()因为我所遵循的教程没有使用dispose方法所以我对此感到困惑.

Geo*_*yar 26

HttpClient.DefaultRequestHeaders(和BaseAddress)只应在您提出任何要求之前设置一次.HttpClient如果您在使用时不进行修改,则只能安全地用作单身人士.

而不是设置DefaultRequestHeaders,在HttpRequestMessage您发送的每个上设置标题.

var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
request.Content = new StringContent("{...}", Encoding.UTF8, "application/json");
var response = await _client.SendAsync(request, CancellationToken.None);
Run Code Online (Sandbox Code Playgroud)

替换"{...}"为您的JSON.


tha*_*Guy 10

也许我的两分钱会帮助某人。

我在调试应用程序时刷新页面时遇到了这个问题。

我使用的是单例,但每次刷新时,它都试图设置基地址。所以我只是把它包裹在一个检查中,看看是否已经设置了基地址。

我的问题是,它试图设置 baseAddress,即使它已经设置。您不能使用 httpClient 执行此操作。

if (_httpClient.BaseAddress == null)
{
    _httpClient.BaseAddress = new Uri(baseAddress);
}
Run Code Online (Sandbox Code Playgroud)

  • 这实际上对我帮助很大,这正是我所面临的。 (2认同)

Mal*_*Tbt 6

该问题是由重置同一 httpclient 实例的 BaseAddress 和标头引起的。

我试过

if (_httpClient.BaseAddress == null) 
Run Code Online (Sandbox Code Playgroud)

但我对此并不热衷。

在我看来,更好的解决方案是使用httpclientFactory。这将在使用 httpclient 实例后终止并对其进行垃圾回收。

private readonly IHttpClientFactory _httpClientFactory;
public Foo (IHttpClientFactory httpClientFactory) 
{
_httpClientFactory = httpClientFactory;
}
public  httpresponse Bar ()
{
_httpClient = _httpClientFactory.CreateClient(command.ClientId);

using var response = await _httpclient.PostAsync(uri,content);
return response;
// here as there is no more reference to the _httpclient, the garbage collector will clean 
// up the _httpclient and release that instance. Next time the method is called a new 
// instance of the _httpclient is created
}

Run Code Online (Sandbox Code Playgroud)