Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should we use Singletons for clients derived from Microsoft.Rest.ServiceClient in C#?

When working with Azure .NET SDKs generated from swagger specs (such as those associated with Azure Resource Manager) the resulting libraries leverage the Microsoft AutoRest Client Runtime and the various "Clients" all inherit from "ServiceClient".

We've been working with DocumentDB Client, and reading a lot about issues with using the native HttpClient in .NET. Microsoft suggests using singleton patterns for both of these clients because of how they work internally, despite the well-known issues with using the singleton pattern. In these cases, it is necessary.

As a result, we've developed a strategy for using and managing singletons for these cases, so we want to know if we should use the same strategy for the Azure REST clients derived from ServiceClient. If it uses HttpClient it would make sense.

Note: This question isn't a question looking for general developer advice about singletons or clients, but rather a specific question for the Microsoft dev teams associated with the AutoRest client runtime based on knowledge of it's inner-workings.

like image 785
solvingJ Avatar asked Apr 19 '17 00:04

solvingJ


3 Answers

I've been trying to solve this same issue. I'm using a number of autorest service clients, but have to re-instantiate them every request to pass user-specific client credentials. With Microsoft.Rest.ClientRuntime 2.3.6 you can now instantiate a ServiceClient with your own HttpClient. This allows me to use a transient ServiceClient with a singleton HttpClient. I simply added a new constructor to the generated autorest client.

public partial class MyClient : ServiceClient<IMyClient>, IMyClient
{

    public MyClient(Uri baseUri, ServiceClientCredentials credentials, HttpClient client) : base(client)
    {
        if (baseUri == null)
        {
            throw new ArgumentNullException("baseUri");
        }
        if (credentials == null)
        {
            throw new ArgumentNullException("credentials");
        }

        this.Initialize();
        this.Credentials = credentials;
        Credentials?.InitializeServiceClient(this);
        this.BaseUri = baseUri;

    }
    [...]
}

This, however, would result in an ObjectDisposedException after the first request. This is because the ServiceClient disposes HttpClients, regardless if you passed it in or not. method

protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        _disposed = true;

        // Dispose the client
        HttpClient.Dispose();
        HttpClient = null;
        FirstMessageHandler = null;
        HttpClientHandler = null;
    }
}

I simply overrode the Dispose method in 'MyClient' to do nothing since the only object getting disposed is the HttpClient.

protected override void Dispose(bool disposing) { }

I haven't noticed any fallout from this as the FirstMessageHandler and HttpClientHandler are only instantiated when ServiceClient creates the HttpClient for you. This approach has allowed me to use a single HttpClient across multiple AutoRest generated ServiceClients with custom user credentials on each request.

I'd be interested to see if anyone sees any fallout from this approach.

like image 69
Mike H Avatar answered Oct 08 '22 19:10

Mike H


Yes and no. :-) You don't need to use the Singleton design pattern, but it is advisable to share ServiceClient-derived instances wherever possible since each one encapsulates an HttpClient.

For some Azure libraries, sharing a single client isn't always possible. For example, the SearchIndexClient in the Azure Search library can only target one index at a time, so if your app uses multiple indexes you'll need to pool them somehow. Here is a related question on this topic which has links to other discussions elsewhere.

like image 39
Bruce Johnston Avatar answered Oct 08 '22 19:10

Bruce Johnston


You can now share HttpClient instances beyween instances of ServiceClient, so there is no longer a large reason to use a singleton pattern

like image 1
Mark Cowlishaw - MSFT Avatar answered Oct 08 '22 20:10

Mark Cowlishaw - MSFT