Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best approach to define an HttpClient instance in a base class of a class library project?

There is an application which has 3 interfaces and whoever wants to use this app needs to implement these interfaces. I have created a class library project which has these interface implementations that I have inherited all from the same base class to be able to have a single HttpClient. Here is what I have done so far:

    public class BaseProxy
    {
        protected static readonly HttpClient Client;

        static BaseProxy()
        {
            Client = new HttpClient();
        }
    }

and I have used this Client in all derived classes to make GetAsync and PostAsync requests as follows:

    public class XProxyImplementation
    {
        var response = Client.GetAsync(BaseUrl + "XXXApi/GetClientSettings/").Result;
        response.EnsureSuccessStatusCode();
    }

None of the methods in Web API are async by the way and I chose singleton solution because I don't want to use using block for each request. My question is should I go for a DI solution or is this code enough for an app which will be used internally? All suggestions for improvement are welcome.

I have read many answers regarding to using DI containers but this is just a class library with proxy implementations.

My other concern is even if I want to use DI, currently I am not able to introduce DI in my constructor classes because the other application that uses my implementations is looking for an empty constructor. When I try to pass HttpClient parameter to the constructor I get the following error:

The current type, System.Net.Http.HttpMessageHandler, is an abstract class and cannot be constructed

The application which uses my dlls doesn't allow me to pass any parameters to constructor that uses any abstract classes. I guess this application uses Unity to make the handshake and in some way it looks for an empty constructor. Once I try to do the following changes I am getting the error:

        public BaseProxy() : this(Service.HttpClient)
        {
        }

        public XProxyImplementation(HttpClient client) : base(client)
        {
        } 

That's why I actually prefered singleton instance to DI implementation.

like image 994
utaco Avatar asked Oct 27 '22 10:10

utaco


1 Answers

DI? Yes

DI will enable testability of your proxy classes, whereas your current implementation cannot be unit-tested. It will also improve separation of concerns: remove the responsibility of controlling HttpClient lifetime from the proxy.

Typically, you would do something like this:

public abstract class BaseProxy
{
    protected readonly HttpClient Client;

    protected BaseProxy(HttpClient client)
    {
        Client = client;
    }

    // ... other members
}

public class XProxyImplementation : BaseProxy
{
    public XProxyImplementation(HttpClient client) : base(client)
    {
    }

    // ... other members

    public Task SendRequest() // for example
    { 
         return Client.GetAsync("....");
    }
}

During the tests, you would initialize a different instance of HttpClient, injecting a test-friendly implementation of HttpMessageHandler:

// you implement TestHttpMessageHandler that aids your tests
var httpClient = new HttpClient(new TestHttpMessageHandler());
var proxyUnderTest = new XProxyImplementation(httpClient);

See this blog post for explanation of unit testing with HttpClient and HttpMessageHandler.

DI container? No

Now that we introduced dependency injection into your code, next question is, what injection mechanism should be used.

In your specific case, I would vote against coupling to any specific DI container, because you want your library to be consumed by many different applications, and you don't want to bloat their dependencies (an application might already be using a different DI container).

Moreover, since the code you posted is very simple, a full-blown DI container would be an overkill. In production code, you can just move your singleton HttpClient to a "service locator":

public static class SingletonServices
{
    public static readonly HttpClient HttpClient;

    static SingletonServices()
    {
        HttpClient = new HttpClient();
    }
}

So that when you instantiate a proxy in production code, you do this:

var proxy = new XProxyImplementation(SingletonServices.HttpClient);
like image 87
felix-b Avatar answered Nov 15 '22 06:11

felix-b