E*Trade适配场景下,如何访问HttpClient的自定义HttpMessageHandlers?
问题描述
我正在为E*Trade连接构建一个HttpClient适配器。该HttpClient需要一个自定义消息处理器(HttpMessageHandler),用于处理OAuth相关的连接参数,例如访问令牌(access token)、消费者密钥(consumer key)、消费者密钥密钥(consumer secret)和令牌密钥(token secret)等。
我的配置代码如下:
// Configure the E*Trade adapter. serviceCollection .AddHttpClient<ETradeAdapter>(httpClient => httpClient.BaseAddress = new Uri(baseAddress, UriKind.Absolute)) .AddHttpMessageHandler<ETradeMessageHandler>();
在运行时,我会根据用户身份收集OAuth参数,并尝试将其注入到ETradeMessageHandler中。请问使用上述模式时,如何找到与我的HttpClient关联的消息处理器,以便设置这些参数?
补充说明:我可以通过以下方式实现需求,但该方式较为繁琐,我认为一定有更优方案:
var eTradeMessageHandler = this.serviceProvider.GetRequiredService<ETradeMessageHandler>(); eTradeMessageHandler.AccessToken = "some token"; eTradeMessageHandler.TokenSecret = "some secret"; var httpClient = new HttpClient(eTradeMessageHandler); var eTradeHttpAdapter = new ETradeAdapter(httpClient);
解决方案
方案1:用Scoped服务封装动态OAuth参数(推荐用于用户上下文场景)
- 定义存储OAuth参数的类:
public class ETradeOAuthParameters { public string AccessToken { get; set; } public string TokenSecret { get; set; } public string ConsumerKey { get; set; } public string ConsumerSecret { get; set; } }
- 将参数类注册为Scoped服务(每个请求上下文独立实例):
services.AddScoped<ETradeOAuthParameters>();
- 修改
ETradeMessageHandler,通过构造函数注入参数类:
public class ETradeMessageHandler : DelegatingHandler { private readonly ETradeOAuthParameters _oauthParams; public ETradeMessageHandler(ETradeOAuthParameters oauthParams) { _oauthParams = oauthParams; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // 这里直接使用_oauthParams中的动态参数处理OAuth逻辑 // 例如生成签名、添加Authorization请求头 return await base.SendAsync(request, cancellationToken); } }
- 运行时赋值并使用:
// 示例:在Controller或中间件中 var oauthParams = HttpContext.RequestServices.GetRequiredService<ETradeOAuthParameters>(); oauthParams.AccessToken = "当前用户的access token"; oauthParams.TokenSecret = "当前用户的token secret"; // 直接获取已配置好的ETradeAdapter即可,其关联的Handler会自动使用当前上下文的参数 var adapter = HttpContext.RequestServices.GetRequiredService<ETradeAdapter>(); await adapter.ExecuteTradeOperation();
方案2:通过HttpClient工厂委托配置Handler(适合静态/启动时可确定的参数)
如果OAuth参数在启动阶段就能确定,可在注册时直接配置Handler:
serviceCollection.AddHttpClient<ETradeAdapter>(httpClient => { httpClient.BaseAddress = new Uri(baseAddress, UriKind.Absolute); }) .AddHttpMessageHandler(sp => { var handler = new ETradeMessageHandler(); // 直接在这里赋值静态参数 handler.ConsumerKey = "固定的consumer key"; handler.ConsumerSecret = "固定的consumer secret"; return handler; });
方案3:让Adapter持有Handler实例(适合单实例Adapter场景)
- 注册Handler为Transient(避免多实例共享导致参数冲突):
services.AddTransient<ETradeMessageHandler>();
- 修改
ETradeAdapter的构造函数,注入Handler:
public class ETradeAdapter { private readonly HttpClient _httpClient; private readonly ETradeMessageHandler _handler; public ETradeAdapter(HttpClient httpClient, ETradeMessageHandler handler) { _httpClient = httpClient; _handler = handler; } public void SetOAuthParameters(string accessToken, string tokenSecret) { _handler.AccessToken = accessToken; _handler.TokenSecret = tokenSecret; } // 业务方法实现... }
- 使用时直接调用设置方法:
var adapter = serviceProvider.GetRequiredService<ETradeAdapter>(); adapter.SetOAuthParameters("用户token", "用户secret"); await adapter.DoETradeRequest();
内容的提问来源于stack exchange,提问作者user365462
相关产品推荐
相关产品推荐

