Asp.net core 如何在asp.net core中写入Response.Body时检测客户端何时关闭流

Asp.net core 如何在asp.net core中写入Response.Body时检测客户端何时关闭流,asp.net-core,Asp.net Core,我试图编写一个无限长的响应体,并检测客户端何时断开连接,以便停止编写。我习惯于在客户端关闭连接时出现套接字异常或类似情况,但直接写入Response.Body时似乎不会出现这种情况。我可以关闭客户端应用程序,服务器端只需继续编写。我已经在下面包含了相关代码。完全有可能有更好的方法,但我想到了这一点。基本上,我有一个实时视频饲料应该永远持续下去。我以分块内容(无内容长度,在每个视频帧后刷新)的形式向ResponseBook写信。视频帧是通过程序中其他地方的事件回调接收的,因此我订阅控制器方法中的事

我试图编写一个无限长的响应体,并检测客户端何时断开连接,以便停止编写。我习惯于在客户端关闭连接时出现套接字异常或类似情况,但直接写入Response.Body时似乎不会出现这种情况。我可以关闭客户端应用程序,服务器端只需继续编写。我已经在下面包含了相关代码。完全有可能有更好的方法,但我想到了这一点。基本上,我有一个实时视频饲料应该永远持续下去。我以分块内容(无内容长度,在每个视频帧后刷新)的形式向ResponseBook写信。视频帧是通过程序中其他地方的事件回调接收的,因此我订阅控制器方法中的事件,然后强制它在等待任务中保持打开状态。延迟循环,以便响应流不会关闭。H264PacketReceived的回调正在将数据格式化为流式mp4文件,并将其写入响应流。这一切似乎都很好,我可以用ffmpeg或chrome播放实时流,但当我关闭客户端应用程序时,我没有得到任何异常或任何东西。它只是不断地写入流,没有任何错误

 public class LiveController : ControllerBase
    {
        [HttpGet]
        [Route("/live/{cameraId}/{stream}.mp4")]
        public async Task GetLiveMP4(Guid cameraId, int stream)
        {
            try
            {
                Response.StatusCode = 200;
                Response.ContentType = "video/mp4";
                Response.Headers.Add("Cache-Control", "no-store");
                Response.Headers.Add("Connection", "close");
                ms = Response.Body;                
                lock (TCPVideoReceiver.CameraStreams)
                {
                    TCPVideoReceiver.CameraStreams.TryGetValue(cameraId, out cameraStream);
                }

                if (this.PacketStream == null)
                {
                    throw new KeyNotFoundException($"Stream {cameraId}_{stream} not found");
                }
                else
                {
                    connected = true;

                    this.PacketStream.H264PacketReceived += DefaultStream_H264PacketReceived;
                    this.PacketStream.StreamClosed += PacketStream_StreamClosed;
                }

                while(connected)
                {
                    await Task.Delay(1000);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            finally
            {
                connected = false;
                this.PacketStream.H264PacketReceived -= DefaultStream_H264PacketReceived;
                this.PacketStream.StreamClosed -= PacketStream_StreamClosed;
            }
        }

        private bool connected = false;
        private PacketStream PacketStream;
        private Mp4File mp4File;
        private Stream ms;

        private async void PacketStream_StreamClosed(PacketStream source)
        {
    await Task.Run(() =>
    {
                try
                {
                    Console.WriteLine($"Closing live stream");
                    connected = false;                    
                    ms.Close();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            });
        }

        private async void DefaultStream_H264PacketReceived(PacketStream source, H264Packet packet)
        {
            try
            {
                if (mp4File == null && packet.IsIFrame)
                {
                    mp4File = new Mp4File(null, packet.sps, packet.pps);
                    var _p = mp4File.WriteHeader(0);
                    await ms.WriteAsync(mp4File.buffer, 0, _p);
                }
                if (mp4File != null)
                {
                    var _p = mp4File.WriteFrame(packet, 0);
                    var start = mp4File._moofScratchIndex - _p;
                    if (_p > 0)
                    {
                        await ms.WriteAsync(mp4File._moofScratch, start, _p);
                        await ms.FlushAsync();
                    }
                }
                return;
            }
            catch (Exception ex)
            {
                connected = false;
                Console.WriteLine(ex.ToString());
            }
        }

回答我自己的问题

当客户端断开mvc核心连接时,设置取消令牌HttpContext.RequestAborted

通过监视和/或使用该取消令牌,您可以检测到断开连接并清除所有内容

也就是说,可以通过创建封装事件处理(生产者/消费者)的自定义流来改进整个设计。然后控制器的动作可以减少到

return File(new MyCustomStream(cameraId, stream), "video/mp4");
File方法已经监视了取消令牌,一切都如您所期望的那样工作