2

Scenario

I am trying to change my existing HttpClient to IHttpClientFactory. When I verified the existing code, its using using{...} statement which causes issues and it is mentioned here. So I thought of implementing singleton Http client and reached another blog related to this and it is here.

From all these, I understood that the best one is IHttpClientFactory introduced in .NET Core.

Implementation Plan

As this application is in ASP.NET MVC 4 and does not use DI, I have to do something to use without the DI framework. Based on my search, got answers from StackOverflow and planned to implement the same way. Meanwhile, I also got another project, which already removed all the dependencies and is ready to use in earlier projects without doing all things. The repo is HttpClientFactoryLite.

Question

Now I can use HttpClientFactoryLite by initializing this class? The description also mentioned it can be used along with the existing DI framework so that ClientFactory can be registered as a singleton. Please find the wordings from the readme

using HttpClientFactoryLite;

var httpClientFactory = new HttpClientFactory(); //bliss

If you are using dependency injection, make sure that IHttpClientFactory is registered as a singleton.

In my scenario, I don't have any DI framework added. So I am going to initialize the factory wherever I needed. Here I am confused that in 2 things

  1. Is it necessary to make a singleton class for HttpClientFactoryLite?

  2. How is this HttpClientFactory class disposed? Is there a need to dispose of it as part of the controller or same using statement etc?

  3. Based on the answer from this, Microsoft.Extensions.Http provides the HttpClientFactory only, not the new optimized HttpClient. This is only available in .NET Core 2.1. So any difference in implementing IHttpClientFactory?

Please advise

Akhil
  • 1,918
  • 5
  • 30
  • 74
  • Just call `AddHttpClient` on the service collection, you don't need a *DI framework* or any other third-party library (potentially just an MS nuget) if you are not in core. From there you can just create a singleton for `httpclientfactory` if you need. or even easier just put `IHttpClientFactory` in your constructor when you want to use it – TheGeneral Aug 13 '20 at 07:36
  • @MichaelRandall Thank you for the response. So you mean I need to create Singleton class implementation for HttpClientFactory as I am not using any DI framework? – Akhil Aug 13 '20 at 09:02
  • @Akhil I humbly suggest you, you just write a static wrapper class for HttpClient, if your requirements are basic. – Safak Ulusoy Aug 13 '20 at 10:32
  • @SafakUlusoy hmm seems ok. But I just want to understand the new factory as well – Akhil Aug 13 '20 at 10:38

1 Answers1

4

ASP.NET 3.1:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddSingleton<IHttpClientFactory, HttpClientFactory>();
}

ASP.NET will automatically pass the correct singleton to controllers which demand an IHttpClientFactory in their constructor.


Poormans variation without DI-Container:

public static class Singleton<TInterface> 
{
    private static TInterface instance;
    public static TInterface Instance
    { 
        get => instance;
        private set => instance ??= value;
    }

    public static void Add<TConcrete>() where TConcrete : TInterface, new()
        => Instance = new TConcrete();

    public static void Add<TConcrete>(TConcrete instance) where TConcrete : TInterface
        => Instance = instance;

    // put dispose logic if necessary
}

Usage:

// Application Entrypoint
Singleton<IHttpClientFactory>.Add<HttpClientFactory>();

// Class/Controller Property
private readonly IHttpClientFactory httpClientFactory 
    = Singleton<IHttpClientFactory>.Instance;
Purity
  • 331
  • 1
  • 8
  • Hi, thanks this is fine in dot net core. I asked how this achieved in asp.net MVC 4 and not used any DI framework? – Akhil Aug 13 '20 at 10:30
  • 1
    The second part of my answers covers how to do this yourself with an ASP.NET version that doesn't integrate DI and without a DI-Framework. Just copy and paste the static Singleton class and use it as shown under 'Usage:'. – Purity Aug 13 '20 at 10:48
  • Looks good. I will check thank you. So I need Singleton configuration in the Global.asax. Is my understanding right? As I am using IHttpClientFactory, dispose not needed (my assumption). is this right? Also just want to confirm, is this thread-safe – Akhil Aug 13 '20 at 10:54
  • 1
    With the provided code you don't need any further configuration for the singleton. As IHttpClientFactory does not implement IDisposable, you don't need any disposal logic. – Purity Aug 13 '20 at 10:56
  • Thanks. Will check in the code. Could you check my third question? Any comments on that. Or can I use the regular HttpClient by using this approach? – Akhil Aug 13 '20 at 11:01
  • 1
    Yes, static initialization is thread-safe in C# and the setter doesn't assign anything if not null. If you want to be ultra-sure, you can refactor the "Instance" property in a nested static class and assign once upon that class-initalization. I wouldn't bother though, this is fine. – Purity Aug 13 '20 at 11:03
  • Thanks. just comment on my question 3. Which one you prefer – Akhil Aug 13 '20 at 11:08
  • 1
    Go with the HttpClientFactory of your HttpClientFactoryLite package with my provided code - as the mentioned issues with HttpClient were the reason you wanted to change this in the first place. :) – Purity Aug 13 '20 at 11:32
  • Coukd rewrite the colaesing assignmnet in c# 7.3 – Akhil Aug 13 '20 at 14:10
  • 1
    private set => instance = instance ?? value; - you are reassigning the same instance whenever this is set again, but that shouldn't happen anyway and it's shorter. Alternatively you can just write it the long way: private set { if (instance == null) { instance = value; } } – Purity Aug 13 '20 at 14:22
  • I wrote like that. Just want to confirm. thanks for the help – Akhil Aug 17 '20 at 07:56
  • @Purity static initialization is thread-safe in C# if you provide a public static constructor. read this great Jon Skeet post: https://csharpindepth.com/Articles/Singleton#lazy – giammin Jun 14 '21 at 09:49