asp.net 5/mvc 6中的PushStreamContent不起作用

本文关键字:中的 PushStreamContent 不起作用 mvc net asp | 更新日期: 2023-09-27 18:24:09

我正在尝试将一个使用PushStreamContent的web api项目(经典的web.config项目)迁移到最新的asp.net 5 web应用程序(project.json)。

我的问题是我无法让PushStreamContent工作。

当我使用这个api控制器时,结果将以json格式而不是流形式结束:

[Route("api/[controller]")]
public class EventsController : Controller
{
    private static readonly ConcurrentQueue<StreamWriter> s_streamWriter = new ConcurrentQueue<StreamWriter>();
   [HttpGet]
    public HttpResponseMessage Get(HttpRequestMessage request)
    {
         HttpResponseMessage response = request.CreateResponse();
        response.Content = new PushStreamContent(new Action<Stream, HttpContent, TransportContext>(WriteToStream), "text/event-stream");
        return response;
    }
    private void WriteToStream(Stream outputStream, HttpContent headers, TransportContext context)
    {
        var streamWriter = new StreamWriter(outputStream) {AutoFlush = true};
        s_streamWriter.Enqueue(streamWriter);
    }
}

如果我更改控制器操作以返回任务并将PushStreamContent包装在类MyPushStreamResult中,如下所示:

[HttpGet]
public async Task<IActionResult> Get(HttpRequestMessage request)
{
    var stream = new PushStreamContent(new Action<Stream, HttpContent, TransportContext>(WriteToStream), "text/event-stream");
    return new MyPushStreamResult(stream, "text/event-stream");
}
public class MyPushStreamResult : ActionResult
{
    public string ContentType { get; private set; }
    public PushStreamContent Stream { get; private set; }
    public MyPushStreamResult(PushStreamContent stream, string contentType)
    {
        Stream = stream;
        ContentType = contentType;
    }
    public override async Task ExecuteResultAsync(ActionContext context)
    {
        var response = context.HttpContext.Response;
        response.ContentType = ContentType;
        await Stream.CopyToAsync(response.Body);
    }
}

对我的控制器操作的请求现在返回了一个流,但在服务器端关闭或包含大量数据之前,流没有刷新。当我将数据推送到PushStreamContent输出流时,我会在每次文本写入后刷新,但我想刷新不在响应上。身体流。

我想念什么?找不到任何具有asp.net 5结构的示例。

asp.net 5/mvc 6中的PushStreamContent不起作用

HttpResponseMessage在ASP.NET 5中不会得到特殊处理,除非您使用的是Microsoft.AspNet.Mvc.WebApiCompatShim包。如果您可以使用ASP.NET 5功能来执行类似的操作,并且创建此程序包是为了支持向后兼容性,则不推荐使用此程序包。

因此,由于HttpResponseMessage并不被认为是特殊的,它被JsonOutuptFormatter呈现为json,就像任何其他.NET对象一样

您当前可以通过HttpContext.Response.Body属性直接访问响应流,而不是PushStreamContent,因此您可以直接写入流。

更新
Web API中的PushStreamContent允许您直接写入响应流。此类型是由Web API团队创建的,不作为System.Net.Http库的一部分(所有其他内容类型都存在),因此可以直接写入流,例如,从控制器或过滤器等。PushStreamContent的替代方案是StreamContent,它只允许您提供Stream对象,然后主机层从源流"复制"数据(如"拉取"数据)。此外,PushStreamContent本身并没有什么特别之处。人们可以编写自己的类型,该类型源自CCD_ 10。

总之,PushStreamContent允许直接写入响应流,就像在ASP.NET 5中一样,我们可以直接访问该流,因此您可以写入它

更新:
在最基本的形式上(对,您可以转换为actionresult以进行可测试性),以下内容应该有效。

[HttpGet]
public Task Get()
{
    HttpContext.Response.ContentType = "text/event-stream";
    var sourceStream = // get the source stream
    return sourceStream.CopyToAsync(HttpContext.Response.Body);
}

正如@Thieme在@Kiran帖子上评论的那样,这里提到的关键是使用await HttpContext.Response.Body.FlushAsync();

例如:

[Route("/api/sse")]
public class ServerSentEventController : Controller
{
    [HttpGet]
    public async Task Get()
    {
        var response = Response;
        response.Headers.Add("Content-Type", "text/event-stream");
        for(var i = 0; true; ++i)
        {
            await response
                .WriteAsync($"data: Controller {i} at {DateTime.Now}'r'r");
            response.Body.Flush();
            await Task.Delay(5 * 1000);
        }
    }
}

您应该在操作任务继续的同时刷新Body流。