Powershell: ConvertTo-Json does not honour [DataMember(EmitDefaultValue = false)] on properties

Created on 20 Oct 2018  路  5Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

Add-Type @"
using System.Runtime.Serialization;
[DataContract]
public class X
{
    [DataMember(EmitDefaultValue=false)]
    public string Y { get; set; }
}
"@

[X]@{} | ConvertTo-Json

Expected behavior

{
}

Actual behavior

{
    "Y": null
}

Environment data

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.1.0
PSEdition                      Core
GitCommitId                    6.1.0
OS                             Microsoft Windows 10.0.17134
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Area-Cmdlets-Utility Issue-Discussion

Most helpful comment

There are a couple of duplicate issue related to not respecting NewtonSoft JSON attributes and other attributes. The crux of the issue is that unless the object is a primitive, dictionary, or JObject, it hits this code path

https://github.com/PowerShell/PowerShell/blob/0a4f33a872ab811d55ff0f255d87035dbf137fb2/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs#L398

The means that's the object gets converted to a dictionary and then converted to JSON by NewtonSoft.

Much of this is legacy baggage from Windows PowerShell from before NewtonSoft was used. We can add attribute detection and change the behavior, but, that might lead to unexpected changes in reestablished behavior and it would definitely be reinventing the wheel.

I think what really should be done is that new Convert(To|From)-JSON cmdlets should written to more closely wrap NewtonSoft. It will lead to better support for these kinds of things, improve performance, and allow for this project to step out of the JSON (de)serialization business. Then deprecate the exiting cmdlets.

All 5 comments

Unfortunately it also does not honour the [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] setting in source.

Wouldn't these be issues in NewtonSoft.Json and not the cmdlet?

Well in the same session (with nothing special loaded):

> [Newtonsoft.Json.JsonConvert]::SerializeObject([X]::new())
{}

My suspicion is that there's some configuration that's on by default that we unwittingly override -- but I want to check that it's not deliberate. It's not well documented in Newtonsoft.Json's docs

There are a couple of duplicate issue related to not respecting NewtonSoft JSON attributes and other attributes. The crux of the issue is that unless the object is a primitive, dictionary, or JObject, it hits this code path

https://github.com/PowerShell/PowerShell/blob/0a4f33a872ab811d55ff0f255d87035dbf137fb2/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/ConvertToJsonCommand.cs#L398

The means that's the object gets converted to a dictionary and then converted to JSON by NewtonSoft.

Much of this is legacy baggage from Windows PowerShell from before NewtonSoft was used. We can add attribute detection and change the behavior, but, that might lead to unexpected changes in reestablished behavior and it would definitely be reinventing the wheel.

I think what really should be done is that new Convert(To|From)-JSON cmdlets should written to more closely wrap NewtonSoft. It will lead to better support for these kinds of things, improve performance, and allow for this project to step out of the JSON (de)serialization business. Then deprecate the exiting cmdlets.

Yeah, I the case I had, I actually just wrote a new ConvertTo-Json (with a different name) in PowerShell and wrapped [JsonConvert]::Serialize($x) with it.

Was this page helpful?
0 / 5 - 0 ratings