13

Question

Can I dynamically ignore a property from a sealed class using System.Text.Json.JsonSerializer?

Example Code

Example class from another library:

public sealed class FrozenClass
{
    // [JsonIgnore] <- cannot apply because I don't own this class
    public int InternalId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Default Serialization:

var person = new FrozenClass() { InternalId = 3, FirstName = "Dorothy", LastName = "Vaughan" };
var jsonString = System.Text.Json.JsonSerializer.Serialize(person);

Actual Outcome:

{ "InternalId": 3, "FirstName": "Dorothy", "LastName": "Vaughan" }

Expected Outcome:

{ "FirstName": "Dorothy", "LastName": "Vaughan" }

Alternatives that don't work

There are two other questions on how to add JsonIgnore at RunTime & add dynamic property name for serialization, but both are targeted at Newtonsoft's Json.NET - and often reference this extension method

There are several ways to modify the way a class is serialized with the native JsonSerializer, but all seem to rely on modifying the underlying class:

However, in my case, the class is from another library and cannot be extended

Workarounds

A possible workaround is to create another exportable class and setup a mapper between them

public class MyFrozenClass
{
    public MyFrozenClass(FrozenClass frozen)
    {
        this.FirstName = frozen.FirstName;
        this.LastName = frozen.LastName;
    }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
var jsonString = System.Text.Json.JsonSerializer.Serialize(new MyFrozenClass(person));
KyleMit
  • 30,350
  • 66
  • 462
  • 664
  • 11
    15ish years of "quite involved with serializers" experience has taught me that *the first moment* a serializer starts fighting with what you want / what a type is: to go with a dedicated DTO, i.e. what you have in your "possible workaround". In the long run, I've found that just doing that saves a *lot* of time and pain. – Marc Gravell Jul 07 '20 at 12:53
  • 2
    You can use a [custom converter ](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to) to emit JSON explicitly but this may be too much work. Mapping using eg `AutoMapper` is a lot easier and far safer - for your sanity – Panagiotis Kanavos Jul 07 '20 at 12:54
  • With Json.NET you could do this easily with a [custom contract resolver](https://www.newtonsoft.com/json/help/html/contractresolver.htm#CustomIContractResolverExamples), however the equivalent types in `System.Text.Json` -- [`JsonClassInfo`](https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs) and [`JsonPropertyInfo`](https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs) -- are **internal**. – dbc Jul 07 '20 at 14:03
  • See: [System.Text.Json API is there something like IContractResolver](https://stackoverflow.com/q/58926112/3744182). The workarounds of a DTO or custom `JsonConverter` would seem to be the way to go. – dbc Jul 07 '20 at 14:04
  • For an example of a custom `JsonConverter` that is fairly generic see [How to exclude a property from being serialized in System.Text.Json.JsonSerializer.Serialize() using a JsonConverter](https://stackoverflow.com/q/58566735/3744182). In fact I think your question could be a duplicate of the two questions to which I linked, agree? – dbc Jul 07 '20 at 14:33
  • @MarcGravell is right, DTO is the way. However I found using interfaces is more handy than DTO classes + Mapping. The dupe question actually has an answer https://stackoverflow.com/a/61344654/56621 – Alex from Jitbit Nov 24 '22 at 11:09

0 Answers0