XDS
XDS

Reputation: 4188

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?

Upvotes: 1

Views: 1709

Answers (3)

benjaminoerskov
benjaminoerskov

Reputation: 240

This is how I made it work:

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

        var recaptchaHttpClient = new HttpClient
        {
            BaseAddress = new Uri("https://www.recaptcha.net/recaptcha/")
        };
        For<IReCaptchaService>().Use<ReCaptchaService>()
            .SelectConstructor(() => new ReCaptchaService(recaptchaHttpClient));

Upvotes: 0

Nikhilesh
Nikhilesh

Reputation: 1751

Extending @Brad M's answer, what worked for me is .SelectConstructor(() => new HttpClient()). Specifying which constructor should be used explicitly.

Upvotes: 1

Brad M
Brad M

Reputation: 7898

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);

Upvotes: 2

Related Questions