首页 > 解决方案 > 无法通过 ASP.NET Core 中的 CancellationToken 中断 HttpClient.GetStreamAsync

问题描述

我正在尝试向 AXIS 相机发送 http 请求以接收流。一切正常,除了我无法在不再需要时使用 CancellationToken 取消请求。我有以下架构:

Blazor 客户端:

// LiveCamera.razor
<img src="CameraSystem/getStream" onerror="[...]" alt="">

ASP.NET 核心服务器:

// CameraSystemController.cs
[ApiController]
[Route("[controller]")]
public class CameraSystemController : Controller
{
    [HttpGet("getStream")]
    public async Task<IActionResult> GetStream()
    {
        Stream stream = await Device_CameraStandard.GetStream();
        if (stream != null) {
            Response.Headers.Add("Cache-Control", "no-cache");
            FileStreamResult result = new FileStreamResult(stream, _contentTypeStreaming) {
                EnableRangeProcessing = true
            };
            return result;
        } else {
            return new StatusCodeResult((int)HttpStatusCode.ServiceUnavailable);
        }
    }
}

访问相机的类:

// Device_CameraStandard.cs
internal class Device_CameraStandard
{
    private HttpClient _httpClient;
    private static CancellationTokenSource _tokenSource;
    private System.Timers.Timer _keepAliveTimer;
    
    internal Device_CameraStandard() {
        _keepAliveTimer = new System.Timers.Timer();
        _keepAliveTimer.Interval = 3000;
        _keepAliveTimer.Elapsed += KeepAliveTimeout;
        _tokenSource = new CancellationTokenSource();
        [...]
    }
    
    internal async Task<Stream> GetStream()
    {
        return await _httpClient.GetStreamAsync("http://[...]/axis-cgi/mjpg/video.cgi?&camera=1", _tokenSource.Token);
    }
    
    // Invoked periodically by client from LiveCamera.razor.cs, not included here
    internal void KeepAlive()
    {
        LLogger.Debug("KeepAlive!");
        _keepAliveTimer.Stop();
        _keepAliveTimer.Start();
    }
    
    private void KeepAliveTimeout(object sender, ElapsedEventArgs e)
    {
        LLogger.Debug("Timeout!");
        _keepAliveTimer.Stop();
        _tokenSource.Cancel();
        _tokenSource.Dispose();
        _tokenSource = new CancellationTokenSource();
    }
}

但是,即使所有客户端都离开 LiveCamera.razor 页面并且 _keepAliveTimer 已过并且 CancellationTokenSource 被取消,请求也不会被取消。我可以从带宽使用量没有减少的事实中看出这一点(“接收”带宽,表明服务器仍在从相机接收数据),只有在我关闭浏览器选项卡时才会减少。

你能帮我理解我做错了什么吗?谢谢

编辑:最后,即使遵循了在使用返回流的所有代码部分中观察令牌的建议,包括控制器,我最终发现标签

// LiveCamera.razor
<img src="CameraSystem/getStream" onerror="[...]" alt="">

导致客户端永远不会停止发送请求。因此,我不得不使用一种解决方法来强制客户端在离开 LiveCamera.razor 页面之前停止发送请求。

标签: asp.net-coreblazor-webassemblycancellationtokensourcecancellation-token

解决方案


推荐阅读