Search code examples
c#restdependency-injectionstructuremapdotnet-httpclient

Defining an 'HttpClient' singleton via StructureMap causes an error about 'HttpMessageHandler' being not configured in runtime


Trying to define an HttpClient singleton in StructureMap ala:

For<HttpClient>().Singleton().UseIfNone<HttpClient>();

This results in the following error in runtime (upon dependency injection):

   StructureMap.StructureMapConfigurationException: No default Instance is registered and cannot be automatically determined for type 'System.Net.Http.HttpMessageHandler'

   There is no configuration specified for System.Net.Http.HttpMessageHandler

   1.) new HttpClient(*Default of HttpMessageHandler*)
   2.) System.Net.Http.HttpClient
   3.) Instance of System.Net.Http.HttpClient
   4.) new AdmanAdapter(*Default of HttpClient*)
   5.) Organotiki.vNext.PostEval.Data.Adapters.ADMAN.AdmanAdapter
   6.) Instance of [....]

      at lambda_method(Closure , IBuildSession , IContext )
      at StructureMap.Building.BuildPlan.Build(IBuildSession session, IContext context)
      at StructureMap.BuildSession.BuildNewInSession(Type pluginType, Instance instance)
      at StructureMap.Pipeline.NulloTransientCache.Get(Type pluginType, Instance instance, IBuildSession session)
      at StructureMap.BuildSession.ResolveFromLifecycle(Type pluginType, Instance instance)
      at StructureMap.SessionCache.GetObject(Type pluginType, Instance instance, ILifecycle lifecycle)

If we also configure HttpMessageHandler like so:

For<HttpClient>().Singleton().UseIfNone<HttpClient>();
For<HttpMessageHandler>().UseIfNone(x => new HttpClientHandler());

Then the problem goes away. The question is why? The default constructor for HttpClient takes care of its own dependency injection:

/// <summary>Initializes a new instance of the <see cref="T:System.Net.Http.HttpClient" /> class.</summary>
[__DynamicallyInvokable]
public HttpClient()
  : this((HttpMessageHandler) new HttpClientHandler())
{
}

Am I missing something here?


Solution

  • From structuremap docs at http://structuremap.github.io/registration/constructor-selection

    If there are multiple public constructor functions on a concrete class, StructureMap's default behavior is to select the "greediest" constructor, i.e., the constructor function with the most parameters.

    If you look at the possible constructors for HttpClient, it should be

    public HttpClient();
    public HttpClient(HttpMessageHandler handler);
    public HttpClient(HttpMessageHandler handler, bool disposeHandler);