Мы используем ASP.NET Core 2.2 для создания проекта веб-API, который по сути является интеллектуальным прокси-сервером для другого API.Мы не хотим делать ничего особенного с токенами доступа, а просто перенаправляем их при вызове другого API.
Я хочу избежать вызовов «sync over async», особенно в конструкторах и DI-преобразователях и фабриках,все еще полагаясь на платформу для обработки извлечения токенов доступа из текущего http-запроса.
Вот репрезентативное повторение нашего сценария:
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") });
Это прекрасно демонстрирует мою проблему: там есть .Result
, от которого я хочу полностью избавиться, не просто перенеся его в какую-то заводскую функцию, зарегистрированную в Startup.
Ища синхронный способ получения токена доступа, я спустился в источник GetTokenAsync(...)
и посмотрел, какой другой метод я мог бы использовать intead.Я обнаружил, что на самом деле он имеет всевозможные побочные эффекты, например, он делает AuthenticateAsync(...)
, прежде чем делать то, что предлагает название метода («получение токена» из контекста).
Я на самом деле хочу только логику из GetTokenValue(...)
без других битов и ура (!): Это не асинхронный .... но этот метод опирается на AuthenticationProperties
, которого у меня нетлегко доступны из HttpContextAccessor?
Мой текущий обходной путь (или «решение»?) состоит в том, чтобы сделать работу самостоятельно:
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
из IHttpContextAccessor
без написания собственной вспомогательной функции для заголовков / манипуляции со строками, чтобы извлечь ее из заголовков?