我们正在使用ASP.NET Core 2.2构建一个Web API项目,该项目实际上是另一个API的智能代理。不过,我们不想对访问令牌做任何特殊的事情,而只是在调用其他API时将其转发。
我想避免“通过异步进行同步”调用,尤其是在构造函数,DI解析器和工厂中,同时仍要依靠该框架来处理从当前http请求中获取访问令牌的过程。
以下是我们场景的典型代表:
const https = require("https");
const data = JSON.stringify({
key: "value"
});
const options = {
hostname: "url",
port: 443,
path: "/path",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": data.length
}
};
const req = https.request(options, res => {
console.log(
`statusCode: ${res.statusCode} statusMessage: ${res.statusMessage}`
);
res.setEncoding("utf8");
res.on("data", chunk => {
console.log(chunk);
});
});
req.on("error", error => {
console.error(error);
});
req.write(data)
req.end();
在public class TheOtherApi : ITheOtherApi
{
private readonly HttpClient _client;
public TheOtherApi(HttpClient client, IHttpContextAccessor httpContextAccessor)
{
_client = client;
// Yuck! Sync over async, inside a constructor!
var token = httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result;
client.SetBearerToken(token);
}
public Task<string> ForwardSomethingCool(MyCommand command)
{
// E.g.
var response await _client.PostAsync(command.path, command.body);
return await response.Content.ReadAsStringAsync();
}
}
中的注册如下:
Startup
这完美地说明了我的问题:这里有一个services.AddScoped<ITheOtherApi, TheOtherApi>();
services.AddHttpContextAccessor();
services.AddScoped(_=> new HttpClient { BaseAddress = new Uri("https://example.org/api") });
,我想彻底摆脱它,而不仅仅是将其移至在Startup中注册的某种工厂功能。
寻找一种获取访问令牌的同步方法,我进入了.Result
的源代码,并查看可以使用intead的其他方法。我发现它实际上具有各种副作用,例如,它在执行方法名称建议的操作(从上下文中“获取令牌”)之前确实AuthenticateAsync(...)
。
我实际上只想要GetTokenAsync(...)
中的逻辑而没有其他位,并且欢呼(!):它不是异步的......但是我无法从that method relies on AuthenticationProperties
HttpContextAccessor?
我当前的解决方法(或“解决方案”?)是自己完成工作:
GetTokenValue(...)
我如何同步从httpContextAccessor.HttpContext.Request.Headers
.TryGetValue("Authorization", out var authorizationHeader);
var bearerToken = authorizationHeader
.SingleOrDefault()
?.Replace("bearer ", "", StringComparison.InvariantCultureIgnoreCase);
if (string.IsNullOrWhiteSpace(bearerToken))
{
throw new ArgumentException(nameof(httpContextAccessor), "HttpContextAccessor resulted in no Access Token");
}
_client.SetBearerToken(token);
获取access_token
,而又不用编写自己的整个标头/字符串操作帮助函数来从标头中提取它呢?