SemaphoreSlim 未按预期工作 - 允许多个线程使用相同的代码

问题描述 投票:0回答:1

我有一个 API 中间层,用于捕获请求、生成令牌,然后将该请求传递到预期的 API 端点。一次只能创建一个令牌,因此每个请求都需要检查是否存在有效令牌并使用它,或者创建一个新令牌。如果中间层API同时收到多个请求,它仍然应该只创建一个token。

为此,我使用 SemaphoreSlim:

接受请求以检查某些内容的当前版本的控制器:

[ApiController]
[Route("[controller]")]
[AuthorizationKey]

public class Controller : ControllerBase
{
    private readonly ILogger<Controller> Logger;
    private readonly Services Services;

    public Controller(ILogger<Controller> logger, Services services)
    {
        Logger = logger;
        Services = services;
    }

    [HttpGet]
    [Route("version")]
    [ResponseCache(NoStore = true, Duration = 0, Location = ResponseCacheLocation.None)]
    public async Task<ActionResult> Version()
    {
        try
        {
            var result = await Services.GetVersionAsync();

            var response = result.Content.ReadAsStringAsync();

            if (result.StatusCode == HttpStatusCode.OK)
            {
                return Ok(response.Result);
            }
            else if (result.StatusCode == HttpStatusCode.Unauthorized)
            {
                return StatusCode(401, response.Result);
            }
            else
            {
                return StatusCode(500, response.Result);
            }
        }

        catch (Exception ex)
        {
            return StatusCode(500);
        }
    }
}

这是我服务的课程:

public class Services
{
    private readonly ILogger<Services> Logger;
    private readonly IConfiguration Configuration;
    private readonly IHttpClientFactory HttpClientFactory;
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

    public Services(ILogger<Services> logger, IConfiguration configuration, IHttpClientFactory httpClientFactory)
    {
        Logger = logger;
        Configuration = configuration;
        HttpClientFactory = httpClientFactory;
    }

    public async Task<HttpResponseMessage> GetVersionAsync()
    {
        var httpClient = await CreateHttpClient();

        var response = await httpClient.GetAsync(Configuration["VERSION_ENDPOINT"]);

        return response;
    }

    #region Helpers

    private async Task<HttpClient> CreateHttpClient()
    {
        var token = await GetAccessTokenAsync();

        var httpClient = HttpClientFactory.CreateClient();
        httpClient.BaseAddress = new Uri(Configuration["API_URI"]);
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        return httpClient;
    }

    private async Task<string> GetAccessTokenAsync()
    {
        await _semaphore.WaitAsync();
        try
        {
            //Checks for a token in a table and returns it if it is valid, or gets a new one if one does not exist
            /if no token, then it calls RequestAccessTokenAsync()
        }
        finally
        {
            _semaphore.Release();
        }
    }

    private async Task<TokenResponse> RequestAccessTokenAsync()
    {
        //Gets a new token from a service
    }

    #endregion
}

如果我同时提交多个请求,则会创建多个令牌。我提交的请求数量并不总是一对一的。例如,我做了 2 个请求,它创建了 2 个令牌,3 个请求,它创建了 2 个令牌,现在我只做了 10 个请求,它创建了 7 个令牌,但无论哪种方式,我只想一次创建 1 个有效令牌。

c# asp.net api http-post semaphore
1个回答
1
投票

将以下代码切换到静态解决了该问题。再次感谢用户“Deleted”的帮助。

private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
© www.soinside.com 2019 - 2024. All rights reserved.