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

.NET Core中如何控制List内DTO对象的JSON属性输出顺序?

控制.NET Core中DTO序列化JSON的属性输出顺序

针对你需要固定或自定义List<SearchResultPersonDto>序列化JSON时的属性顺序问题,以下是两种常用序列化库的解决方案:


一、使用特性固定顺序(简单直接)

1. 针对System.Text.Json(.NET 5+默认)

给DTO的每个属性添加[JsonPropertyOrder]特性,通过指定数字控制顺序(数字越小,序列化时越靠前):

public class SearchResultPersonDto
{
    [JsonPropertyOrder(1)]
    public string LastName { get; set; }

    [JsonPropertyOrder(2)]
    public string FirstName { get; set; }

    // 自定义顺序:把TaxYear放在最前面
    [JsonPropertyOrder(0)]
    public int TaxYear { get; set; }

    [JsonPropertyOrder(3)]
    public string Position { get; set; }

    [JsonPropertyOrder(4)]
    public string IncomeBracket { get; set; }
}

如果需要同时重命名属性,配合[JsonPropertyName]使用即可:

[JsonPropertyName("last_name"), JsonPropertyOrder(1)]
public string LastName { get; set; }

2. 针对Newtonsoft.Json(第三方库)

使用[JsonProperty(Order = n)]特性控制顺序,规则和System.Text.Json一致:

public class SearchResultPersonDto
{
    [JsonProperty(Order = 1)]
    public string LastName { get; set; }

    [JsonProperty(Order = 2)]
    public string FirstName { get; set; }

    [JsonProperty(Order = 0)]
    public int TaxYear { get; set; }

    [JsonProperty(Order = 3)]
    public string Position { get; set; }

    [JsonProperty(Order = 4)]
    public string IncomeBracket { get; set; }
}

二、动态自定义顺序(适合多场景不同顺序需求)

如果不同接口需要输出不同的属性顺序,无需修改DTO特性,可通过自定义解析器/转换器实现:

1. Newtonsoft.Json 动态顺序

创建自定义契约解析器:

public class CustomPropertyOrderResolver : DefaultContractResolver
{
    private readonly Dictionary<Type, List<string>> _propertyOrderMap;

    public CustomPropertyOrderResolver(Dictionary<Type, List<string>> propertyOrderMap)
    {
        _propertyOrderMap = propertyOrderMap;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);
        if (_propertyOrderMap.TryGetValue(type, out var orderedProps))
        {
            // 按指定顺序排序,未指定的属性放最后
            properties = properties.OrderBy(p => orderedProps.IndexOf(p.PropertyName)).ToList();
        }
        return properties;
    }
}

全局配置(影响所有该类型序列化)

在Program.cs或Startup.cs中配置:

builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        var orderMap = new Dictionary<Type, List<string>>
        {
            { 
                typeof(SearchResultPersonDto), 
                new List<string> { "TaxYear", "Position", "LastName", "FirstName", "IncomeBracket" } 
            }
        };
        options.SerializerSettings.ContractResolver = new CustomPropertyOrderResolver(orderMap);
    });

单个接口动态配置

在Action中单独指定顺序:

[HttpGet("custom-order")]
public IActionResult GetPersonsCustomOrder()
{
    var persons = GetPersonList(); // 你的数据获取逻辑

    var customOrder = new List<string> { "TaxYear", "IncomeBracket", "Position", "LastName", "FirstName" };
    var settings = new JsonSerializerSettings
    {
        ContractResolver = new CustomPropertyOrderResolver(new Dictionary<Type, List<string>>
        {
            { typeof(SearchResultPersonDto), customOrder }
        })
    };

    var json = JsonConvert.SerializeObject(persons, settings);
    return Content(json, "application/json");
}

2. System.Text.Json 动态顺序

创建自定义转换器:

public class CustomPropertyOrderConverter<T> : JsonConverter<T>
{
    private readonly List<string> _propertyOrder;

    public CustomPropertyOrderConverter(List<string> propertyOrder)
    {
        _propertyOrder = propertyOrder;
    }

    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return JsonSerializer.Deserialize<T>(ref reader, options);
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        var type = typeof(T);

        // 先写入指定顺序的属性
        foreach (var propName in _propertyOrder)
        {
            var prop = type.GetProperty(propName);
            if (prop != null)
            {
                writer.WritePropertyName(propName);
                JsonSerializer.Serialize(writer, prop.GetValue(value), prop.PropertyType, options);
            }
        }

        // 写入剩余未指定的属性
        foreach (var prop in type.GetProperties().Where(p => !_propertyOrder.Contains(p.Name)))
        {
            writer.WritePropertyName(prop.Name);
            JsonSerializer.Serialize(writer, prop.GetValue(value), prop.PropertyType, options);
        }

        writer.WriteEndObject();
    }
}

在Action中使用:

[HttpGet("dynamic-order")]
public IActionResult GetPersonsDynamicOrder()
{
    var persons = GetPersonList(); // 你的数据获取逻辑

    var options = new JsonSerializerOptions();
    options.Converters.Add(new CustomPropertyOrderConverter<SearchResultPersonDto>(
        new List<string> { "TaxYear", "Position", "IncomeBracket", "LastName", "FirstName" }));

    return Json(persons, options);
}

注意事项

  • 如果使用了属性重命名(如[JsonPropertyName]或[JsonProperty]),动态顺序配置中要使用重命名后的名称而非DTO属性名。
  • 全局配置会作用于所有该类型的JSON序列化,动态配置仅影响当前接口。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 03:07:53