Deploying HttpClient Singleton in ASP.NET MVC

After reading this blog post and this official www.asp.net note:

HttpClient is designed to instantiate and reuse the life of the application. Especially in server applications, creating a new HttpClient instance for each request will exhaust the number of sockets available under heavy loads. This will result in a SocketException Error.

I found that our code deleted the HttpClient for each call. I am updating our code to reuse HttClient, but I am interested in implementation, but not in streaming mode.

Here is the current draft of the new code:

To test the modules, we used the shell for HttpClient, consumers call the shell:

public class HttpClientWrapper : IHttpClient { private readonly HttpClient _client; public Uri BaseAddress { get { return _client.BaseAddress; } set { _client.BaseAddress = value; } } public HttpRequestHeaders DefaultRequestHeaders { get { return _client.DefaultRequestHeaders; } } public HttpClientWrapper() { _client = new HttpClient(); } public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, String userOrProcessName) { IUnityContainer container = UnityCommon.GetContainer(); ILogService logService = container.Resolve<ILogService>(); logService.Log(ApplicationLogTypes.Debug, JsonConvert.SerializeObject(request), userOrProcessName); return _client.SendAsync(request); } #region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing && _client != null) { _client.Dispose(); } disposedValue = true; } } public void Dispose() { Dispose(true); } #endregion } 

Here is the service that calls:

 public class EnterpriseApiService : IEnterpriseApiService { private static IHttpClient _client; static EnterpriseApiService() { IUnityContainer container = UnityCommon.GetContainer(); IApplicationSettingService appSettingService = container.Resolve<IApplicationSettingService>(); _client = container.Resolve<IHttpClient>(); } public EnterpriseApiService() { } public Task<HttpResponseMessage> CallApiAsync(Uri uri, HttpMethod method, HttpContent content, HttpRequestHeaders requestHeaders, bool addJsonMimeAccept = true) { IUnityContainer container = UnityCommon.GetContainer(); HttpRequestMessage request; _client.BaseAddress = new Uri(uri.GetLeftPart(UriPartial.Authority)); if (addJsonMimeAccept) _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); request = new HttpRequestMessage(method, uri.AbsoluteUri); // Removed logic that built request with content, requestHeaders and method return _client.SendAsync(request, UserOrProcessName); } } 

My questions:

  • Is this a suitable approach for reusing an HttpClient object?
  • Is the _httpClient static field (populated with a static constructor) common to all instances of EnterpriseApiService? I wanted to confirm, as called by instance methods.
  • When CallApiAsync () is called, when it makes a change to the static HttpClient, for example, "_client.DefaultRequestHeaders.Accept.Add (new MediaTypeWithQualityHeaderValue (" application / json ")), can these values ​​be overwritten by another process before the last line of" _client. Is SendAsync called? I'm concerned that halfway through CallApiAsync () processing, the static instance is being updated.
  • Since it calls SendAsync (), is the answer guaranteed to the correct answer? I want to confirm that the answer does not transfer to another subscriber.

Update: Since I deleted USING statements and the Garage Collection does not call Dispose, I'm going to move on to a safer approach to creating a new instance inside the method. To reuse an instance of HttpClient even during the life cycle of a stream, this will require significant processing of the logic, because the method sets the HttpClient properties for each call.

+5
source share
3 answers

Do you really need one copy?

I do not think you need one instance of the application. You need one instance for the stream. Otherwise, you will not get very good performance! In addition, this will solve your issues # 3 and # 4, since neither of the two threads will access the same HttpClient at the same time.

You don't need a singleton

Just use Container.Resolve with PerThreadLifetimeManager .

+2
source

Since it calls SendAsync (), is the answer guaranteed to the correct answer? I want to confirm that the answer does not go to another caller.

This will be handled using callback pointers. This has nothing to do with using HttpClient as a singleton. Read more here - fooobar.com/questions/59420 / ...

0
source

For those who are fortunate enough to use the .NET Core , it's pretty simple.

As John Wu so eloquently stated, you do not want a single title per se, but rather a single single per request. So the AddScoped<TService>() method is what you need.

In your ConfigureServices(IServiceCollection services) method:

 services.AddScoped<HttpClient>(); 

Consumption:

 public class HomeController { readonly HttpClient client; public HomeController (HttpClient client) { this.client = client; } //rest of controller code } 
0
source

Source: https://habr.com/ru/post/1258732/


All Articles