Как обновлять sh токен-носитель при каждом вызове CreateClient (возможно, переопределив CreateClient) - PullRequest
0 голосов
/ 07 мая 2020

Я впервые пытаюсь использовать IHttpClientFactory в проекте. NET Core 3.1 MVC. Я использую HttpClient для вызовов Microsoft Graph API.

Всякий раз, когда мне нужно выполнить вызов API, мне нужно сначала проверить, что токен аутентификации, имеющийся в приложении, действителен (т.е. истек), и, если нет, используйте токен refre sh для получения нового токена аутентификации.

Перед изучением IHttpClientFactory я инициализировал экземпляр HttpClient для своего приложения, а затем всякий раз, когда мне было нужно чтобы сделать вызов API, я бы сначала вызвал свою собственную функцию PrepareHttpClient(), поэтому она будет go примерно так:

public class MyController : Controller
{
    private static HttpClient httpClient = new HttpClient();
    private readonly IOAuthService _oAuthService;

    public MyController(IOAuthService oAuthService)
    {
        _oAuthService = oAuthService;
    }

    public async Task<IActionResult> Index()
    {
        var url = "http://whatever";
        await PrepareHttpClient();
        var response = await httpClient.GetAsync(url);
        // Other stuff
    }

    private async Task PrepareHttpClient()
    {
        httpClient.DefaultRequestHeaders.Clear();
        string bearerToken = await _oAuthService.GetOAuthBearerToken();
        httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {bearerToken}");
    }
}

Функция GetOAuthBearerToken находится в службе, которая, как вы можете см., вводится в контроллер и в основном выполняет танец, проверяя, истек ли текущий токен, и получает новый, если требуется, и возвращает действительный токен в виде строки. Я не думаю, что здесь нужен полный код этой функции, но я могу добавить его, если потребуется.

После изучения IHttpClientFactory и того факта, что вы можете дать HttpClient имя и настроить его в Startup.cs я подумал: «Отлично, я просто вызову функцию GetOAuthBearerToken при настройке клиента». Что-то вроде

services.AddHttpClient("OneDrive", async(c) => {
    string bearerToken = await IOAuthService.GetOAuthBearerToken();
    c.DefaultRequestHeaders.Add("Authorization", $"Bearer {bearerToken}");
});

Однако с этим возникает ряд проблем:

  1. Внедрение службы в класс Startup кажется не- go , что имеет смысл, поэтому я не могу ввести свой IOAuthService, как это делаю в контроллере.
  2. Сам GetOAuthBearerToken использует HttpClient для получения обновленных токенов API и с помощью DI вводит IHttpClientFactory в функцию, которая сама вводится в Startup звучит так ... Я схожу с ума.

В конце концов я понял, что все это не имеет значения, потому что мне нужно проверить и обновить sh токен API каждый раз, когда я вызываю, а не только когда клиент создается при запуске приложения. Поэтому мне кажется, что наиболее элегантным решением было бы переопределить метод CreateClient в IHttpClientFactory, который я вызываю прямо перед каждым вызовом API, чтобы он мог вызывать мою функцию GetOAuthBearerToken, и тогда я знал бы что каждый раз, когда я звонил CreateClient, HttpClient соответствовал go, с действующим токеном носителя в заголовке.

Мой вопрос (наконец!), как бы я go переопределил CreateClient таким образом? Если это лучший способ достичь моей цели.

1 Ответ

0 голосов
/ 07 мая 2020

Извините, если кто-то может сделать это комментарием.

Первое, что я заметил, это то, что вы забыли очистить заголовки и добавить новый заголовок для каждого запроса, для экземпляра, который вы регистрируете в своем запуске.

Редактировать : Я просто go заранее отвечу на него. Извините, у меня нет компилятора c# или intellisense.

public class MyController : Controller
{
    private static IHttpClientFactory httpClientFactory = new IHttpClientFactory();
    private readonly IOAuthService _oAuthService;

    public MyController(IOAuthService oAuthService,IHttpClientFactory myfactory)
    {
        _oAuthService = oAuthService;
        httpClientFactory = myfactory;
    }

    public async Task<IActionResult> Index()
    {
        var url = "http://whatever";
        HttpClient myclient = httpClientFactory.CreateClient("MyNamedClient");
        var response = await HttpClient.GetAsync(url);
        // Other stuff
    }
}
...