Throwing exception in the singleton pattern in C#
The initialize dance is not nice. Requires the caller to keep track of if it has been called etc. Pit of failure.
The IsInitialized() is not very useful as it is now as there no way to lock over check and initialize. There will always be a risk that another thread calls Initialize between the check IsInitialized and the call to Initialize.
I have not used HttpClient much but my gut feeling is that the locking is not needed.
A singleton will make it hard to mock in tests. What about writing it like this:




public class AssetSyncServiceClientSettings
{
    public string BaseUrl { get; set; }
    public bool JsonOnly { get; set; }
}

public interface IAssetSyncServiceClient : IDisposable
{
    // Picked a sample method randomly, you can expose an api that makes sense in your app/lib
    Task&lt;string&gt; GetStringAsync(string requestUri);
}

public sealed class AssetSyncServiceClient : IAssetSyncServiceClient
{
    private readonly HttpClient _client;
    private bool _disposed;

    public AssetSyncServiceClient(AssetSyncServiceClientSettings settings)
    {
        _client = new HttpClient();
        _client.BaseAddress = new Uri(settings.BaseUrl);

        if (settings.JsonOnly)
        {
            _client.DefaultRequestHeaders.Accept.Clear();
            _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }
    }

    public Task&lt;string&gt; GetStringAsync(string requestUri)
    {
        VerifyNotDisposed();
        return _client.GetStringAsync(requestUri);
    }

    public void Dispose()
    {
        if (_disposed)
        {
            return;
        }

        _disposed = true;
        _client.Dispose();
    }

    private void VerifyNotDisposed()
    {
        if (_disposed)
        {
            throw new ObjectDisposedException(this.GetType().FullName);
        }
    }
}



Doing it like this avoids initialization. If you need it lazy for some reason the service could handle it internally.
An interface probably makes sense for this so you can mock it in tests.
Use the Dependency Injection container to make the service a singleton instance.
Pass in the service interface in to constructors where it is needed. It makes the dependency explicit and makes it easy to mock in tests.
The settings object can perhaps contain urls so that the service can expose methods like public async Task&lt;Stuff&gt; GetStuffAsync()