benjamin
benjamin

Reputation: 1654

Configuring HttpClient using dependency injection where one client needs information from another

I have a .NET Core 3.0 Console application (although I plan to change this to a Blazor app later on).

In my Program class's public static void Main method, I am configuring dependency injection using the pattern described by Microsoft here.

In particular, I want to register a handful of HttpClient instances using the "named clients" pattern described here.

It's all fine except for this one problem: My second and third HttpClient instances should have a DefaultRequestHeader that passes a session Id. But I won't know the value of the session Id until I execute an API command to log in to a remote server using the first HttpClient instance. What should I do?

My code so far is below.

Can I somehow get a reference to the first HttpClient instance and call my Login method from inside this block of code? Or can I call the Login method later from a different block of code and then add the appropriate DefaultRequestHeader to the other HttpClient instances long after they have been instantiated?

public class Program
{
    public static void Main()
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddUserSecrets<Program>()
            .AddEnvironmentVariables(); ;

        IConfigurationRoot configuration = builder.Build();
        var settings = new ApplicationOptions();
        configuration.GetSection("AppSettings").Bind(settings);

        var services = new ServiceCollection();

        // This is the client I'll use to log in and get a session token
        services.AddHttpClient("Authentication", c =>
        {
            c.BaseAddress = new Uri(settings.AuthenticationApi);
            c.DefaultRequestHeaders.Accept.Clear();
            c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            c.DefaultRequestHeaders.Add("X-Application", settings.AppKey);
            c.DefaultRequestHeaders.Add("User-Agent", "My API Client v0.0.1");
        }).ConfigurePrimaryHttpMessageHandler(() =>
        {
            return GetMessageHandlerWithSecurityCertificate(settings);
        });


        // and this is the next of several clients where I'll need to send the session token with my requests
        services.AddHttpClient("AnotherApi", c =>
        {
            c.BaseAddress = new Uri(settings.AnotherApi);
            c.DefaultRequestHeaders.Accept.Clear();
            c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            c.DefaultRequestHeaders.Add("X-Application", settings.AppKey);
            c.DefaultRequestHeaders.Add("User-Agent", "My API Client v0.0.1");
            //c.DefaultRequestHeaders.Add("ssoid", sessionToken);
            // What should I do here? I want to add a sessionToken string but I can only get the token's value by using the other HttpClient (above) to log in! 
        });


        // Removed one more HttpClient for brevity
    }

    private static HttpMessageHandler GetMessageHandlerWithSecurityCertificate(ApplicationOptions settings)
    {
        var handler = new HttpClientHandler();
        handler.ClientCertificates.Add(GetSecurityCertificate(settings.SslCertificateFilename, settings.SslCertificatePassword));
        return handler;
    }


    private static X509Certificate2 GetSecurityCertificate(string certFilename, string certPassword)
    {
        return new X509Certificate2(certFilename, certPassword);
    }
}

Upvotes: 0

Views: 3468

Answers (1)

Robert Perry
Robert Perry

Reputation: 1956

Can you not use the IHttpClientFactory directly and generate an HttpClient at the time you need it using your credentials? In other words, instead of trying to register all of the individual HttpClient(s), register the IHttpClientFactory as normal. Inject that into the class thats going to need the HttpClient, and just create it with your credentials there? Thats what I would do. After all, the IHttpClientFactory is simply a wrapper class which generates your HttpClients using the factory pattern.

Additionally: At a stretch you could use an extension method to configure your HttpClient with preset values to save duplicating code everywhere for consistent stuff.

Upvotes: 1

Related Questions