gRPC Code First客户端疑问:如何获取IAsyncStreamReader?
gRPC Code First客户端流式调用解决方案
服务端定义中的IAsyncStreamReader<FileChunk>是服务端用来读取客户端发送流数据的对象,客户端无需手动创建该对象,只需通过gRPC Code First提供的客户端API发送流数据即可,以下是两种常用实现方式:
方式一:用IAsyncEnumerable简化调用
如果文件块可以通过异步枚举生成,直接传入方法即可:
private readonly IFileStorageService _fileStorageService; public async Task UploadFile(string filePath) { // 封装文件块异步生成逻辑 async IAsyncEnumerable<FileChunk> GenerateFileChunks() { using var fileStream = File.OpenRead(filePath); var buffer = new byte[4096]; int bytesRead; while ((bytesRead = await fileStream.ReadAsync(buffer)) > 0) { yield return new FileChunk { Data = buffer.Take(bytesRead).ToArray(), // 按需填充文件名、块序号等字段 }; } } // 调用服务接口,传入异步枚举 var response = await _fileStorageService.StoreFile(GenerateFileChunks(), new CallContext()); // 处理上传响应 Console.WriteLine($"上传完成,文件ID:{response.FileId}"); }
方式二:手动控制流式调用(更灵活)
如果需要精细控制发送过程(比如进度监控、中途取消),可以使用CallAsync方法获取流式调用对象:
private readonly IFileStorageService _fileStorageService; public async Task UploadFile(string filePath) { // 获取流式调用实例 using var call = _fileStorageService.StoreFileCallAsync(); // 读取文件并逐块发送 using var fileStream = File.OpenRead(filePath); var buffer = new byte[4096]; int bytesRead; while ((bytesRead = await fileStream.ReadAsync(buffer)) > 0) { await call.RequestStream.WriteAsync(new FileChunk { Data = buffer.Take(bytesRead).ToArray() }); Console.WriteLine($"已发送 {bytesRead} 字节"); } // 通知服务端数据发送完成 await call.RequestStream.CompleteAsync(); // 等待服务端响应 var response = await call.ResponseAsync; Console.WriteLine($"上传完成,响应消息:{response.Message}"); }
额外说明
- 若需设置超时、元数据等,可将
CallContext替换为CallOptions:var callOptions = new CallOptions { Deadline = DateTime.UtcNow.AddMinutes(5), Headers = new Metadata { { "Authorization", "Bearer your-token" } } }; var response = await _fileStorageService.StoreFile(GenerateFileChunks(), callOptions); - Code First客户端会自动完成
IAsyncEnumerable到服务端IAsyncStreamReader的适配,无需手动转换。
内容的提问来源于stack exchange,提问作者Branislav B.
相关产品推荐
相关产品推荐

