C# 如何在DelegatingHandler中读取发送给操作方法(WebAPI)的参数

C# 如何在DelegatingHandler中读取发送给操作方法(WebAPI)的参数,c#,asp.net-core,dependency-injection,token,httpclientfactory,C#,Asp.net Core,Dependency Injection,Token,Httpclientfactory,我正在使用IHttpClientFactory通过netcore2.2从外部api发送请求和接收HTTP响应 我已经实现了一个DelegatingHandler来“拦截”我的http请求并添加授权头(令牌)。如果令牌无效,它将获取一个新令牌并重试一次 同样,当我第一次获得一个新的令牌时,我会将该令牌缓存在内存中以供进一步引用。为了缓存令牌,我创建了一个需要accountID和令牌的字典 我遇到的问题是DelegatingHandler在Startup.cs类中注册,但此时我没有accountID

我正在使用IHttpClientFactory通过netcore2.2从外部api发送请求和接收HTTP响应

我已经实现了一个DelegatingHandler来“拦截”我的http请求并添加授权头(令牌)。如果令牌无效,它将获取一个新令牌并重试一次

同样,当我第一次获得一个新的令牌时,我会将该令牌缓存在内存中以供进一步引用。为了缓存令牌,我创建了一个需要accountID和令牌的字典

我遇到的问题是DelegatingHandler在Startup.cs类中注册,但此时我没有accountID,我将accountID作为控制器ActionMethod中的参数获取。该操作方法调用SendAsync并从DelegatingHandler获取令牌,以此类推

我不知道,在控制器收到请求后,如何将accountID注入DelegatingHandler

我试图创建一个IClientCredentials接口和该接口的一个实现,该接口可以在控制器中实例化并注入DelegatingHandler

我的代码如下所示:

委托人:

public class AuthenticationDelegatingHandler : DelegatingHandler
{

    private readonly AccessTokenManager _accessTokenManager;
    private readonly IClientCredentials _clientCredentials;

    public AuthenticationDelegatingHandler(IHttpClientFactory httpClientFactory, 
                                           IOptions<AppSettings> appSettings, IClientCredentials clientCredentials)
    {
        _accessTokenManager = new AccessTokenManager(httpClientFactory, appSettings);
        _clientCredentials = clientCredentials;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var clientCredentials = _clientCredentials.GetClientCredentials();

        var accessToken =  _accessTokenManager.GetToken(clientCredentials._accountID);

        if (accessToken == null) {               

             accessToken = await _accessTokenManager.GetAccessTokenAsync(clientCredentials._accountID);
            _accessTokenManager.AddOrUpdateToken(clientCredentials._accountID, accessToken);
        }

        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.access_token);

        var response = await base.SendAsync(request, cancellationToken);

        if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
        {
            var token = await _accessTokenManager.GetAccessTokenAsync(clientCredentials._accountID);
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.access_token);
            response = await base.SendAsync(request, cancellationToken);
        }

        return response;
    }

}
公共类身份验证DelegatingHandler:DelegatingHandler
{
私有只读AccessTokenManager\u AccessTokenManager;
专用只读IClientCredentials _客户端凭据;
公共身份验证DelegatingHandler(IHttpClientFactory httpClientFactory,
IOOptions应用程序设置、IClientCredentials客户端凭据)
{
_accessTokenManager=新的accessTokenManager(httpClientFactory,appSettings);
_clientCredentials=clientCredentials;
}
受保护的覆盖异步任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
var clientCredentials=_clientCredentials.GetClientCredentials();
var accessToken=\u accessTokenManager.GetToken(clientCredentials.\u accountID);
如果(accessToken==null){
accessToken=await\u accessTokenManager.GetAccessTokenAsync(客户端凭据.\u帐户ID);
_accessTokenManager.AddOrUpdateToken(客户端凭据。\u accountID,accessToken);
}
request.Headers.Authorization=新的AuthenticationHeaderValue(“承载者”,accessToken.access\u令牌);
var response=await base.sendaync(请求、取消令牌);
if(response.StatusCode==HttpStatusCode.Unauthorized | | response.StatusCode==HttpStatusCode.Forbidden)
{
var token=await\u accessTokenManager.GetAccessTokenAsync(clientCredentials.\u accountID);
request.Headers.Authorization=新的AuthenticationHeaderValue(“承载者”,token.access\u token);
response=wait base.sendaync(请求、取消令牌);
}
返回响应;
}
}
Startup.cs类似于:

 services.AddScoped<IClientCredentials>(_ => new 
                    ClientCredentials("au","123"));

services.AddHttpClient("myClient")
              .AddHttpMessageHandler<AuthenticationDelegatingHandler>();
services.AddScoped(=>new)
客户证书(“au”、“123”);
服务。AddHttpClient(“myClient”)
.AddHttpMessageHandler();
以及控制器:

[HttpPost("{siteName}/{accountID}")]
public async Task<ActionResult<AirRequest>> Post(AirModel model, string 
siteName, string accountID)
    {
      ....
      SetClientCredentials(siteName, accountID);

      var clientJAAPI = 
      _httpClientFactory.CreateClient("myClient");

      var responseclientJAAPI = await 
        clientJAAPI.SendAsync(request);
     .....
    }

  private ClientCredentials SetClientCredentials(string siteName, string 
  accountID) =>
       new ClientCredentials(siteName, accountID);
this.HttpContext.Items["accountId"] = accountId;
[HttpPost(“{siteName}/{accountID}”)]
公共异步任务Post(AirModel模型,字符串
站点名称、字符串帐户ID)
{
....
SetClientCredentials(站点名称、帐户ID);
var clientJAAPI=
_httpClientFactory.CreateClient(“myClient”);
var responseclientJAAPI=等待
clientJAAPI.SendAsync(请求);
.....
}
private ClientCredentials SetClientCredentials(字符串siteName,字符串
帐户ID)=>
新客户端凭据(站点名称、帐户ID);

您可以使用
HttpContext.Items
传递数据。 (未测试,由手机发送)。 在控制器中:

[HttpPost("{siteName}/{accountID}")]
public async Task<ActionResult<AirRequest>> Post(AirModel model, string 
siteName, string accountID)
    {
      ....
      SetClientCredentials(siteName, accountID);

      var clientJAAPI = 
      _httpClientFactory.CreateClient("myClient");

      var responseclientJAAPI = await 
        clientJAAPI.SendAsync(request);
     .....
    }

  private ClientCredentials SetClientCredentials(string siteName, string 
  accountID) =>
       new ClientCredentials(siteName, accountID);
this.HttpContext.Items["accountId"] = accountId;
在处理程序中注入
IHttpContextAccessor

var accountId = _httpContextAccessor.HttpContext.Items["accountId"];
默认情况下,IHttpContextAccessor未注册,但可以由您正在使用的组件之一注册。如果出现异常,请在DI中明确注册它:

services.AddHttpContextAccessor();
如果缺少IHttpContextAccessor类型,请添加
Microsoft.AspNetCore.Http
nuget


数据将一直保存到请求结束

您可以使用
HttpContext.Items
传递数据。 (未测试,由手机发送)。 在控制器中:

[HttpPost("{siteName}/{accountID}")]
public async Task<ActionResult<AirRequest>> Post(AirModel model, string 
siteName, string accountID)
    {
      ....
      SetClientCredentials(siteName, accountID);

      var clientJAAPI = 
      _httpClientFactory.CreateClient("myClient");

      var responseclientJAAPI = await 
        clientJAAPI.SendAsync(request);
     .....
    }

  private ClientCredentials SetClientCredentials(string siteName, string 
  accountID) =>
       new ClientCredentials(siteName, accountID);
this.HttpContext.Items["accountId"] = accountId;
在处理程序中注入
IHttpContextAccessor

var accountId = _httpContextAccessor.HttpContext.Items["accountId"];
默认情况下,IHttpContextAccessor未注册,但可以由您正在使用的组件之一注册。如果出现异常,请在DI中明确注册它:

services.AddHttpContextAccessor();
如果缺少IHttpContextAccessor类型,请添加
Microsoft.AspNetCore.Http
nuget

数据将一直保存到请求结束