HttpClient - 请求已取消 - 超时 100 秒

HttpClient - Request was canceled - Timeout of 100 seconds elapsing

我正在使用一个 blazor web assembly 项目,然后是一个 asp.net 核心 web api 和一个共享项目。当 运行 我的两个项目并拉起 post 人执行 GET 请求时 https://localhost:5011/api/WebReport/GatherAllReports 它从 blazor web 程序集命中 ReporterRepository 并且当它命中第一行时 var response 它停留在那条线上,然后在很长一段时间后它最终在 postman...

上说

System.Threading.Tasks.TaskCanceledException:由于配置的 HttpClient.Timeout 已过 100 秒,请求被取消。

---> System.TimeoutException: The operation was canceled.

---> System.Threading.Tasks.TaskCanceledException: The operation was canceled.

---> System.IO.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..

---> System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.
--- End of inner exception stack trace ---

at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)

at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.GetResult(Int16 token)

at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)

at System.Net.Http.HttpConnection.FillAsync(Boolean async)

at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean async, Boolean foldedHeadersAllowed)

at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)

--- End of inner exception stack trace ---

at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)

at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)

at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)

at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)

at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)

--- End of inner exception stack trace ---

以及 postman.

中返回的更多其他消息

每当我为我的网络 api 控制器调用路由端点时发生这种情况是否有原因?

Web API 控制器:

using BlazorReports.Services; // this contains the `ReporterRepository.cs` file

[Route("api/[controller]")]
[ApiController]
public class WebReportController : ControllerBase
{
    
    private readonly ReporterRepository_repo;

    public WebReportController (ReporterRepository repo)
    {
        _repo = repo;
    }

    [HttpGet]
    [Route("GatherAllReports")]
    public async Task<IActionResult> Get()
    {
        var reportValues = await _repo.GetAll();
        return Ok(reportValues);
    }

}

startup.cs 网络 api:

public class 启动 { public Startup(IConfiguration配置) { 配置=配置; }

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{

    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPI", Version = "v1" });
    });
    services.AddDbContext<ReportContext>(options =>
          options.UseSqlServer(Configuration.GetConnectionString("Default")));

    services.AddScoped<IReporterRepository, ReporterRepository>();

    services.AddHttpClient<IReporterRepository, ReporterRepository>(client =>
        {
            client.BaseAddress = new Uri("https://localhost:5011/");
        });

    services.AddHttpContextAccessor();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger();
        app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPI v1"));
    }

    app.UseHttpsRedirection();

    app.UseCors(opt => opt
          .AllowAnyMethod()
          .AllowAnyHeader()
          .SetIsOriginAllowed(origin => true) 
          .AllowCredentials()); 

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

}

在我的 blazor web assembly 项目中:

IReporterRepository.cs:

public interface IReporterRepository
{
    Task<List<Reports>> GetAll();
}

ReporterRepository.cs:

public class ReporterRepository: IReporterRepository
{
   
    private readonly HttpClient _httpClient;
    private readonly JsonSerializerOptions _options;

    public ReporterRepository(HttpClient httpClient)
    {
        _httpClient = httpClient;
        _options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
    }

    public async Task<List<Reports>> GetAll()
    {
        var response = await _httpClient.GetAsync("/ReportsPage/GatherAllReports");
        var content = await response.Content.ReadAsStringAsync();

        if (!response.IsSuccessStatusCode)
        {
            throw new ApplicationException(content);
        }

        var results = JsonSerializer.Deserialize<List<Reports>>(content, _options);
        return results;
    }

}

您的请求超时,因为您创建了一个无限循环。

WebReportController.Get() 调用 ReporterRepository.GetAll(),后者又向 WebReportController.Get() 发出 HTTP 请求,您又回到了起点。对于您似乎正在使用的模式,您的控制器操作调用服务 class 来执行业务逻辑(这是一个很好的模式),您将调用保存报表数据的数据访问层。您实际上并没有在您提供的代码中检索任何报告数据。

例如:

public async Task<List<Reports>> GetAll()
{
    var reportA = await _reports.GetReportA();
    var reportB = await _reports.GetReportA();

    // do any further business logic or error handling here

    return new List<Reports> { reportA, reportB };
}

您将进入无限循环,因为您的 GetAll() 方法正在调用自身。您的代码应如下所示:

public class ReporterAccessLayer
{
   
    private readonly HttpClient _httpClient;
    private readonly JsonSerializerOptions _options;

    public ReporterAccessLayer(HttpClient httpClient)
    {
        _httpClient = httpClient;
        _options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
        _repository = repository;
    }

    public async Task<List<Reports>> GetAll()
    {
      try
      {
         return await httpClient.GetAsync<List<Reports>>("/ReportsPage/GatherAllReports");
      }
      catch
      {
         // do exception handling

      } 
    }

}