【问题标题】:Consuming an IAsyncEnumerable使用 IAsyncEnumerable
【发布时间】:2022-02-08 00:43:05
【问题描述】:

我有一个 Web API 应用程序,它具有需要流式传输某些数据的功能。然后我有另一个 Web 应用程序,它基本上就像代理一样。这个其他应用程序做了很多其他的事情,比如处理授权等等。它需要连接到 API 端点并通过可能对每行数据进行一些附加处理来传递流。例如,在一种情况下,它需要将该数据写入 Excel 文件。

不幸的是,我看到很多关于如何创建 IAsyncEnumerable 的教程,但没有任何关于实际连接到公开一个端点的教程。

理想情况下,我想实际包装我的 IAsyncEnumerable 并将其与其他一些东西一起返回。这就是我基本上已经对其他非流式端点所做的事情:

public class NonStreamedResult : BaseResult
{
    public SomeMetaData MetaData {get; set; }
    // here Data is usually small, so returning it all at once is no big deal
    public IEnumerable<SomeData> Data {get; set; }  
}

//....controller
public async Task<NonStreamedResult> GetNonStreamedData()

在消费端,我使用HttpClient,等待HttpResponseMessage 并使用ReadAsAsync&lt;T&gt; 将该响应转换为对象。

但是,如果我尝试这样做:

public class StreamedResult : BaseResult
{
    public SomeOtherMetaData MetaData {get; set; }
    // Here data could be huge, so we don't want to have to hold it all in memory at once
    public IAsyncEnumerable<SomeData> Data {get; set; }
}

//....controller
public async Task<StreamedResult> GetStreamedData()

当它尝试反序列化时会出错,因为它不知道将IAsyncEnumerable 转换为哪个具体类。

那么连接到使用IAsyncEnumerable 的端点的正确方法是什么将整个响应加载到内存中(显然),以便我最终可以从代理返回另一个IAsyncEnumerable应用?

如果我仍然可以把它包裹起来就好了,但如果我必须只与裸体 IAsyncEnumerable 一起工作,这并不是世界末日@

请注意,我使用的是 Microsoft.Bcl.AsyncInterfaces NuGet 包,因为我仍然针对早期版本的 .NET 框架。

【问题讨论】:

  • 接收数据时,代码必须知道数据的结束位置。在发送多个对象时,您不能在没有分隔符的情况下继续将数据附加到传输的末尾。比在接收端,您必须能够在分隔符周围拆分数据。此外,您可能不会在每次读取时收到一个对象,因此代码必须能够将异步接收数据片段附加到更大的对象中,直到找到分隔符。

标签: c# asp.net-web-api iasyncenumerable


【解决方案1】:

我仍然针对早期版本的 .NET 框架。

这不会很好地工作。 Unbuffered IAsyncEnumerable&lt;T&gt; support was added in ASP.NET 6.

如果您无法升级,那么您需要编写自己的流式 JSON 解析器和自己的流式 JSON 序列化器,并封装在定期刷新的自定义格式化程序中。这是一项不平凡的工作。我的回答的其余部分假设您将迁移到 .NET 6。

如果我仍然可以将它打包通过就好了,但如果我只需要使用裸露的 IAsyncEnumerable 就不是世界末日

包装不可能工作。只需考虑定义多个 IAsyncEnumerable&lt;T&gt; 属性的情况。在 ASP.NET 6 中处理 IAsyncEnumerable&lt;T&gt; 时,必须将其作为顶级类型返回。元数据可以表示为标题。

要使用,首先确保您设置了HttpClient 完成选项,以便在收到标头时认为HTTP 操作“完成”,然后您可以获取响应主体流并将其传递给JsonSerializer.DeserializeAsyncEnumerable。从下游 API 检索每个项目后,您可以进行任何您需要的处理,然后 yield 将其流式传输到您的客户端。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-14
    • 1970-01-01
    • 2020-03-08
    • 2020-03-21
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    相关资源
    最近更新 更多