JsonConvert如何将缺失成员设为null?FilterDto反序列化问题
Alright, let's figure out how to fix this. The root of the problem is that Newtonsoft.Json (Json.NET) preserves the default initialized value of your Code property when the corresponding field is missing from the incoming JSON. Instead of setting it to null, it hangs onto the "Default code" you defined in the property initializer. Here are a few practical solutions to handle this:
Method 1: Ignore the Constructor During Deserialization
Move the default value initialization for Code into the class constructor, then tell Json.NET to skip calling the constructor when deserializing. This way, missing fields will default to the type's default value (which is null for strings).
First, update your FilterDto class:
public class FilterDto { // Set the default Code value here for when we serialize to the client public FilterDto() { Code = "Default code"; } public string Code { get; set; } public string Description { get; set; } }
Then use this setting when deserializing the client's JSON:
var deserializeSettings = new JsonSerializerSettings { ConstructorHandling = ConstructorHandling.IgnoreConstructor }; var filter = JsonConvert.DeserializeObject<FilterDto>(json, deserializeSettings);
This works because:
- When you create a
FilterDtoinstance to send to the client, the constructor setsCodeto "Default code", so it will serialize correctly. - When deserializing, skipping the constructor means
Codewill benullif the JSON doesn't include the field.
Method 2: Separate Serialization and Deserialization Settings
If you don't want to mess with constructors, you can use different Json settings for serializing to the client vs deserializing their response.
First, update your FilterDto to remove the property initializer and mark the default value:
public class FilterDto { [DefaultValue("Default code")] // Mark the default value for serialization public string Code { get; set; } public string Description { get; set; } }
Serialize to the Client
Use DefaultValueHandling.Populate to ensure the default value is included when serializing:
var serializeSettings = new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Populate }; var filterDto = new FilterDto(); string clientJson = JsonConvert.SerializeObject(filterDto, serializeSettings);
Deserialize the Client's Response
Use DefaultValueHandling.Ignore so missing fields stay as null:
var deserializeSettings = new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore }; var filter = JsonConvert.DeserializeObject<FilterDto>(json, deserializeSettings);
This way, serialization will inject the default "Default code" if Code is null, while deserialization will leave Code as null if the field is missing from the JSON.
Method 3: Custom JsonConverter (For Full Control)
If you need more fine-grained control over the logic, write a custom converter to handle both serialization and deserialization exactly how you want.
Here's a sample converter:
public class FilterDtoConverter : JsonConverter<FilterDto> { public override FilterDto ReadJson(JsonReader reader, Type objectType, FilterDto existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonObject = JObject.Load(reader); var filter = new FilterDto(); // Only set Code if the JSON has the field; otherwise leave it null if (jsonObject.ContainsKey("Code")) { filter.Code = jsonObject["Code"].ToString(); } else { filter.Code = null; } filter.Description = jsonObject["Description"]?.ToString(); return filter; } public override void WriteJson(JsonWriter writer, FilterDto value, JsonSerializer serializer) { // Ensure we send the default Code value if it's null or empty var jsonObject = new JObject(); jsonObject["Code"] = string.IsNullOrEmpty(value.Code) ? "Default code" : value.Code; jsonObject["Description"] = value.Description; jsonObject.WriteTo(writer); } }
Use the converter in both serialization and deserialization:
var converterSettings = new JsonSerializerSettings { Converters = new List<JsonConverter> { new FilterDtoConverter() } }; // Serialize to client string clientJson = JsonConvert.SerializeObject(new FilterDto(), converterSettings); // Deserialize client response var filter = JsonConvert.DeserializeObject<FilterDto>(json, converterSettings);
This approach is great for complex scenarios where you need full control over how the DTO is converted to and from JSON.
内容的提问来源于stack exchange,提问作者João Menighin

