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

ASP.NET Core Web API如何仅返回子对象ID?

使用特性实现ASP.NET Core Web API子对象仅返回Id

可以通过自定义特性结合JSON序列化扩展来实现这个需求,无需创建大量中间DTO对象。以下是具体实现步骤:


1. 定义自定义特性

创建一个标记特性,用来标识哪些导航属性只需要返回Id:

[AttributeUsage(AttributeTargets.Property)]
public class OnlyReturnIdAttribute : Attribute
{
}

2. 标记实体类属性

在ProjectItem类中,给需要仅返回Id的导航属性添加该特性:

public class ProjectItem
{
    [Key]
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public DateTime Created { get; set; }
    // 该属性保持完整序列化
    public virtual User? CreatedByUser { get; set; }
    
    // 仅返回子项的Id
    [OnlyReturnId]
    public virtual ICollection<ProjectItem> Children { get; } = new List<ProjectItem>();
    
    // 仅返回父项的Id
    [OnlyReturnId]
    public virtual ProjectItem? Parent { get; set; }
}

3. 实现自定义JSON转换器

编写一个JSON转换器,处理带有OnlyReturnId特性的属性,序列化时仅输出Id字段:

public class OnlyReturnIdConverter : JsonConverter<object>
{
    public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 若无需反序列化,可直接抛出异常或返回默认值
        throw new NotImplementedException("反序列化功能暂未实现");
    }

    public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
    {
        // 处理集合类型(如Children)
        if (value is IEnumerable enumerable)
        {
            writer.WriteStartArray();
            foreach (var item in enumerable)
            {
                WriteSingleItem(writer, item, options);
            }
            writer.WriteEndArray();
            return;
        }

        // 处理单个对象(如Parent)
        WriteSingleItem(writer, value, options);
    }

    private void WriteSingleItem(Utf8JsonWriter writer, object? item, JsonSerializerOptions options)
    {
        if (item == null)
        {
            writer.WriteNullValue();
            return;
        }

        var idProperty = item.GetType().GetProperty("Id");
        if (idProperty == null)
        {
            // 若无Id属性,按默认规则序列化
            JsonSerializer.Serialize(writer, item, options);
            return;
        }

        var idValue = idProperty.GetValue(item);
        writer.WriteStartObject();
        writer.WritePropertyName("id");
        JsonSerializer.Serialize(writer, idValue, options);
        writer.WriteEndObject();
    }
}

4. 配置全局JSON序列化规则

在Program.cs中配置JSON选项,使用自定义契约解析器识别特性并应用转换器:

public class OnlyReturnIdContractResolver : DefaultJsonTypeInfoResolver
{
    public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
    {
        var jsonTypeInfo = base.GetTypeInfo(type, options);
        
        foreach (var property in jsonTypeInfo.Properties)
        {
            // 检查属性是否带有OnlyReturnId特性
            if (property.AttributeProvider?.GetCustomAttributes(typeof(OnlyReturnIdAttribute), inherit: true).Any() == true)
            {
                property.CustomConverter = new OnlyReturnIdConverter();
            }
        }
        
        return jsonTypeInfo;
    }
}

// 在服务配置中添加
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.ContractResolver = new OnlyReturnIdContractResolver();
        // 可选:设置驼峰命名,匹配示例响应格式
        options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    });

5. 修正控制器代码(可选)

注意到你的控制器中返回的是MyItem,但实体类是ProjectItem,需要统一类型:

[HttpGet("GetById")]
public async Task<ActionResult<ProjectItem>> GetById(int id)
{
    var item = await _context.FindAsync<ProjectItem>(id);
    if (item == null)
        return NotFound();
    return Ok(item);
}

这样配置后,接口返回的响应会自动将带有OnlyReturnId特性的属性序列化为仅含Id的对象/数组,其他属性保持完整序列化,完全符合你的期望格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 05:14:54