C#/ASP.NET Core Web API中MongoDB嵌套对象数据获取异常排查
问题描述
MongoDB数据结构
{"_id": "6602fc150d713b8f94494338","type": "Brands","screenContext": {"title": "","handle": "tapas-products","media": [],"styles": {},"additionalInfo": {},"translations": {}},"sections": {"name": "Category 3x3","type": "categories","sectionPosition": 1,"styles": {"containerStyle": {},"titleNViewAllSecStyle": {},"tileStyle": {"tileSec": {"width": "48%","marginHorizontal": "1%"},"tileImageSec": {},"tileImage": {"width": 160,"height": 160},"titleStyle": {}}},"additionalInfo": {"numOfColumns": 2,"noOfTilesOnMainView": 4,"showLabel": true},"subSections": [{"title": "Offers","handle": "frontpage","image": "products/abc.jpg","navigation": {"tab": "AgriStoreTab","screen": "AgriStoreProductsList","params": {"nextScreenParamName": "currentScreenPayloadName"}},"additionalInfo": {},"styles": {},"translations": {"te": {"title": "ఆఫర్"},"hi": {"title": "ऑफ़र"},"ta": {"title": "சலுகை"},"kn": {"title": "ಆಫರ్"}}},"translations": {"te": {},"hi": {},"ta": {},"kn": {}}}}
C# 查询方法
public async Task<dynamic> GetAppScreensData(string type, string handle) { try { var pipeline = new[] { new BsonDocument("$match", new BsonDocument { { "type", type }, { "screenContext.handle", handle } }), new BsonDocument("$unwind", "$sections"), new BsonDocument("$sort", new BsonDocument("sections.sectionPosition", 1)) }; var query = pipeline.ToJson(); var data = await _context.AppScreens.Aggregate<BsonDocument>(pipeline).ToListAsync().ConfigureAwait(false); var list = data.ConvertAll(BsonTypeMapper.MapToDotNetValue); var json = JsonConvert.SerializeObject(list); var screenResponseList = JsonConvert.DeserializeObject<List<dynamic>>(json); if (screenResponseList.Count > 0) { var appScreenResponse = screenResponseList.FirstOrDefault(); return appScreenResponse; } return new {}; } catch (Exception ex) { throw new ex; } }
问题现象
调试时能正常获取响应,但Postman返回的所有字段均为嵌套空数组形式,且重复返回多条相同异常结构数据。尝试过IEnumerable、BsonDocument、dynamic等返回类型均无效,因MongoDB数据存在动态嵌套,无法使用固定模型。
问题原因与解决方法
原因分析
$unwind操作误用:MongoDB数据中的sections是单个对象而非数组,$unwind是用于拆分数组的操作符,对单个对象执行会破坏原始数据结构,导致后续序列化出现异常。- 冗余序列化/反序列化:将
BsonDocument转成.NET对象后,又序列化为JSON再反序列化为List<dynamic>,多次类型转换会丢失动态嵌套结构的类型信息,引发输出异常。 - 异常处理语法错误:
throw new ex;是无效语法,正确写法应为throw ex;或throw;,错误的异常抛出会干扰正常响应输出。
解决方法
1. 修正聚合管道
移除错误的$unwind步骤,因为sections不是数组:
var pipeline = new[] { new BsonDocument("$match", new BsonDocument { { "type", type }, { "screenContext.handle", handle } }), new BsonDocument("$sort", new BsonDocument("sections.sectionPosition", 1)) };
2. 简化序列化流程
直接将BsonDocument序列化为JSON返回,避免多次转换导致的类型丢失:
public async Task<IActionResult> GetAppScreensData(string type, string handle) { try { var pipeline = new[] { new BsonDocument("$match", new BsonDocument { { "type", type }, { "screenContext.handle", handle } }), new BsonDocument("$sort", new BsonDocument("sections.sectionPosition", 1)) }; var data = await _context.AppScreens.Aggregate<BsonDocument>(pipeline).FirstOrDefaultAsync().ConfigureAwait(false); if (data != null) { var json = data.ToJson(new JsonWriterSettings { OutputMode = JsonOutputMode.Strict }); return Content(json, "application/json"); } return Content("{}", "application/json"); } catch (Exception ex) { // 可添加日志记录逻辑 return StatusCode(500, new { error = ex.Message }); } }
3. 额外注意事项
- 若未来
sections可能变为数组,再考虑添加$unwind,但需确保仅在数组类型字段上使用该操作符。 - 避免用
dynamic作为返回类型,直接返回JSON字符串或IActionResult,能更好控制输出格式,避免ASP.NET Core自动序列化的问题。 - 修正异常处理代码,确保异常能正确抛出或返回错误响应。
内容的提问来源于stack exchange,提问作者user22213789
相关产品推荐
相关产品推荐

