.NET Minimal API异步POST查询MongoDB返回空响应问题求助
问题描述
搭建了一个Minimal API,其中POST接口/query接收原始JSON格式的查询条件以操作MongoDB,相关代码如下:
app.MapPost("/query", async (HttpContext context) => await FreeQuery(context));
FreeQuery是异步方法,返回IEnumerable<PreOrder>,但该异步版本会引发内部服务器错误,客户端收到空响应(Content-Length为0),具体实现代码:
async Task<IEnumerable<PreOrder>> FreeQuery(HttpContext context) { using (StreamReader reader = new StreamReader(context.Request.Body, Encoding.UTF8)) { string query = await reader.ReadToEndAsync(); var filter = BsonDocument.Parse(query); var result = _collection.Find(filter); var list = EnumFromBson<PreOrder>(result); Console.WriteLine(list.Count()); return list; } }
控制台打印list.Count()结果为34,但客户端获取不到有效数据。另外同步版本的GET请求可以正常工作,代码如下:
IEnumerable<PreOrder> FindByField(string field, string value) { var filter = Builders<BsonDocument>.Filter.Eq(field, value); var result = _collection.Find(filter); var list = EnumFromBson<PreOrder>(result); return list; }
解决方案
- 核心问题:MongoDB的
Find()返回的IFindFluent是延迟执行的查询对象,同步版本中调用Count()会触发立即枚举,但异步方法返回IEnumerable<PreOrder>后,ASP.NET Core框架在序列化时再去枚举时,可能因上下文资源已释放或异步状态问题导致无法获取数据。同时,异步方法中未正确使用MongoDB的异步查询API,导致查询未完成就返回了延迟枚举对象。 - 修复步骤:
- 异步获取MongoDB查询结果:将
_collection.Find(filter)改为异步获取列表,使用await result.ToListAsync(),确保数据在返回前已全部加载到内存:var result = await _collection.Find(filter).ToListAsync(); - 调整
EnumFromBson方法:修改该方法接收List<BsonDocument>(或已枚举的集合),而非IFindFluent,确保处理的是已加载的数据:// 假设原EnumFromBson是处理IFindFluent,现在改为处理List<BsonDocument> List<PreOrder> EnumFromBson<T>(List<BsonDocument> documents) { // 自定义转换逻辑 } - 返回具体集合类型而非
IEnumerable:将方法返回类型改为Task<List<PreOrder>>,返回已加载的列表,避免延迟执行带来的序列化问题:async Task<List<PreOrder>> FreeQuery(HttpContext context) { using (StreamReader reader = new StreamReader(context.Request.Body, Encoding.UTF8)) { string query = await reader.ReadToEndAsync(); var filter = BsonDocument.Parse(query); var result = await _collection.Find(filter).ToListAsync(); var list = EnumFromBson<PreOrder>(result); Console.WriteLine(list.Count); return list; } } - 简化请求体读取:在Minimal API中可以直接绑定JSON到
BsonDocument,无需手动读取Stream,代码更简洁且不易出错:app.MapPost("/query", async (BsonDocument filter, IMongoCollection<BsonDocument> collection) => { var result = await collection.Find(filter).ToListAsync(); var list = EnumFromBson<PreOrder>(result); return list; });
- 异步获取MongoDB查询结果:将
- 验证逻辑:修改后,返回的
List<PreOrder>是已完全加载的集合,ASP.NET Core框架可以正常序列化为JSON响应,客户端能正确接收数据。
内容的提问来源于stack exchange,提问作者Serve Laurijssen
相关产品推荐
相关产品推荐

