如何读取发送到 DelegatingHandler 中的操作方法 (WebAPI) 的参数
How to Read Parameters sent to an Action Method (WebAPI) within a DelegatingHandler
我正在使用 IHttpClientFactory 从使用 Net Core 2.2 的外部 API 发送请求和接收 HTTP 响应。
我已经为 "intercept" 我的 http 请求实现了一个 DelegatingHandler,并添加了授权 header(令牌)。如果令牌无效,它会获得一个新令牌并再试一次。
同样,当我第一次获得新令牌时,我会缓存令牌 in-memory 以供进一步参考。为了缓存令牌,我创建了一个需要 accountID 和令牌的字典。
我遇到的问题是 DelegatingHandler 已在 Startup.cs class 中注册,但那时我没有 accountID,我在 ActionMethod 中将 accountID 作为参数获取控制器的。该操作方法是调用 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;
}
}
Startup.cs 那样:
services.AddScoped<IClientCredentials>(_ => new
ClientCredentials("au","123"));
services.AddHttpClient("myClient")
.AddHttpMessageHandler<AuthenticationDelegatingHandler>();
和控制器:
[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);
您可以使用HttpContext.Items
来传递数据。
(未测试,从手机发送)。
在控制器中:
this.HttpContext.Items["accountId"] = accountId;
在你的 Handler 中注入 IHttpContextAccessor
var accountId = _httpContextAccessor.HttpContext.Items["accountId"];
IHttpContextAccessor 默认未注册,但可以由您正在使用的组件之一注册。如果出现异常,请在 DI 中明确注册:
services.AddHttpContextAccessor();
如果缺少 IHttpContextAccessor 类型,请添加 Microsoft.AspNetCore.Http
nuget。
数据将保留在那里直到请求结束。
我正在使用 IHttpClientFactory 从使用 Net Core 2.2 的外部 API 发送请求和接收 HTTP 响应。
我已经为 "intercept" 我的 http 请求实现了一个 DelegatingHandler,并添加了授权 header(令牌)。如果令牌无效,它会获得一个新令牌并再试一次。
同样,当我第一次获得新令牌时,我会缓存令牌 in-memory 以供进一步参考。为了缓存令牌,我创建了一个需要 accountID 和令牌的字典。
我遇到的问题是 DelegatingHandler 已在 Startup.cs class 中注册,但那时我没有 accountID,我在 ActionMethod 中将 accountID 作为参数获取控制器的。该操作方法是调用 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;
}
}
Startup.cs 那样:
services.AddScoped<IClientCredentials>(_ => new
ClientCredentials("au","123"));
services.AddHttpClient("myClient")
.AddHttpMessageHandler<AuthenticationDelegatingHandler>();
和控制器:
[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);
您可以使用HttpContext.Items
来传递数据。
(未测试,从手机发送)。
在控制器中:
this.HttpContext.Items["accountId"] = accountId;
在你的 Handler 中注入 IHttpContextAccessor
var accountId = _httpContextAccessor.HttpContext.Items["accountId"];
IHttpContextAccessor 默认未注册,但可以由您正在使用的组件之一注册。如果出现异常,请在 DI 中明确注册:
services.AddHttpContextAccessor();
如果缺少 IHttpContextAccessor 类型,请添加 Microsoft.AspNetCore.Http
nuget。
数据将保留在那里直到请求结束。