【问题标题】:HttpClient - Request was canceled - Timeout of 100 seconds elapsingHttpClient - 请求被取消 - 超时 100 秒
【发布时间】:2021-10-01 15:26:31
【问题描述】:

我正在使用一个 blazor Web 程序集项目,然后是一个 asp.net 核心 Web api 和一个共享项目。当运行我的两个项目并拉起邮递员以执行 GET 请求 https://localhost:5011/api/WebReport/GatherAllReports 时,它会从 blazor Web 程序集命中 ReporterRepository,当它到达第一行 var response 时,它会停留在该行,然后最终经过一个真正的很长一段时间它都在邮递员上说......

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

---> System.TimeoutException: 操作被取消。

---> System.Threading.Tasks.TaskCanceledException: 操作被取消。

---> System.IO.IOException: Unable to read data from the transport connection: 由于线程退出或应用程序请求,I/O 操作已中止..

---> System.Net.Sockets.SocketException (995):I/O 操作已 由于线程退出或应用程序请求而中止。
--- 内部异常堆栈跟踪结束 ---

在 System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError 错误,CancellationToken cancelToken)

在 System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.GetResult(Int16 令牌)

在 System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter 适配器,内存`1 缓冲区)

在 System.Net.Http.HttpConnection.FillAsync(布尔异步)

在 System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(布尔异步,布尔 foldedHeadersAllowed)

在 System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage 请求,布尔异步,CancellationToken cancelToken)

---内部异常堆栈跟踪结束---

在 System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage 请求,布尔异步,CancellationToken cancelToken)

在 System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage 请求,布尔异步,布尔 doRequestAuth,CancellationToken 取消令牌)

在 System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage 请求,布尔异步,CancellationToken cancelToken)

在 System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage 请求,布尔异步,CancellationToken cancelToken)

在 Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancelToken)

在 Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancelToken)

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

---内部异常堆栈跟踪结束---

还有更多其他邮件在邮递员中返回。

每当我为我的 web 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 用于 web api:

公共类启动 { 公共启动(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 程序集项目中:

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;
    }

}

【问题讨论】:

  • 这听起来像是您的 IReportRepository.GetAll() 方法中的性能问题,您的问题中没有包含其内容。
  • 抱歉,您的意思有点搞糊涂了。我确实包含了IReportRepository.GetAll() 的内容,请检查ReporterRepository 文件GetAll() 方法。 @AndrewH
  • 只是我还是 GET 到 _httpClient.GetAsync("/ReportsPage/GatherAllReports") 会造成无限循环? /GatherAllReports 的控制器操作调用 ReporterRepository.GetAll()
  • 是的,我也遇到了无限循环,不知道为什么会这样。 @AndrewH

标签: c# asp.net-core-webapi dotnet-httpclient blazor-webassembly


【解决方案1】:

您将进入无限循环,因为您的 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

      } 
    }

}

【讨论】:

  • 谢谢!这个文件,我应该在我的 blazor web 程序集项目中实现它,还是需要在我的 web api 项目中?我意识到我在我的 web api 项目中正在做services.AddHttpClient&lt;IReporterRepository, ReporterRepository&gt;(client =&gt; { client.BaseAddress = new Uri("https://localhost:5011/"); });,而这应该在我的 blazor 应用程序中。但我注意到 blazor 服务器项目只包含一个startup.cs 文件。我需要翻译它并将这行代码放在我的 blazor wa 项目的program.cs 中吗?
  • 我没有 blazor 服务器项目,我只想使用带有 api 项目的 blazor Web 程序集
  • 没有。仅在 Web 程序集项目中。 WA 将有 builder.Services.AddHttpClient("localhost:5011", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)) .AddHttpMessageHandler();和记者访问层。 WebAPI 应该有 services.AddScoped()
  • 我明白了,所以这个 ReporterAccessLayer 应该是它自己的唯一文件,即 ReporterAccessLayer.cs,并放置在包含 IReporterRepository.csReporterRepository.cs 的同一文件夹中?另一方面,在重载的构造函数内部有_repository,但我看不到它在哪里初始化,是来自IReporterRepositer吗?
  • ReporterAccessLayer 应该在 wasm 中。另外两个在 WebAPI 上的构造函数:不需要。您应该阅读有关依赖注入的工作原理 Keep get all in Reporter repo。那是实际获取数据的地方。 ReporterAccessLayer只是围绕http请求调用controller,管理物流。
【解决方案2】:

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

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

例如:

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 };
}

【讨论】:

  • 谢谢!这很有意义为什么会发生这种情况。我需要将此数据访问层文件包含到我的 blazor Web 程序集项目中吗?
  • 可能是的,因为您的数据应该存储在 Web 程序集可访问的位置。
猜你喜欢
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-08
  • 1970-01-01
  • 2017-04-15
  • 1970-01-01
相关资源
最近更新 更多