在运行时使用网络凭据更新HttpMessageHandler或创建类型化HttpClient

时间:2019-05-17 11:48:26

标签: c# asp.net-core .net-core asp.net-core-mvc

我需要根据最终用户使用应用程序传递网络凭据来模拟应用程序运行期间的域用户。我无法弄清楚如何通过Services.AddHttpClient和HttpClientFactory生成一个绑定到单个用户的HttpClient。

        var httpClientBuilder = services
            .AddHttpClient<SomeHttpClint>()
            .ConfigurePrimaryHttpMessageHandler(sp => new HttpClientHandler
            {
                AllowAutoRedirect = false,
                UseCookies = false,
                Credentials = new NetworkCredential("user", "pass", "domain")
            });

所以我的问题如下:

  1. 是否可以使用命名或键入的HttpClientFactories生成代表单个用户的HttpClient?还是有更好的解决方案来生成绑定到单个用户的一堆HttpClient?

  2. 是否可以在将HTTP客户端工厂注入控制器(例如中间件类型)之外访问该客户端工厂?

1 个答案:

答案 0 :(得分:0)

您可以在运行时注册客户端。这是我的解决方法代码。 定义2个类别:

public class DynamicHttpClientFactoryOptions : IConfigureNamedOptions<HttpClientFactoryOptions>
{
    private readonly DynamicHttpClientFactoryWrapper _options;

    public DynamicHttpClientFactoryOptions(DynamicHttpClientFactoryWrapper options)
    {
        _options = options;
    }

    public void Configure(HttpClientFactoryOptions options)
    {
    }

    public void Configure(string name, HttpClientFactoryOptions options)
    {
        if (!_options.TryGetValue(name, out var configure)) return;

        configure(options);
    }
}
public class DynamicHttpClientFactoryWrapper : ConcurrentDictionary<string, Action<HttpClientFactoryOptions>>
{
    
    public HttpClient GetOrCreateClient(string name, Action<HttpClientFactoryOptions> optionsBuilder)
    {
        if (!ContainsKey(name) || !TryGetValue(name, out var action))
        {
            TryAdd(name, optionsBuilder);
        }

        
        //you can store serviceProvider in startup class
        var factory = _serviceProvider.GetRequiredService<IHttpClientFactory>();
        return factory.CreateClient(name);
    }
}

使用方法:
注册:

services.AddHttpClient(...);
services.AddSingleton<DynamicHttpClientFactoryWrapper>();
services.ConfigureOptions<DynamicHttpClientFactoryOptions>();

通过MS DI获取:

public class SomeClass
{
    private readonly DynamicHttpClientFactoryWrapper _wrapper;

    public SomeClass(DynamicHttpClientFactoryWrapper wrapper)
    {
        _wrapper = wrapper;
    }
    
    public async Task Work()
    {
        var client = _wrapper.GetOrCreateClient(name/*userid or something else*/, options =>
        {
            options.HttpClientActions.Add(c =>
            {
                c.BaseAddress = new Uri("...");
            });
            options.HttpMessageHandlerBuilderActions.Add(handlerBuilder =>
            {
                var handler = new HttpClientHandler
                {
                    Credentials = new NetworkCredential("user", "pass", "domain")
                }

                handlerBuilder.PrimaryHandler = handler;
            });
        });

        var response = await client.SendAsync(request);
        //do your work...
    }
}