自定义对象序列化含Null属性,无法生成合规API请求体的问题
问题描述
我用下面的C#代码给API端点发送请求:
public static async Task PostPosition(string authorizationHeader, string apiUrl, string subDirectory, string xRoutingToken, string xApiKey, CustomObject payload) { using (HttpClient client = new HttpClient()) { // 设置请求头 client.DefaultRequestHeaders.Add("Accept", "application/json, text/plain"); client.DefaultRequestHeaders.Add("Authorization", authorizationHeader); client.DefaultRequestHeaders.Add("x-api-key", xApiKey); client.DefaultRequestHeaders.Add("x-routing-token", xRoutingToken); Console.WriteLine(apiUrl+subDirectory); string jsonPayload = System.Text.Json.JsonSerializer.Serialize(payload); var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); try { HttpResponseMessage response2 = await client.PostAsync(apiUrl + subDirectory, content); Console.WriteLine($"响应状态码: {response2.StatusCode}"); Console.WriteLine($"响应内容: {await response2.Content.ReadAsStringAsync()}"); } catch { Console.WriteLine("位置信息发送失败"); } } }
当前遇到的问题是:发送包含null属性的CustomObject时,序列化后的JSON会包含所有属性(未赋值的属性值为null),但目标API仅需要部分字段。我的CustomObject类定义及构造器如下:
namespace Project { // 定义两个构造器:一个初始化所有字段,一个初始化实际要用的字段 public class CustomObject { public string id { get; set; } public string? unit_address { get; set; } public string? position_date { get; set; } public double? latitude { get; set; } public double? longitude { get; set; } public string? position_status { get; set; } public string? position_type { get; set; } public bool? ignition { get; set; } public int? speed { get; set; } public string? direction { get; set; } public long? odometer { get; set; } // 初始化所有属性的构造器 public CustomObject(string objectId, string unitAddress, string positionDate, double lat, double lon, string posStatus, string posType, bool ign, int spd, string dir, long odom) { id = objectId; unit_address = unitAddress; position_date = positionDate; latitude = lat; longitude = lon; position_status = posStatus; position_type = posType; ignition = ign; speed = spd; direction = dir; odometer = odom; } // 仅初始化实际所需字段的构造器 public CustomObject(string iid, double llatitude, double llongitude, string ppositionDate) { this.id = iid; this.latitude = llatitude; this.longitude = llongitude; this.position_date = ppositionDate; } } }
目标API只需要id、position_date、latitude、longitude这几个字段。使用匿名对象(如下)可以成功完成请求:
var payload2 = new { id = "IDNUMBERHERE", position_date = "20230101010000-0400", latitude = 35.542887, longitude = -79.778473, };
但用CustomObject的构造器创建实例时:
CustomObject payload3 = new CustomObject("IDHere", 35.542887, -79.778473, "20230101010000-0400");
序列化后的JSON会包含所有属性,未赋值的属性值为null:
{ "id": "IDHere", "unit_address": null, "position_date": "20230101010000-0400", "latitude": 35.542887, "longitude": -79.778473, "position_status": null, "position_type": null, "ignition": null, "speed": null, "direction": null, "odometer": null }
我需要序列化后的JSON仅包含有值的属性,如下所示:
{ "id": "IDHere", "position_date": "20230101010000-0400", "latitude": 35.542887, "longitude": -79.778473 }
请问如何修改构造器、类或序列化配置来实现这一需求?
解决方案
方法1:修改序列化配置(推荐,无需改动类结构)
直接给System.Text.Json的序列化器添加忽略null值属性的配置,修改序列化代码即可:
var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; string jsonPayload = System.Text.Json.JsonSerializer.Serialize(payload, options);
这样序列化时,所有值为null的属性会被自动忽略,完全符合需求。
方法2:给不需要的属性添加[JsonIgnore]特性
如果确定某些字段永远不需要传给API,可以直接在类的对应属性上标记[JsonIgnore]特性:
namespace Project { public class CustomObject { public string id { get; set; } [JsonIgnore] public string? unit_address { get; set; } public string? position_date { get; set; } public double? latitude { get; set; } public double? longitude { get; set; } [JsonIgnore] public string? position_status { get; set; } [JsonIgnore] public string? position_type { get; set; } [JsonIgnore] public bool? ignition { get; set; } [JsonIgnore] public int? speed { get; set; } [JsonIgnore] public string? direction { get; set; } [JsonIgnore] public long? odometer { get; set; } // 构造器代码保持不变 // ... } }
这种方法适合字段固定不需要发送的场景,但如果后续需要发送某些字段,需重新修改类定义。
方法3:拆分类结构
创建一个专门用于API请求的精简类,只包含需要的字段:
public class PositionApiRequest { public string id { get; set; } public string position_date { get; set; } public double latitude { get; set; } public double longitude { get; set; } public PositionApiRequest(string id, string positionDate, double latitude, double longitude) { this.id = id; this.position_date = positionDate; this.latitude = latitude; this.longitude = longitude; } }
然后将PostPosition方法的参数类型改为PositionApiRequest,这样序列化时自然只会包含目标字段,也避免了原类冗余属性的干扰。
内容的提问来源于stack exchange,提问作者dylatwork
相关产品推荐
相关产品推荐

