我正在.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)
{ ....
这里是构造函数:
private readonly HttpClient _httpClient;
public UserRepository(HttpClient httpClient)
{
_httpClient = httpClient;
}
方法调用:
var user1 = AddUser("user@user.com");
var user2 = AddUser("test@test.com");
await Task.WhenAll(user1, user2);
这是启动配置:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
那我做错了什么?我需要用AddTransient()更改AddSingleton还是有其他问题。响应后,我还需要使用_client.Dispose()另一个问题,因为我遵循的教程没有使用dispose方法,因此我对此不太困惑。
答案 0 :(得分:11)
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);
用您的JSON替换"{...}"
。
答案 1 :(得分:9)
也许我的两分钱会帮助某人。
调试应用程序时刷新页面时遇到了这个问题。
我使用的是单例,但是每次刷新时,它都试图设置基址。因此,我只是将其包装在检查中,以查看是否已设置基本地址。
对我来说,问题是,即使已设置baseAddress,它也在尝试设置baseAddress。您无法使用httpClient进行此操作。
if (_httpClient.BaseAddress == null)
{
_httpClient.BaseAddress = new Uri(baseAddress);
}
答案 2 :(得分:0)
此问题是由于为httpclient的同一实例重置BaseAddress和标头引起的。
我尝试过
if (_httpClient.BaseAddress == null)
但是我对此并不热衷。
我认为,更好的选择是使用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
}
答案 3 :(得分:0)
当您在消息而不是在客户端添加请求 url 和标头时,它工作得很好。所以最好不要分配给 BaseAddress
或标头 DefaultRequestHeaders
,如果您将它们用于许多请求。
HttpRequestMessage msg = new HttpRequestMessage {
Method = HttpMethod.Put,
RequestUri = new Uri(url),
Headers = httpRequestHeaders;
};
httpClient.SendAsync(msg);