尝试通过 httpclient 调用访问 IHostedService 中的 swagger.json 时出现超时错误

Timeout error in trying to access swagger.json in IHostedService through a httpclient call

我想访问 swagger.json 文件并将其反序列化并存储到缓存中。

我正在 IHostedService 中进行异步调用。

public class InitializeCacheService : IHostedService
{
    private IMemoryCache _cache;
    public static readonly string swaggerJson = "swagger.json";
    private readonly HttpClient _httpClient;
    private readonly IServiceProvider _serviceProvider;

    public InitializeCacheService(IMemoryCache cache, HttpClient client, IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
        _httpClient = client;

        _cache = cache;
    }
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        if (!_cache.TryGetValue(swaggerJson, out SwaggerDocumentCache cacheEntry))
        {
            _httpClient.BaseAddress = new Uri("https://localhost:44397");

            var response = await _httpClient.GetAsync("swagger/v1/swagger.json");

            response.EnsureSuccessStatusCode();

            using var responseStream = await response.Content.ReadAsStreamAsync();

            cacheEntry = await JsonSerializer.DeserializeAsync
                <SwaggerDocumentCache>(responseStream);

            var cacheEntryOptions = new MemoryCacheEntryOptions()
                  .SetSlidingExpiration(TimeSpan.FromSeconds(3));

            _cache.Set(swaggerJson, cacheEntry, cacheEntryOptions);
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}

但是应用程序一直在旋转,并且正在超时 var response = await _httpClient.GetAsync("swagger/v1/swagger.json");

它给出的错误是:

IOException: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request.

我在这里缺少什么?访问 swagger.json 以构建自定义 API 游乐场应用程序的正确方法是什么?

我认为实际的 JSON 不一定是有效的端点,这本身可能就是一个问题。您是否尝试过在端点路由上没有显式文件名的情况下进行调用?

SwaggerMiddleware 处理服务 OpenAPI 文档。我们可以以此为参考来自己构建文档。

首先使用 DI 注册 SwaggerGenerator

// Startup.Configure
services.AddTransient<SwaggerGenerator>();

然后将其注入到 class 中,这里我使用端点直接为其提供服务:

// Startup.Configure
app.UseEndpoints(e =>
{
    // ...
    e.MapGet("/openapi.json", context =>
    {
        // inject SwaggerGenerator
        var swaggerGenerator = context.RequestServices.GetRequiredService<SwaggerGenerator>();
        // document name is defined in Startup.ConfigureServices method inside the AddSwaggerGen call
        var doc = swaggerGenerator.GetSwagger("v1");

        // serialize the document as json
        using var writer = new StringWriter(CultureInfo.InvariantCulture);
        var serializer = new OpenApiJsonWriter(writer);
        doc.SerializeAsV3(serializer);
        var json = writer.ToString(); // this is the openapi document
        
        // serve it as json
        context.Response.ContentType = MediaTypeNames.Application.Json;
        return context.Response.WriteAsync(json, new UTF8Encoding(false));
    });
});