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

如何在ASP.NET Core Web API的JSON结果中仅返回接口成员

问题描述

我有一个简单的API,用于从数据库返回行列表,代码如下:

[HttpGet]
[Route("list/{count}")]
public async Task<ActionResult<IEnumerable<IResult>>> GetRows(int count)
{
    var list = await dbc.GetList(count);
    return new JsonResult( list.ToList<IResult>() );
}

数据库返回的行包含id、name、status等属性,而接口仅包含其中的子集,定义如下:

public class Result
{
   int id { get; set; }
   string name { get; set; }
   int status { get; set; }
}

public interface IResult
{
   int id { get; set; }
   string name { get; set; }
}

我目前使用.ToList<IResult>()来确保JSON结果仅包含接口中的字段,请问有没有比先转换为List更优、更高效的实现方式?

优化实现方案

下面几种方式都比直接转换List更高效,各有适用场景:

  • 查询阶段直接投影(性能最优)
    不要先加载完整的Result对象,而是在数据库查询时就只选择需要的字段,这样既减少数据库传输的数据量,又避免了后续的类型转换操作。如果你的dbc.GetList(count)是基于IQueryable的,可以直接修改查询逻辑:

    [HttpGet]
    [Route("list/{count}")]
    public async Task<ActionResult<IEnumerable<IResult>>> GetRows(int count)
    {
        var list = await dbc.Results // 假设这是你的DbSet
                            .Take(count)
                            .Select(r => new Result { id = r.id, name = r.name }) // 仅选择接口需要的字段
                            .Cast<IResult>()
                            .ToListAsync();
        return list;
    }
    

    部分ORM支持直接投影到接口,也可以简化为:

    .Select(r => new IResult { id = r.id, name = r.name })
    

    这种方式从根源上减少了不必要的数据加载,性能提升最明显。

  • 通过序列化配置过滤字段
    如果你不想修改查询逻辑,可以直接配置JSON序列化器,让它只序列化IResult接口定义的属性,这样直接返回原始的Result集合即可,不需要转换类型:
    以System.Text.Json为例:

    [HttpGet]
    [Route("list/{count}")]
    public async Task<ActionResult<IEnumerable<IResult>>> GetRows(int count)
    {
        var list = await dbc.GetList(count);
        return Json(list, new JsonSerializerOptions
        {
            Converters = { new InterfaceProjectionConverter<IResult>() }
        });
    }
    
    // 自定义转换器,仅序列化接口属性
    public class InterfaceProjectionConverter<TInterface> : JsonConverter<TInterface>
    {
        public override TInterface Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
    
        public override void Write(Utf8JsonWriter writer, TInterface value, JsonSerializerOptions options)
        {
            var interfaceProps = typeof(TInterface).GetProperties();
            writer.WriteStartObject();
            foreach (var prop in interfaceProps)
            {
                writer.WritePropertyName(prop.Name);
                JsonSerializer.Serialize(writer, prop.GetValue(value), options);
            }
            writer.WriteEndObject();
        }
    }
    

    用Newtonsoft.Json的话,可以通过自定义ContractResolver实现同样的效果,同样无需转换集合。

  • 使用AutoMapper的ProjectTo(适合多场景复用)
    如果项目中已经在用AutoMapper,可以用ProjectTo<IResult>()方法,它会在IQueryable层面进行投影,只查询需要的字段,同时自动映射到接口类型:

    [HttpGet]
    [Route("list/{count}")]
    public async Task<ActionResult<IEnumerable<IResult>>> GetRows(int count)
    {
        var list = await dbc.GetListQueryable(count) // 需要返回IQueryable<Result>
                            .ProjectTo<IResult>(_mapper.ConfigurationProvider)
                            .ToListAsync();
        return list;
    }
    

    这种方式适合需要在多个地方复用相同映射规则的场景,代码更简洁可维护。

内容的提问来源于stack exchange,提问作者Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:24:55