-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow custom converters to feed back to the POCO converter not to write the property name #50294
Comments
Tagging subscribers to this area: @eiriktsarpalis, @layomia Issue DetailsThis is mainly a rehash of comments in #33433 but I'm pulling it out into it's own issue for visibility.
Newtonsoft does support this, and it's a reason why our F# responses with System.Text.Json have more nulls in the results than we would like when IgnoreNullValues is enabled. We literally can't do anything else than emit null for F# (Value)Option.None cases as any F# discriminated union must be serialized with the help of a custom converter. I just wanted to bring it to the attention specifically so it could be taken into consideration for the new poco converter model #36785. Ideally it should be possible to have a value converter opt out of its property getting written. However I guess with #36785 in the 'worst case' you could create your own generic POCO converter that does support this.
|
Related to #29812. |
The new ValueOptionConverter (and the normal option converter) will unconditionally write null values and does not respect Line 82 in dc2fe34
Will this still get fixed in 6.0, is a PR welcome? |
Null/default value handling is extraneous to the converter implementation. The changes include testing that validates this for F# option and value option types. |
@NinoFloris going back to the original issue, are you still experiencing this with .NET 5? I tried this code using System;
using System.Text.Json;
using System.Text.Json.Serialization;
var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault };
var value = new { Struct = default(MyStruct), Class = default(MyClass), Int = default(int?) };
string json = JsonSerializer.Serialize(value, options);
Console.WriteLine(json); // prints "{}"
[JsonConverter(typeof(MyCoolConverterFactory))]
public struct MyStruct
{
public int X { get; set; }
}
[JsonConverter(typeof(MyCoolConverterFactory))]
public class MyClass
{
public int X { get; set; }
}
public class MyCoolConverter<T> : JsonConverter<T>
{
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotSupportedException();
public override void Write(Utf8JsonWriter writer, T _, JsonSerializerOptions options) => writer.WriteNumberValue(42);
}
public class MyCoolConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type _) => true;
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions _)
{
return (JsonConverter)Activator.CreateInstance(typeof(MyCoolConverter<>).MakeGenericType(typeToConvert))!;
}
} and ignored default values seem to be honored, even for custom converters. Changing If I'm misunderstanding the issue, could you please share a minimal repro? Thanks. |
@eiriktsarpalis Something like this is the best we can do as a library supplying ValueOption conversion without internals access and it still emits nulls, Option only works because, as you know The idea is, no attributes or other nonsense to tune per property. Just app wide proper ValueOption support without using using System;
using System.Text.Json;
using System.Text.Json.Serialization;
var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
options.Converters.Add(new ValueOptionConverterFactory());
var value = new MyDTO { Description = new ValueOption<string>() };
string json = JsonSerializer.Serialize(value, options);
Console.WriteLine(json); // prints "{ "description": null }"
public struct ValueOption<T>
{
public enum Cases
{
ValueNone = 0,
ValueSome = 1
}
public Cases Tag { get; set; }
public T Value { get; set; }
}
public class MyDTO
{
public ValueOption<string> Description { get; set; }
}
public class ValueOptionConverter<T> : JsonConverter<ValueOption<T>>
{
public override ValueOption<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotSupportedException();
public override void Write(Utf8JsonWriter writer, ValueOption<T> value, JsonSerializerOptions options)
{
switch (value.Tag)
{
case ValueOption<T>.Cases.ValueNone:
writer.WriteNullValue();
break;
case ValueOption<T>.Cases.ValueSome:
JsonSerializer.Serialize<T>(writer, value.Value, options);
break;
};
}
}
public class ValueOptionConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type t)
=> t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ValueOption<>);
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions _)
{
return (JsonConverter)Activator.CreateInstance(typeof(ValueOptionConverter<>).MakeGenericType(typeToConvert.GetGenericArguments()[0]))!;
}
} |
Ah I see now, so you're requesting for something like conditional property serialization but specified on the converter level? Could you provide an API proposal?
I wasn't around when these were named, but I would think that the "Null" in both |
Closing in favor of #55781 (comment) |
This is mainly a rehash of comments in #33433 but I'm pulling it out into it's own issue for visibility.
Newtonsoft does support this, and it's a reason why our F# responses with System.Text.Json have more nulls in the results than we would like when IgnoreNullValues is enabled. We literally can't do anything else than emit null for F# (Value)Option.None cases as any F# discriminated union must be serialized with the help of a custom converter.
I just wanted to bring it to the attention specifically so it could be taken into consideration for the new poco converter model #36785.
Ideally it should be possible to have a value converter opt out of its property getting written. However I guess with #36785 in the 'worst case' you could create your own generic POCO converter that does support this.
The text was updated successfully, but these errors were encountered: