7

I normally use ShouldSerialize to exclude properties that have no data such as array but now, it does not appear to be triggered when I'm only using JSON serializer in .NET Core 3. It was being triggered when using NewtonSoft but I've removed it from my project since it no longer appears to be required.

For example:

    private ICollection<UserDto> _users;

    public ICollection<UserDto> Users
    {
        get => this._users ?? (this._users = new HashSet<UserDto>());
        set => this._users = value;
    }

    public bool ShouldSerializeUsers()
    {
        return this._users?.Count > 0;
    }

Any ideas why ShouldSerializeUsers is not being triggered?

I've seen other answers where you can use:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddJsonOptions(options => { 
        options.SerializerSettings.NullValueHandling = 
        NullValueHandling.Ignore;
    });
}

But I'd like to know if there is another way to handle this as I'm not using .AddMvc

Thanks.

Thierry
  • 6,142
  • 13
  • 66
  • 117
  • 1
    IIUC, there is no such option in built-in json serializer from `System.Text.Json` namespace, according [sources](https://github.com/dotnet/corefx/blob/2b2dd5120029081af767e0eea5e813fd68bded11/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs#L20) – Pavel Anikhouski Dec 28 '19 at 09:26
  • 1
    There is also a GitHub [issue](https://github.com/dotnet/corefx/issues/41612) related to possibility to change these options – Pavel Anikhouski Dec 28 '19 at 09:26
  • 1
    You need to revert back to Json.NET to use `ShouldSerializeXXX()` functionality. To do that see [Where did IMvcBuilder AddJsonOptions go in .Net Core 3.0?](https://stackoverflow.com/q/55666826/3744182). – dbc Dec 29 '19 at 18:39
  • @dbc I've just tried to revert back to Json.NET but I'm not getting error when it tries to serialize a array of enum as string rather than using a value when using `Unable to cast object of type 'System.Text.Json.Serialization.JsonStringEnumConverter' to type 'Newtonsoft.Json.JsonConverter'.` so for now, I'll just have to live with the array being defined in Json even if empty. Not critical right now but would have been nice. – Thierry Dec 30 '19 at 00:12
  • Well having switched to a different serializer you will need to use the equivalent converter(s) and attributes. Specifically replace [`JsonStringEnumConverter`](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonstringenumconverter?view=netcore-3.1) with [`StringEnumConverter`](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Converters_StringEnumConverter.htm). – dbc Dec 30 '19 at 00:14
  • Hard to make it an answer since your question doesn't show use of `JsonStringEnumConverter` anywhere. Absent that, maybe close as a duplicate of [Where did IMvcBuilder AddJsonOptions go in .Net Core 3.0?](https://stackoverflow.com/q/55666826/3744182)? – dbc Dec 30 '19 at 00:22
  • 1
    @dbc No, but my original issue is resolved which is to revert back to Json.NET – Thierry Dec 30 '19 at 00:23

3 Answers3

14

The reason that your ShouldSerialize is not triggered in ASP.NET Core 3.0 is that, in this and subsequent versions of ASP.NET, a different JSON serializer is being used by default, namely System.Text.Json.JsonSerializer. See:

Unfortunately as of .NET Core 3.1 this serializer does not support the ShouldSerializeXXX() pattern; if it did it would be somewhere in JsonSerializer.Write.HandleObject.cs -- but it's not. The following issues track requests for conditional serialization:

To restore ShouldSerialize functionality, you can revert back to using Newtonsoft as shown in this answer to Where did IMvcBuilder AddJsonOptions go in .Net Core 3.0? by poke, and also Add Newtonsoft.Json-based JSON format support:

  1. Install Microsoft.AspNetCore.Mvc.NewtonsoftJson.
  2. Then call AddNewtonsoftJson() in Startup.ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers()
            .AddNewtonsoftJson();
    }
    
dbc
  • 104,963
  • 20
  • 228
  • 340
4

It is possible in Net 5 to use conditional JsonIgnore. It does not give you full conditional option, but you can exclude null at least which I suppose is the most used case:

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? MyProperty { get; set; }

If one wants to allow for optional null in json, it is possible to use a custom Optional<T> struct that is similar to Nullable, like e.g. one from Roslyn. Then it's possible to have a value, null, or no field at all in the result JSON.

Ilya Chernomordik
  • 27,817
  • 27
  • 121
  • 207
0

I also had a ShouldSerialize method not triggered while returning a DTO object from a rest API. The solution I found was to manually convert the object to a JSON string using:

string json = JsonConvert.SerializeObject(
    objectToSerialize,
    Formatting.Indented,
    new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() }
);

The ShouldSerialize method is then triggered and if it returns false the corresponding property is hidden in the resulting JSON string. You just need to manually add an HTTP header Content-Type:application/json to the response in order to get a similar result.

radarbob
  • 4,964
  • 2
  • 23
  • 36
piero B
  • 37
  • 6