使用依赖注入配置 HttpClient,其中一个客户端需要来自另一个客户端的信息

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

我有一个 .NET Core 3.0 控制台应用程序(尽管我打算稍后将其更改为 Blazor 应用程序)。

在我的程序 class 的 public static void Main 方法中,我正在使用 Microsoft here.

描述的模式配置依赖注入

特别是,我想使用 here 描述的 "named clients" 模式注册少数 HttpClient 个实例。

一切都很好,除了这个问题:我的第二个和第三个 HttpClient 实例应该有一个 DefaultRequestHeader 传递会话 ID。但是在我执行 API 命令以使用第一个 HttpClient 实例登录到远程服务器之前,我不会知道会话 ID 的值。我该怎么办?

到目前为止我的代码如下。

我能否以某种方式获得对第一个 HttpClient 实例的引用并从该代码块内部调用我的 Login 方法?或者我可以稍后从不同的代码块调用 Login 方法,然后在实例化很久之后将适当的 DefaultRequestHeader 添加到其他 HttpClient 实例吗?

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

您能否不直接使用 IHttpClientFactory 并在需要时使用您的凭据生成 HttpClient?换句话说,与其尝试注册所有单独的 HttpClient,不如正常注册 IHttpClientFactory。将其注入到需要 HttpClient 的 class 中,然后使用您的凭据在那里创建它?那就是我会做的。毕竟,IHttpClientFactory 只是一个包装器 class,它使用工厂模式生成 HttpClient。

另外:在一段时间内,您可以使用扩展方法为您的 HttpClient 配置预设值,以在任何地方保存重复代码以获得一致的内容。