You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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数据存在动态嵌套,无法使用固定模型。


问题原因与解决方法

原因分析

  1. $unwind操作误用:MongoDB数据中的sections是单个对象而非数组,$unwind是用于拆分数组的操作符,对单个对象执行会破坏原始数据结构,导致后续序列化出现异常。
  2. 冗余序列化/反序列化:将BsonDocument转成.NET对象后,又序列化为JSON再反序列化为List<dynamic>,多次类型转换会丢失动态嵌套结构的类型信息,引发输出异常。
  3. 异常处理语法错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 22:58:10