title: Is it possible to inject IHttpClientFactory to a strongly typed client?
body: <p>As the heading tells.</p>
  
  <p>Let's say I register a strongly typed client like</p>
  
  <pre><code>var services = new ServiceCollection();
  
  //A named client is another option that could be tried since MSDN documentation shows that being used when IHttpClientFactory is injected.
  //However, it appears it gives the same exception.
  //services.AddHttpClient("test", httpClient =&gt; 
  services.AddHttpClient&lt;TestClient&gt;(httpClient =&gt;
  {
      httpClient.BaseAddress = new Uri("");                    
  });
  .AddHttpMessageHandler(_ =&gt; new TestMessageHandler());
  
  //Registering IHttpClientFactory isn't needed, hence commented.
  //services.AddSingleton(sp =&gt; sp.GetRequiredService&lt;IHttpClientFactory&gt;());
  var servicesProvider = services.BuildServiceProvider(validateScopes: true);
  
  public class TestClient
  {
      private IHttpClientFactory ClientFactory { get; }
      public TestClient(IHttpClientFactory clientFactory)
      {
          ClientFactory = clientFactory;
      }
  
      public async Task&lt;HttpResponseMessage&gt; CallAsync(CancellationToken cancellation = default)
      {
          //using(var client = ClientFactory.CreateClient("test")) 
          using(var client = ClientFactory.CreateClient())
          {
              return await client.GetAsync("/", cancellation);
          }
      }
  }
  
  // This throws with "Message: System.InvalidOperationException : A suitable constructor
  // for type 'Test.TestClient' could not be located. Ensure the type is concrete and services
  // are registered for all parameters of a public constructor.
  
  var client = servicesProvider.GetService&lt;TestClient&gt;();
  </code></pre>
  
  <p>But as noted in the comments, an exception will be thrown. Do I miss something bovious or is this sort of an arrangement not possible?</p>
  
  <p>&lt;edit: If <code>IHttpClientFactory</code> is registered, a <code>NullReferenceException</code> is thrown while trying to resolve <code>client</code>. Strange, strange.</p>
  
  <p>&lt;edit 2: The scenario I'm thinking to avoid is described and discussed also at <a href="https://github.com/aspnet/Extensions/issues/924" rel="nofollow noreferrer">https://github.com/aspnet/Extensions/issues/924</a> and maybe the way written there is one, perhaps not as satisfactory, way of avoiding some problems.</p>
  
  <p>This happens in a XUnit project, probably doesn't have anything to do with the problem, but who knows. :)</p>
  
  <p>&lt;edit 3: A console program to show the problem.</p>
  
  <pre><code>using Microsoft.Extensions.DependencyInjection;
  using System;
  using System.Net.Http;
  using System.Threading;
  using System.Threading.Tasks;
  
  namespace TypedClientTest
  {
  
  public class TestClient
  {
      private IHttpClientFactory ClientFactory { get; }
  
      public TestClient(IHttpClientFactory clientFactory)
      {
          ClientFactory = clientFactory;
      }
  
      public async Task&lt;HttpResponseMessage&gt; TestAsync(CancellationToken cancellation = default)
      {
          using (var client = ClientFactory.CreateClient())
          {
              return await client.GetAsync("/", cancellation);
          }
      }
  }
  
  class Program
  {
      static void Main(string[] args)
      {
          var services = new ServiceCollection();
  
          services
              .AddHttpClient&lt;TestClient&gt;(httpClient =&gt; httpClient.BaseAddress = new Uri("https://www.github.com/"));
  
          var servicesProvider = services.BuildServiceProvider(validateScopes: true);
  
          //This throws that there is not a suitable constructor. Should it?
          var client = servicesProvider.GetService&lt;TestClient&gt;();
      }
  }
  }
  </code></pre>
  
  <p>with <code>install-package Microsoft.Extensions.Http</code> and <code>install-package Microsoft.Extensions.DependencyInjection</code>.</p>
  
  <p>Also in the exception stack there reads</p>
  
  <blockquote>
    <p>at System.Threading.LazyInitializer.EnsureInitializedCore[T](T&amp; target, Boolean&amp; initialized, Object&amp; syncLock, Func<code>1 valueFactory)
       at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory</code>1.Cache.get_Activator()
       at ** Microsoft.Extensions.Http.DefaultTypedHttpClientFactory<code>1.CreateClient(HttpClient httpClient) **
       at System.Threading.LazyInitializer.EnsureInitializedCore[T](T&amp; target, Boolean&amp; initialized, Object&amp; syncLock, Func</code>1 valueFactory)
       at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory<code>1.Cache.get_Activator()
       at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory</code>1.CreateClient(HttpClient httpClient)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProviderEngineScope scope)
       at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
       at TypedClientTest.Program.Main(String[] args) in C:\projektit\testit\TypedClientTest\TypedClientTest\Program.cs:line 40</p>
  </blockquote>
  
  <p>which of course points towards the problem. But needs probably further debugging.</p>
  
  <p>&lt;edit 4: So going to the source, the problem is visible at <a href="https://github.com/aspnet/Extensions/blob/557995ec322f1175d6d8a72a41713eec2d194871/src/HttpClientFactory/Http/src/DefaultTypedHttpClientFactory.cs#L47" rel="nofollow noreferrer">https://github.com/aspnet/Extensions/blob/557995ec322f1175d6d8a72a41713eec2d194871/src/HttpClientFactory/Http/src/DefaultTypedHttpClientFactory.cs#L47</a> and in <a href="https://github.com/aspnet/Extensions/blob/11cf90103841c35cbefe9afb8e5bf9fee696dd17/src/HttpClientFactory/Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs" rel="nofollow noreferrer">https://github.com/aspnet/Extensions/blob/11cf90103841c35cbefe9afb8e5bf9fee696dd17/src/HttpClientFactory/Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs</a> in general.</p>
  
  <p>There are probably some ways to go about this now. :)</p>
  
  <p>&lt;edit 5: </p>
  
  <p>So it appears calling <code>.AddHttpClient</code> for a typed client that has <code>IHttpClientFactory</code> one ends up in a "weird place". And indeed, it's not possible to use <code>IHttpClientFactory</code> to create a typed client of its own type.</p>
  
  <p>One way of making this with named client could be something like</p>
  
  <pre><code>public static class CustomServicesCollectionExtensions
  {
      public static IHttpClientBuilder AddTypedHttpClient&lt;TClient&gt;(this IServiceCollection serviceCollection, Action&lt;HttpClient&gt; configureClient)  where TClient: class
      {
          //return serviceCollection.Add(new ServiceDescriptor(typeof(TClient).Name, f =&gt; new ...,*/ ServiceLifetime.Singleton));
          servicesCollection.AddTransient&lt;TClient&gt;();
          return serviceCollection.AddHttpClient(typeof(TType).Name, configureClient);
      }
  }
  
  public static class HttpClientFactoryExtensions
  {
      public static HttpClient CreateClient&lt;TClient&gt;(this IHttpClientFactory clientFactory)
      {
          return clientFactory.CreateClient(typeof(TClient).Name);
      }
  }
  
  
  public class TestClient
  {
      private IHttpClientFactory ClientFactory { get; }
  
      public TestClient(IHttpClientFactory clientFactory)
      {
          ClientFactory = clientFactory;
      }
  
      public async Task&lt;HttpResponseMessage&gt; Test(CancellationToken cancellation = default)
      {
          using(var client = ClientFactory.CreateClient&lt;TestClient&gt;())
          {
              return await client.GetAsync("/", cancellation);
          }
      }
  }
  </code></pre>
  
  <p>Which mimicks what the extension methods already do. It's of course now possible to expose the lifetime services better too.</p>