Search code examples
c#.net-coredependency-injectiondotnet-httpclient

IHostEnvironment and no DI in Startup constructor .NET Core 3+


We are building .NET Core microservices.

Many of our microservices use HttpClient logging through ConfigurePrimaryMessageHandler()

With .NET Core 2+ our approach had been to

services.AddHttpClient().ConfigurePrimarymessageHandler() in ConfigureServices of Startup.cs. We had to pass in a ILogger<T> here and we would get that by injecting it into our Startup constructor.

Now that we have migrated to IHostEnvironment we can no longer use DI to inject ILogger<T> into Startup constructor AND we can't inject IServiceCollection into Configure().

One idea I had was to create the HttpClientBuilder, store a reference to it and then do the ConfigurePrimaryMessageHandler in Configure... This did NOT work. I'm assuming because once it is built, it is built so you need to do it in ConfigureServices.

So I ended up coming up with a nasty hack that works but it feels yucky:

I have an ILogger<T> as a protected member of my Startup.cs.

I pass that in (its null) into my HttpClientBuilders...

Then in Configure() I inject ILogger<T> and set the protected member variable.

Yuck!

It kind of looks like this:

class Startup
{
    protected ILogger<HttpClientLoggingHandler> _logHack;

    public void ConfigureServices(IServiceCollection)
    {
        services.AddHttpClient<T>().ConfigurePrimaryMessageHandler(()=>{ new 
        HttpClientLoggingHandler(_logHack, otherstuff) });
    }

    public void Configure(IApplicationBuilder bld, ILogger<T> logForHack, otherstufffordi)
    {
         _logHack = logForHack;   // note this works, but is this really a good design pattern?
    }
}

So this does work... But it doesn't feel like a really great design pattern. Any advice out there anyone? Is this really the approach we should be taking? Feel like something was missed here when we migrated to IHostEnvironment.


Solution

  • You can simply do .ConfigurePrimaryMessageHandler<HttpClientLoggingHandler>();, provided the HttpClientLoggingHandler is registered.

    The lambda overloads for ConfigurePrimaryMessageHandler also can pass you an IServiceProvider. From there, call sp.GetRequiredService<T>.