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

ASP.NET接口如何同时支持接收整数或对象类型的关联字段参数

实现方案

最低侵入性的方案是为System.Text.Json实现针对这类关联实体集合的泛型自定义JsonConverter,仅对标记了对应特性的属性生效,完全不影响实体其他属性的默认处理逻辑,同时可以复用在所有同类需求的接口上。

步骤1:定义通用关联实体接口

首先定义一个仅包含Id字段的公共接口,所有需要兼容「id值/实体对象」两种传入格式的关联实体都实现该接口:

public interface IAssociatedEntity
{
    int Id { get; set; }
}

// 你的Creator实体实现该接口
public class Creator : IAssociatedEntity
{
    public int Id { get; set; }
    public string? Name { get; set; }
    // 其他属性保持不变
}

步骤2:实现泛型JsonConverter

写一个可复用的集合类型转换器,自动识别数组中的整数和对象格式,统一转换为对应的关联实体实例:

using System.Text.Json;
using System.Text.Json.Serialization;

public class AssociatedEntityCollectionConverter<T> : JsonConverter<IEnumerable<T>> 
    where T : IAssociatedEntity, new()
{
    public override IEnumerable<T>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }

        if (reader.TokenType != JsonTokenType.StartArray)
        {
            throw new JsonException("Expected array for associated entity collection");
        }

        var result = new List<T>();
        while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
        {
            T entity = new T();
            switch (reader.TokenType)
            {
                // 处理纯id的情况
                case JsonTokenType.Number:
                    entity.Id = reader.GetInt32();
                    break;
                // 处理完整对象的情况
                case JsonTokenType.StartObject:
                    // 用默认逻辑反序列化对象
                    entity = JsonSerializer.Deserialize<T>(ref reader, options)!;
                    break;
                default:
                    throw new JsonException("Unsupported element type in associated entity collection");
            }
            result.Add(entity);
        }
        return result;
    }

    // 序列化保持默认行为,不需要修改
    public override void Write(Utf8JsonWriter writer, IEnumerable<T> value, JsonSerializerOptions options)
    {
        JsonSerializer.Serialize(writer, value, options);
    }
}

步骤3:绑定到对应属性

只需要在你需要兼容两种格式的集合属性上添加[JsonConverter]特性即可,其他属性完全不受影响:

public class WidgetUpdateDto
{
    public string Name { get; set; }
    // 仅该属性会走自定义转换逻辑
    [JsonConverter(typeof(AssociatedEntityCollectionConverter<Creator>))]
    public List<Creator> Creators { get; set; }
}

如果多个接口都用到了相同类型的关联实体集合,也可以全局注册转换器,避免重复加特性:

// Program.cs中注册
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new AssociatedEntityCollectionConverter<Creator>());
        // 其他需要支持的关联实体类型可继续添加
    });

方案优势

  • 侵入性极低:仅修改需要特殊处理的属性标记,不会覆盖全局默认序列化逻辑,其他属性的处理完全不变
  • 类型安全:不需要将属性声明为object,编译期即可完成类型校验
  • 通用可复用:所有同类多对多关联属性都可以通过实现IAssociatedEntity接口复用这套转换逻辑
  • 符合需求:既兼容用户直接传id数组的场景,也兼容GET获取数据修改后直接PUT回传的场景,后台始终可以直接取实体的Id值使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 17:54:03