One httpClient for many method in one class - c#

I would like to use one httpclient to many method in class.
Below is the simplified code:
public class test{
private readonly HttpClient _httpClient;
public Test(){
_httpClient = new HttpClient();
}
public void method1(){
using (_httpClient){
//...
}
}
public void method2(){
using (_httpClient){
//...
}
}
public void method3(){
using (_httpClient){
//...
}
}
}
Then it calls the method data:
public async static void TestHttpClient()
{
Test test1 = new Test();
test1.Method1();
test1.Method2();
test1.Method3();
}
Method 1 is working. When calling the second one I get the message: "You cannot access a deleted object."
Thanks for helps.
Regards

using calls the Dispose() method after the scope - which destroys the object - keep the instance of your HttpClient within the instance of your object
public class test : IDisposable
{
private readonly HttpClient _httpClient;
public test()
{
_httpClient = new HttpClient();
}
public void Dispose()
{
_httpClient.Dispose();
}
public void method1()
{
//...
}
}
then you can dispose your object instead of the HttpClient
using(test myObject = new test())
{
myObject.method1();
myObject.method2();
}

If you want Test to create and reuse a disposable resource (e.g. HttpClient, then Test should implement IDisposable and should dispose of the resource in its Dispose method. That means that the class using Test should use a using block:
public async static void TestHttpClient()
{
using (Test test1 = new Test())
{
test1.Method1();
test1.Method2();
test1.Method3();
}
}

One way to do it is to create a private variable and a get accessor
private HttpClient _httpClient;
private HttpClient MyClient
{
get {
if (_httpClient == null)
{
_httpClient = new HttpClient
{
BaseAddress = new Uri($"https://your.url/")
};
//Other client logic goes here
}
return _httpClient;
}
}
Then from your method, you just reference the accessor
public async Task method1()
{
await MyClient.Post() //post logic here
//...
}
You don't need to dispose HttpClient, MS recommends leaving the object in place, unless you know you need to forcibly close the connection.

Related

Passing IHttpClientFactory into class

If I have a controller class, and I want to pass it to a different namespace that handles my HTTP calls, such as in the below scenario, Main task calls TaskA() which calls TaskG(), do I need to pass it to TaskG via A like the below? Or is there someway to just create it in the namespace HttpClassFurtherDown without the calling classes needing to pass it.
namespace Controllers{
public class Drawings : ControllerBase
{
private IHttpClientFactory _client {get;set;}
public Drawings(IHttpClientFactory client)
{
_client=client;
}
[Route("api/Drawings")]
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] JsonFileContent[] content)
{
HttpExample e = new HttpExample(_client);
e.TaskA();
TaskB();
return Accepted($"Drawings/Job/{id}");
}
}}
namespace HttpClassExample{
public class HttpExample
{
private IHttpClientFactory _client {get;set;}
public HttpExample(IHttpClientFactory client)
{
_client=client;
}
public void TaskA()
{
DoSomeProcessing();
HttpClassExampleFurtherDown e = new HttpClassExampleFurtherDown(client);
e.TaskG();
}
}
}
namespace HttpClassExampleFurtherDown{
public class HttpExampleFurtherDown
{
private IHttpClientFactory _client {get;set;}
public HttpExampleFurtherDown(IHttpClientFactory client)
{
_client=client;
}
public void TaskG(client)
{
//Finally Using It Here. I want to avoid having to generate it at the controller level and pass it all the way down.
client.CreateClient();
client.SendAsync();
}
}
}
I want to avoid having to generate it at the controller level and pass it all the way down.
If following DIP then inject explicit dependencies where they are actually needed instead of tightly coupling to implementation concerns.
While I believe the example provided are oversimplified, here is what the example above should look like
Controllers.Drawings
namespace Controllers{
using HttpClassExample;
//...
public class Drawings : ControllerBase {
private readonly IHttpExample client;
public Drawings(IHttpExample client) {
this.client = client;
}
[Route("api/Drawings")]
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] JsonFileContent[] content) {
await client.TaskA();
TaskB();
return Accepted($"Drawings/Job/{id}");
}
}
}
HttpClassExample.HttpExample
namespace HttpClassExample{
using HttpClassExampleFurtherDown;
//...
public class HttpExample : IHttpExample{
private readonly IHttpExampleFurtherDown client;
public HttpExample(IHttpExampleFurtherDown client) {
this.client = client;
}
public async Task TaskA() {
DoSomeProcessing();
await client.TaskG();
}
//...
}
}
HttpClassExampleFurtherDown.HttpExampleFurtherDown
namespace HttpClassExampleFurtherDown{
public class HttpExampleFurtherDown : IHttpExampleFurtherDown {
private readonly IHttpClientFactory factory;
public HttpExampleFurtherDown(IHttpClientFactory factory) {
this.factory = factory;
}
public async Task TaskG() {
HttpClient client = factory.CreateClient();
//...
var response = await client.SendAsync();
//...
}
}
}
This assumes that a container is being used to manage the resolution and injection of dependency implementations based on their registered abstractions

How to set a readonly property in a C# async constructor

I have a service in an ASP .Net Core 2.2 Web API. The constructor is async because it calls an async method. But because the constructor is async, it's complaining about trying to initialize a property.
public class MyService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public async Task MyService(IServiceScopeFactory serviceScopeFactory)
{
this._serviceScopeFactory = serviceScopeFactory;
await DoSomething();
}
}
It gives me this error:
"A readonly field cannot be assigned to (except in a constructor or a variable initializer)"
Any ideas?
As users mentioned in the comments above, I was mistaken to think that I could make a constructor async.
Mathew Watson and Stephen Cleary provided me with a link with a good alternative to my problem: https://blog.stephencleary.com/2013/01/async-oop-2-constructors.html
Summary:
Factory Pattern
Use a static creation method, making the type its own factory:
public sealed class MyClass
{
private MyData asyncData;
private MyClass() { ... }
private async Task<MyClass> InitializeAsync()
{
asyncData = await GetDataAsync();
return this;
}
public static Task<MyClass> CreateAsync()
{
var ret = new MyClass();
return ret.InitializeAsync();
}
}
public static async Task UseMyClassAsync()
{
MyClass instance = await MyClass.CreateAsync();
...
}
One common example to solve your problem is to create a static method on the class and call the async method from there and well as the constructor.
public class MyService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public static async Task<MyService> BuildMyService(IServiceScopeFactory serviceScopeFactory)
{
await DoSomething();
return new MyService(serviceScopeFactory);
}
public MyService(IServiceScopeFactory serviceScopeFactory)
{
this._serviceScopeFactory = serviceScopeFactory;
}
}

Set a default header to each http client call

I want to set a default header for every method in the UserHttpClient but I don`t want that every method is doing that, I want to do it in a general way.
The problem I see with the current implementation is, that when I call one method the _client gets disposed thus at the next call within a Http Request the _client is not initialized, as this happens within the constructor.
The UserHttpClient is registered via DI as per Http Request.
I also do not want to create a private/base method where I pass the _client and do the header addition there.
How would you solve that problem?
public class UserHttpClient : IUserRemoteRepository
{
private readonly string baseUrl = ConfigurationManager.AppSettings["baseUrl"];
private readonly string header = ConfigurationManager.AppSettings["userHeader"];
private readonly HttpClient _client;
public ServiceProductDataProvider(string toolSystemKeyHeader)
{
_client = new HttpClient();
_client.DefaultRequestHeaders.Add(header, token);
}
public async Task<List<UserDto>> GetUsers(UserRequestDto dto)
{
using (_client)
{
// do stuff
var users = await _client.GetAsync("url here");
}
}
public async Task<UserDto> GetUser(Guid userId)
{
using (_client)
{
// do stuff
var users = await _client.GetAsync("url here");
}
}
}
The class UserHttpClient has a member that is IDisposable (private readonly HttpClient _client;). That means that the UserHttpClient should also implement IDisposable:
public void Dispose()
{
_client.Dispose();
}
Then, the class/code that is using UserHttpClient is responsible for Disposing it after it's done with it. If the instance is injected, then the DI framework you use probably handles disposing it automatically at the end of the request. What's left for you then is to simply remove the using blocks from the implementation:
public async Task<List<UserDto>> GetUsers(UserRequestDto dto)
{
// do stuff
var users = await _client.GetAsync("url here");
}
---- EDIT ----
You could also work around the issue by not reusing the HttpClient:
private string _toolSystemKeyHeader;
public ServiceProductDataProvider(string toolSystemKeyHeader)
{
_toolSystemKeyHeader = toolSystemKeyHeader
}
private HttpClient GetClientInstance()
{
HttpClient _client = new HttpClient();
_client.DefaultRequestHeaders.Add(header, _toolSystemKeyHeader); //?? in your original code, the toolSystemKeyHeader is not used, but I guess it is the token..?
return _client;
}
And:
public async Task<List<UserDto>> GetUsers(UserRequestDto dto)
{
using (var _client = GetClientInstance())
{
// do stuff
var users = await _client.GetAsync("url here");
}
}

CA1001 Types that own disposable fields should be disposable over HttpClient

I have a HttpClientWrapper class to bring unit testability over my classes which are making HttpCalls.
This class is injected via IoC, and acts as a singleton. Because I would like to use same HttpClient instance over and over again without disposing it.
Do HttpClient and HttpClientHandler have to be disposed?
public class HttpClientWrapper : IHttpClientWrapper
{
readonly HttpClient _client;
public HttpClientWrapper()
{
_client = new HttpClient();
}
public Uri BaseAddress
{
get { return _client.BaseAddress; }
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage message)
{
Task<HttpResponseMessage> sendAsync = _client.SendAsync(message);
return sendAsync;
}
}
Following clears the warning naturally.
public class HttpClientWrapper : IHttpClientWrapper, IDisposable
{
readonly HttpClient _client;
public HttpClientWrapper()
{
_client = new HttpClient();
}
public Uri BaseAddress
{
get { return _client.BaseAddress; }
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage message)
{
Task<HttpResponseMessage> sendAsync = _client.SendAsync(message);
return sendAsync;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_client != null)
{
_client.Dispose();
}
}
}
When I run code analysis, I am receiving following warning from IDE.
CA1001 Types that own disposable fields should be disposable Implement
IDisposable on 'HttpClientWrapper' because it creates members of the
following IDisposable types: 'HttpClient'. If 'HttpClientWrapper' has
previously shipped, adding new members that implement IDisposable to
this type is considered a breaking change to existing consumers.
So am I missing something here? Since I would like to keep only one instance of HttpClient and would like not to dispose it, can I safely surpress the warning?
Does second version of class implementation makes sense?

Refactoring class to make it injectable/mockable

I am really struggling to properly refactor my class so I can inject it.
This is the class I am talking about:
internal class OCRService : IDisposable, IOCRService
{
private const TextRecognitionMode RecognitionMode = TextRecognitionMode.Handwritten;
private readonly ComputerVisionClient _client;
public OCRService(string apiKey)
{
_client = new ComputerVisionClient(new ApiKeyServiceClientCredentials(apiKey))
{
Endpoint = "https://westeurope.api.cognitive.microsoft.com"
};
}
public async Task<List<Line>> ExtractTextAsync(byte[] image)
{
//Logic with _client here
}
}
I really don't know where to Initialize the ComputerVisionClient. I am thinking of the following options:
Make ComputerVisionClient a public property which can be set after injecting.
Putting the apikey in a config file and then read it in the constructor.
The problem is that I want to mock this service but when I mock it it still calls the constructor which connects to the ComputerVisionClient.
Depending on the rest of your architecture, you have a few options. The simplest is to inject the ComputerVisionClient (or IComputerVisionClient if you can create one) into the constructor, and mock it in your tests.
public class OCRService : IOCRService, IDisposable
{
public OCRService(IComputerVisionClient client)
{
_client = client;
}
}
If, for some reason, you must create the client in the constructor, you can create a factory and inject that:
internal class ComputerVisionClientFactory : IComputerVisionClientFactory
{
public GetClient(string apiKey)
{
return new ComputerVisionClient(new ApiKeyServiceClientCredentials(apiKey))
{
Endpoint = "https://westeurope.api.cognitive.microsoft.com"
};
}
}
// ...
internal class OCRService : IOCRService, IDisposable
{
public OCRService(string apiKey, IComputerVisionClientFactory clientFactory)
{
_client = clientFactory.GetClient(apiKey);
}
}
As #maccettura suggested, you can also further abstract away the apiKey by creating an IOCRServiceConfiguration that contains the logic for getting the key, and pass that into the constructor for either OCRService or ComputerVisionFactory, depending on your architecture. Naively:
internal class OCRServiceConfiguration : IOCRServiceConfiguration
{
public OCRServiceConfiguration(string apiKey)
{
ApiKey = apiKey;
}
public string ApiKey { get; }
}

Categories

Resources