-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
JsonSerializer does not serialize DBNull.Value as null #418
Comments
From @RandomGHUser in https://github.com/dotnet/corefx/issues/39808:
|
|
I would imagine creating and registering a custom Would that be sufficient or is |
I think the dev expectation here is that DbNull is always considered to be equal to null when serializing and handled as such. Newtonsoft.Json seems to have a lot of checks and tests for DbNull, and there is a lot of code depending on that. From another perspective, I cannot imagine a scenario where "{}" (empty object, which DbNull.Value is serialized to) in JSON would carry any meaningful value, as there is no way to differentiate it from any other empty object. |
@SanderSade, @RandomGHUser - what do you expect the deserialization to be for that? For When we deserialize Also, in what context do you end up getting an instance of |
Starting from the last - it seems that a very common (see links in #682) use of SqlDataReader in APIs is fetching the results directly into
With JSON.NET, any DbNull.Value values in the dictionary were serialized as null values. With System.Json.Text, the DbNull.Value is serialized into empty object, "{}". For deserialization/roundtripping, I cannot see a valid scenario where an empty object would be preferable to null (literally, "there is an object, but we have no idea what it is"). In .NET, DbNull is a mostly a legacy artifact due to non-nullable value types (see Marc Gravell's comment, "I have yet to see an occasion where I need to represent two different "null" states, so DBNull is entirely redundant given that null already exists and has much better language and runtime support."). |
sidenote to @layomia i don't think that codebranch was taken in your example -- if nullvalue.ignore was set it would return and not show the key or value, producing As there is a difference in the statement "the database holds the null value" and "c# has no value for this" I don't think that this is necessarily an error. From a language point of view: In ORM-like scenarios where the application is king, and the database is just there to store its data, then there is little use for dbNull, but in other scenarios (interacting with a data warehouse, or other shared data store) then that difference between those two states should be important. Marc Gravell's comment (linked above by SanderSade) says "i don't think there is a reason for anyone to use DbNull" -- that is a different conversation to "Given we are using DbNull, we should be automatically demoting them to normal null when we serialize them" If there is no need for DbNull, shouldn't the argument be taken to the libraries that produce them from the database, not here inside the runtime? From a languange point of view we have an object that in memory. Finally, given that we are trying to minimize the use of nulls within the language as a whole (null reference tracking etc in c#8) , should we consider encouraging people to use DbNull, not actual null? |
Here's a converter for a workaround: private class DBNullConverter : System.Text.Json.Serialization.JsonConverter<DBNull>
{
public override DBNull Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// Implement custom logic.
// Debug.Assert(typeToConvert == typeof(DBNull));
// if (reader.TokenType != JsonTokenType.Null)
// {
// throw new JsonException();
// }
// return DBNull.Value;
throw new NotSupportedException();
}
public override void Write(Utf8JsonWriter writer, DBNull value, JsonSerializerOptions options)
{
writer.WriteNullValue();
}
} As stated above, I can't imagine a deserialization scenario where an object graph would contain a strongly-typed property of DBNull, but a converter could handle such a case. |
One open question with DbNull is with |
This just surprised me. count me into the camp that agrees it should serialize to null and it isn't that important to round trip back to a dbnull as i think a null is ok. |
I don't believe offering out-of-the-box support for every serializable BCL type is a design goal for STJ. Rooting more converter implementations has a detrimental effect on size in trimmed apps, so we need to be selective about what types we do support. I defer to @layomia on whether we should still pursue adding a converter for
Might be possible to address on the converter level provided that something like #55781 has been implemented. |
…he suggestion in dotnet/runtime#418 Move duplicate code in GxRedis.cs and GxMemcached.cs to GxClasses.csproj Adding the package reference System.Text.Json to GxClasses.csproj gets a conflict with System.Net.Http. Because of that, HttpClient used in MapFunctions.cs is replaced by HttpWebRequest for .netframework similar to the use in GXGeolocation.
* Add a converter to serialize properly the DBNull value according to the suggestion in dotnet/runtime#418 Move duplicate code in GxRedis.cs and GxMemcached.cs to GxClasses.csproj Adding the package reference System.Text.Json to GxClasses.csproj gets a conflict with System.Net.Http. Because of that, HttpClient used in MapFunctions.cs is replaced by HttpWebRequest for .netframework similar to the use in GXGeolocation. * Remove unused code.
* Add a converter to serialize properly the DBNull value according to the suggestion in dotnet/runtime#418 Move duplicate code in GxRedis.cs and GxMemcached.cs to GxClasses.csproj Adding the package reference System.Text.Json to GxClasses.csproj gets a conflict with System.Net.Http. Because of that, HttpClient used in MapFunctions.cs is replaced by HttpWebRequest for .netframework similar to the use in GXGeolocation. * Remove unused code. (cherry picked from commit fbfe50c)
At this point it would be a breaking change to change the serialized output here. It would be better for users to handle the behavior using a custom converter. |
cc @RandomGHUser, @SanderSade
The text was updated successfully, but these errors were encountered: