Search code examples
c#jsonsystem.text.json.net-7.0

How to customize System.Text.Json serialization of certain fields?


I need to (de)serialize objects which reference 3rd party API objects which arent serializable. However I dont need their content to be serialized. I just want to serialize Id of these objects and then retrieve them on deserailization.

Short example:

class MyClass
{
    public int Id;
    public I3rdParyObject Data;
}

I want a custom logic to be called on (de)serializing Data. I would write to text "Data": "abc" on serialization and retrieve it on deserialization like: deserializedObject.Data = DataManager.GetDataById("abc")


Solution

  • Assuming that the text "abc" can be extracted from I3rdParyObject itself, e.g. via some property:

    public interface I3rdParyObject
    {
        public string Id { get; }
        // Remainder not shown in your question
    }
    

    You can write a custom JsonConverter<I3rdParyObject> for I3rdParyObject like so:

    public class I3rdParyObjectConverter : JsonConverter<I3rdParyObject>
    {
        public override void Write(Utf8JsonWriter writer, I3rdParyObject value, JsonSerializerOptions options) =>
            writer.WriteStringValue(value.Id);
        
        public override I3rdParyObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => 
            DataManager.GetDataById(reader.GetString()!);
    }
    

    Or if the Id cannot be obtained directly from I3rdParyObject but can be returned by DataManager using some method like:

    public static class DataManager
    {
        public static string GetDataId(I3rdParyObject obj) => /* Logic to get the Id */
    }
    

    Then WriteJson() could be written as follows:

        public override void Write(Utf8JsonWriter writer, I3rdParyObject value, JsonSerializerOptions options) =>
            writer.WriteStringValue(DataManager.GetDataId(value));
    

    Then add the converter to JsonSerializerOptions during serialization like so when serializing or deserializing:

    var options = new JsonSerializerOptions
    {
        Converters = { new I3rdParyObjectConverter() },
        // Other options as required
        IncludeFields = true,  // You must set this if MyClass.Id and MyClass.Data are really fields not properties.
    };
    
    var json = JsonSerializer.Serialize(myClass, options);
    var myClass2 = JsonSerializer.Deserialize<MyClass>(json, options);
    

    Notes:

    Demo fiddle here.