9

I am trying to figure out how to serialize to a json object and skip serializing properties whose values are empty lists. I am not using Newtonsoft json

using System.Text.Json;
using System.Text.Json.Serialization;
using AutoMapper;

I have an object with a property.

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("extension")]
public List<Extension> Extension { get; set; }

When I try to serialize this object using the following

var optionsJson =   new JsonSerializerOptions
    {
    WriteIndented = true,
    IgnoreNullValues = true,
    PropertyNameCaseInsensitive = true,
    };

var json = JsonSerializer.Serialize(report, optionsJson);

It still gives me an empty array:

"extension": [],

Isn't there a way to keep it from serializing these empty lists? I would like to see extension gone. It should not be there at all. I need to do this because the gateway will respond with an error if I send:

"extension": null,

It must not be part of the object when serialized.

gateway error

The reason why I do not want these empty lists is that the third party gateway I am sending to objects to empty lists

"severity": "error", "code": "processing", "diagnostics": "Array cannot be empty - the property should not be present if it has no values", "location": [ "Bundle.entry[2].resource.extension", "Line 96, Col 23" ]

I'm trying to avoid doing some kind of nasty string replace on this.

dbc
  • 104,963
  • 20
  • 228
  • 340
Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • What do you want? Why this empty object is so annoying you? Does it cause the error? If it is so important, use Newtonsoft.Json. – Serge Mar 09 '22 at 12:44
  • Because the third party gateway i am sending these objects to objects to having empty lists. See edit for their kind error message. – Linda Lawton - DaImTo Mar 09 '22 at 12:45
  • https://stackoverflow.com/questions/11320968/can-newtonsoft-json-net-skip-serializing-empty-lists – Maroun Mar 09 '22 at 12:47
  • You need to say precisely what do you want? You want "extension": null or you don't want any line at all? – Serge Mar 09 '22 at 12:47
  • Pretty sure there is no generic way to do this. Make your own check if an array is empty simply remove it. – Josip Juros Mar 09 '22 at 12:48
  • @Serge see update i want it gone. – Linda Lawton - DaImTo Mar 09 '22 at 12:49
  • 1
    I would say that if you have only one such property the easiest way should be to switch to property with backing field and do something like `public List Extension { get => _extension.Any() ? _extension : null; set => _extension = value; }` – Guru Stron Mar 09 '22 at 12:50
  • @gunr2171 isn't OP using `System.Text.Json`? – Guru Stron Mar 09 '22 at 12:51
  • @gunr2171 I am not using Newtonsoft json. I made a point of stating that. – Linda Lawton - DaImTo Mar 09 '22 at 12:51
  • 3
    https://stackoverflow.com/questions/59720612/c-sharp-net-core-3-1-system-text-json-ignore-empty-collection-in-serialization – gunr2171 Mar 09 '22 at 12:53
  • @gunr2171 im using .net 6 not .net core. – Linda Lawton - DaImTo Mar 09 '22 at 12:54
  • 2
    That's the same thing. – gunr2171 Mar 09 '22 at 12:54
  • 1
    .NET Core stopped with 3.1. It's the technology that was moved forward to 5 and 6, but the names are now without Core. If you're talking about .NET Core, you're not talking about .NET 5 or 6. Technically, you're right, but you're also wrong :) – Lasse V. Karlsen Mar 09 '22 at 12:56
  • 1
    Mark the original property as ignored for serialization, then make a dummy property that reflects the value of the original property except that if the original property is an empty list, the dummy property returns null. Then mark the dummy property as ignored when writing null values (defaults). – Lasse V. Karlsen Mar 09 '22 at 13:03
  • Have you considered separating the types used for (de)serialization from your in-memory representation of the data? It would be much easier to handle this during mapping to your serialization types, and just don't populate that property, thus it would be `null` and you could tag it with the JsonIgnore attribute to avoid serializing it in that case. Typically you *should* consider this separation as then you can still refactor your in-memory structure separate from the contract you have with integrations. – Lasse V. Karlsen Mar 09 '22 at 13:24
  • you can just use NullValueHandling=NullValueHandling.Ignore as a property if you want. – Bechir Anoir Chabchoub Mar 09 '22 at 13:31
  • @LasseV.Karlsen I am using automapper to map objects i tried getting it to ignore it but failed. – Linda Lawton - DaImTo Mar 09 '22 at 13:54

1 Answers1

10

You can add a dummy property that is used during serialization that handles this.

  • Add a new property with the same signature, but flag it with JsonPropertyNameAttribute to ensure it is being serialized with the correct name, and also with the JsonIgnoreAttribute so that it will not be serialized when it returns null.
  • The original property you mark with JsonIgnore, unconditionally, so that it will never be serialized itself
  • This dummy property would return null (and thus be ignored) when the actual property contains an empty list, otherwise it would return that (non-empty) list
  • Writes to the dummy property just writes to the actual property

Something like this:

[JsonIgnore]
public List<Extension> Extensions { get; set; } = new();

[JsonPropertyName("extension")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
 public List<Extension> SerializationExtensions
    {
        get => Extensions?.Count > 0 ? Extensions : null;
        set => Extensions = value ?? new();
    }
Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • Note if you use a custom naming policy, JsonPropertyName will override it e.g. if you serialize with PascalCase naming, `[JsonPropertyName("extension")]` will be serialized as "extension" instead of "Extension". – Jason Weinzierl Sep 05 '22 at 04:40
  • It's dirty compared to the NewtonSoft solution but it works. Thanks. – Carra Mar 20 '23 at 14:37