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

如何在ASP.NET Web API C#中返回指定格式的JSON数组

解决ASP.NET Web API返回嵌套JSON结构的问题

看起来你的核心问题是:EF自动生成的存储过程结果类是扁平结构,直接返回List会输出扁平的JSON数组,但你需要的是多层嵌套的目标结构。下面是一步步的解决方案:

1. 创建匹配目标JSON的DTO类

首先,我们需要定义和目标JSON结构完全对应的数据传输对象(DTO),因为EF生成的实体类无法直接映射嵌套结构:

// 最内层的子区域明细
public class SubDistDetail
{
    public string SubDistBbsID { get; set; }
    public string Amount { get; set; } // 匹配目标的字符串类型
    public string Hail { get; set; }
    public string Date { get; set; }
}

// 区域层级明细
public class DistDetail
{
    public string DistBbsID { get; set; }
    public string SubDistCount { get; set; }
    public string Amount { get; set; }
    public string Hail { get; set; }
    public List<SubDistDetail> DistDetails { get; set; }
}

// 大区域汇总层级
public class AreaDetail
{
    public string AreaBbsID { get; set; }
    public string DistCount { get; set; }
    public string SubDistCount { get; set; }
    public string Amount { get; set; }
    public string Hail { get; set; }
    public List<DistDetail> ArealDetails { get; set; }
}

// 最外层根对象,匹配目标的JSON结构
public class RainfallAreaAVGResponse
{
    public List<AreaDetail> RainfallAreaAVG { get; set; }
}

2. 修改控制器方法,组装嵌套数据

接下来,需要修改控制器方法,同时调用两个存储过程获取汇总和明细数据,通过LINQ分组、投影把扁平数据转换成嵌套结构。另外要解决原来两个GetRainfall方法的路由冲突问题:

namespace RainfallService.Controllers 
{ 
    public class DistAVGController : ApiController 
    { 
        // 返回嵌套的目标JSON结构
        [HttpGet]
        [Route("api/DistAVG/RainfallSummary")] // 自定义路由避免方法冲突
        public RainfallAreaAVGResponse GetRainfallSummary(string distBbsID, string entryDate) 
        { 
            using (var db = new Farmer_WebEntities()) 
            { 
                // 获取汇总数据
                var summaryData = db.SP_GetRainfallByDistDateAVG(distBbsID, entryDate).ToList();
                // 获取明细数据
                var detailData = db.SP_GetRainfallByDistDateAVGDetails(distBbsID, entryDate).ToList();

                // 组装嵌套结构
                var response = new RainfallAreaAVGResponse
                {
                    RainfallAreaAVG = summaryData
                        .GroupBy(s => s.AreaBbsId) // 按大区域分组
                        .Select(areaGroup => new AreaDetail
                        {
                            AreaBbsID = areaGroup.Key,
                            DistCount = areaGroup.Select(s => s.DistBbsID).Distinct().Count().ToString(),
                            SubDistCount = areaGroup.Sum(s => s.SubDistCount ?? 0).ToString(),
                            Amount = areaGroup.Sum(s => s.Amount ?? 0).ToString(),
                            Hail = areaGroup.Sum(s => s.Hail ?? 0).ToString(),
                            ArealDetails = areaGroup
                                .GroupBy(s => s.DistBbsID) // 按区域分组
                                .Select(distGroup => new DistDetail
                                {
                                    DistBbsID = distGroup.Key,
                                    SubDistCount = distGroup.Sum(s => s.SubDistCount ?? 0).ToString(),
                                    Amount = distGroup.Sum(s => s.Amount ?? 0).ToString(),
                                    Hail = distGroup.Sum(s => s.Hail ?? 0).ToString(),
                                    DistDetails = detailData
                                        .Where(d => d.AreaBbsId == areaGroup.Key && d.DistBbsID == distGroup.Key)
                                        .Select(d => new SubDistDetail
                                        {
                                            SubDistBbsID = d.SubDistBbsId,
                                            Amount = (d.Amount ?? 0).ToString(),
                                            Hail = (d.Hail ?? 0).ToString(),
                                            Date = entryDate // 用传入的entryDate填充Date字段
                                        }).ToList()
                                }).ToList()
                        }).ToList()
                };

                return response;
            } 
        } 

        // 保留原有的明细接口(如果需要),修正路由和参数
        [HttpGet]
        [Route("api/DistAVG/RainfallDetails")]
        public List<SP_GetRainfallByDistDateAVGDetails_Result> GetRainfallDetails(string distBbsID, string entryDate, string type) 
        { 
            using (var db = new Farmer_WebEntities()) 
            { 
                // 注意:原代码未使用type参数,若存储过程需要该参数,请补充到调用中
                var rainfalls = db.SP_GetRainfallByDistDateAVGDetails(distBbsID, entryDate).ToList(); 
                return rainfalls; 
            } 
        } 
    } 
}

3. 调整Web API序列化设置(可选)

如果你的目标JSON属性名是大驼峰格式(比如AreaBbsID),上面的DTO已经用了和目标一致的命名,序列化会自动匹配。若需要更灵活的命名控制,可以在WebApiConfig里调整:

// 保留属性原有的大小写格式(匹配目标的大驼峰)
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver();

// 若需要驼峰命名可启用下面的代码,但你的目标是大驼峰,所以不需要
// config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

为什么原来的代码不行?

你之前直接返回EF生成的List<SP_GetRainfallByDistDateAVG_Result>,这些类是扁平结构,Web API会直接将其序列化为扁平的JSON数组;而你需要的是多层嵌套的层级结构,所以必须手动将扁平数据组装成嵌套的DTO对象才能输出目标格式。

内容的提问来源于stack exchange,提问作者sydur.rahman21

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:09:08