zoukankan      html  css  js  c++  java
  • 在Asp.net core返回PushStream

    最近用asp.net core webapi实现了一个实时视频流的推送功能,在Asp.net中,这个是通过PushStreamContent来实现的。

    基于对asp.net core的知识,随手写了一个(要求控制器继承自Controller基类)

    [HttpGet]
    public async Task Get()
    {
        var response = HttpContext.Response;
        response.ContentType = "text/html";
        response.StatusCode = 200;
        var stream = HttpContext.Response.Body;
    
        while (true)
        {
            await Task.Delay(1000);
            var content = DateTime.Now + @"<br>";
            var data = Encoding.Default.GetBytes(content);
            await stream.WriteAsync(data, 0, data.Length);
            await stream.FlushAsync();
        }
    }

    使用chrome调试这个接口时,发现它确实行之有效的将当前的时间推送到了浏览器的页面上。

    然而,当我进一步的调试它的异常情况时,发现就算将chrome关掉,这个程序却依然在继续运行。从调试器中看到stream的状态为Aborted,已经识别到位终止的流了。

      

    并且从VS的调试窗口也能看到异常信息:

      

    但下面这两行就是不抛异常:

    await stream.WriteAsync(data, 0, data.Length);
    await stream.FlushAsync();

    单单从接口的实现角度上来看,这个已经不合理了。这是一个很大的坑,功能看上去还是正确的,没有详细调试还看不出来。一个不留神就踩上了。不知道微软为什么要这么设计。

    埋怨归埋怨,问题还是要解决的。我查看了下FileStreamResult的源码,发现它是靠HttpContext.RequestAborted来判断客户端是否终止了的。这是一个CancellationToken类型的对象,当客户端连接断开后,它就处于被取消的状态。

    知道原因后,就可以知道如何修改我的程序了。

    [HttpGet]
    public async Task Get()
    {
        var cancel = HttpContext.RequestAborted;
     
        var response = HttpContext.Response;
        response.ContentType = "text/html";
        response.StatusCode = 200;
        var stream = HttpContext.Response.Body;
     
        while (true)
        {
            cancel.ThrowIfCancellationRequested();
            await Task.Delay(1000, cancel);
            var content = DateTime.Now + @"<br>";
            var data = Encoding.Default.GetBytes(content);
            await stream.WriteAsync(data, 0, data.Length, cancel);
            await stream.FlushAsync(cancel);
        }
    }

    再然后就是封装了,我这里将其封装为了一个PushStreamResult,这样就可以在PocoController中使用了。

    class MyPushStreamResult :IActionResult
    {
        Func<Stream, CancellationToken, Task> _pushAction;
        string _contentType;
     
        public MyPushStreamResult(Func<Stream, CancellationToken, Task> pushAction, string contentType)
        {
            _pushAction = pushAction;
            _contentType = contentType;
        }
    
        public Task ExecuteResultAsync(ActionContext context)
        {
            var response = context.HttpContext.Response;
            response.ContentType = _contentType;
            response.StatusCode = 200;
     
    
            return _pushAction(response.Body, context.HttpContext.RequestAborted);
        }
    }

    使用方法如下:

    [HttpGet]
    public IActionResult Get()
    {
        return new MyPushStreamResult(pushData, "text/html");
    }
     
    async Task pushData(Stream stream, CancellationToken cancel)
    {
        while (true)
        {
            if (cancel.IsCancellationRequested)
                return;
            await Task.Delay(1000, cancel);
            var content = DateTime.Now + @"<br>";
            var data = Encoding.Default.GetBytes(content);
            await stream.WriteAsync(data, 0, data.Length, cancel);
            await stream.FlushAsync(cancel);
        }
    }
  • 相关阅读:
    python 判断返回结果 in用法
    关于requests的session方法保持不了cookie的问题。(seesion的意思是保持一个会话,比如 登陆后继续操作(记录身份信息) 而requests是单次请求的请求,身份信息不会被记录)
    python-selenium并发执行测试用例(方法一 各模块每一条并发执行)
    python 正则表达提取方法 (提取不来的信息print不出来 加个输出type 再print信息即可)
    unittest框架 assertEqual 报错 让其出现中文的方法(这个问题出现时 我找了老半天) 还追加了 报错信息自定义的方法
    python 指定文件编码的方法
    解决python中路径中包含中文无法找到文件的问题
    python 字符转换记录
    python-selenium 并发执行用例的问题
    深度影响价值
  • 原文地址:https://www.cnblogs.com/TianFang/p/8502770.html
Copyright © 2011-2022 走看看