c# - 是否可以在长时间运行的请求中通过 ServiceStack 流式传输部分结果?

标签 c# angular http servicestack httpresponse

我的 ServiceStack API 上有一个长时间运行的数据库复制请求。完成后,它会返回数据库复制过程的日志。

我希望响应返回每一行,因为它被添加到包含数据库复制日志的列表对象中。

响应将由 angular4 应用程序接收,所以我想如果这可能的话,我还需要在 angular4 中配置一些东西以在每次响应更新时更改状态 (ngrx)。

老实说,我不确定从哪里开始。

有人有什么想法吗?

最佳答案

流式传输到 ServiceStack 中的响应你只需要直接写入 IResponse.OutputStream,你可以在你的服务中这样做:

public async Task Any(MyRequest request)
{
    foreach (var chunk in Chunks)
        await base.Response.OutputStream.WriteAsync(chunk, 0, chunk.Length);
}

或者通过返回实现IStreamWriterAsyncIStreamWriter 的结果,例如:

public class StreamChunksResponse : IStreamWriterAsync
{
    public IEnumerable<byte[]>> Chunks { get; set; }

    public async Task WriteToAsync(
        Stream responseStream, 
        CancellationToken token = default(CancellationToken))
    {
        foreach (var chunk in Chunks)
            await responseStream.WriteAsync(chunk, 0, chunk.Length);
    }
}

这将为不缓冲响应的主机写入响应输出流,对于 IIS/ASP.NET,您需要确保 Response Buffering is disabled .

然后问题就变成了如何处理客户端的部分响应,这需要通过使用 readyState == 3 处理响应来针对浏览器的 XMLHttpRequest API 手动编码,例如:

<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', '/stream');
xhr.seenBytes = 0;

xhr.onreadystatechange = function() {
  console.log("state change.. state: "+ xhr.readyState);

  if(xhr.readyState == 3) {
    var newData = xhr.response.substr(xhr.seenBytes);
    console.log("newData: <<" +newData+ ">>");
    document.body.innerHTML += "New data: <<" +newData+ ">><br />";

    xhr.seenBytes = xhr.responseText.length;
    console.log("seenBytes: " +xhr.seenBytes);
  }
};

xhr.addEventListener("error", function(e) {
  console.log("error: " +e);
});

console.log(xhr);
xhr.send();
</script>

这很快就会变得笨拙,尤其是当您尝试流式传输像 JSON 这样的序列化格式时,您需要确保客户端可以构建有效的 JSON 片段。

如果您只是想在客户端下载整个响应时通知客户端更新,我建议使用类似 Server Events 的东西您在将响应流式传输到客户端的同时逐步发送客户端通知更新。

关于c# - 是否可以在长时间运行的请求中通过 ServiceStack 流式传输部分结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46688354/

相关文章:

Javascript My Array Push 仅获取最后一个值

angular - 如何在 ngFor 中将对象作为组件输入传递

c# .NET multipart/form-data 上传文件

Cordova 地理定位插件 getCurrentPosition 已弃用

c# - 如何在 ASP.NET + C# 中裁剪 mp3?

c# - 无法在 SQL 中创建程序集 'System.ServiceModel.Internals'

c# - 列表框中的 WPF 数据模板多态性

javascript - 将当前值的 html.dropdownlist 传递给 Actionlink?

angular - 使用 XLSX(表格到工作表)导出 html 表格时隐藏/删除列

http - 我如何告诉 Rust 中的 std::io::copy 停止阅读并完成写作?