如何在 protobuf-net.grpc 的消息中使用 IAsyncEnumerable?

How to use IAsyncEnumerable within a message in protobuf-net.grpc?

所以,最近我在 IAsyncEnumerable<T> 的帮助下了解了如何使用 protobuf-net.grpc 进行流式处理。这一切都很好,但我现在遇到了一些问题。

对于我的一些调用,我想用一些元数据和流作为参数来调用。

例如:

[OperationContract]
Task<bool> UploadPicture(ProfilePictureQuery query);

签名如下:

[ProtoContract]
public class ProfilePictureQuery
{
    [ProtoMember(1)]
    public IAsyncEnumerable<byte[]> RawDataStream { get; set; }

    [ProtoMember(2)]
    public string FileExtension { get; set; }
}

但是,当尝试调用它时,我遇到了类似 'Status(StatusCode=Unimplemented, Detail="Method is unimplemented.") 的异常。我知道状态响应有点神秘,所以我发现这实际上只是参数的问题。

那我该怎么做呢?

我也试过用下面的签名来做:

[OperationContract]
Task<bool> UploadPicture(IAsyncEnumerable<byte[]> rawDataStream, string fileExtension);

结果相同,因为我显然只被允许提供一个参数(符合 grpc 定义的一个消息参数和一个响应输出)。

太好了,那我该怎么做?

这里有两个不同的概念:

  • gRPC 允许通过 IAsyncEnumerable<T> 的消息流(而不是单个消息的 Task<T>
  • 但是,每条消息都必须完整且独立;编组器(per-message 序列化程序)仅同步

因此:您可以将 IAsyncEnunerable<T> 用作服务方法的参数或 return,但不能用作消息的字段。

如果您需要提供流和额外的元数据,有几个选项:

  • 使用 http headers(通过 CallContext 作为第二个参数)
  • 有两个服务调用 - 一个启动事物并获取元数据,一个 return流
  • 在消息中有一个包含一些可选字段的流,并且只填充第一条或最后一条消息中的可选字段