Custom JsonConverter WriteJson non altera la serializzazione delle sottoproprietà

Custom JsonConverter WriteJson non altera la serializzazione delle sottoproprietà

Il motivo per cui il tuo convertitore non viene applicato ai tuoi oggetti figlio è perché JToken.FromObject() utilizza internamente una nuova istanza del serializzatore, che non conosce il tuo convertitore. C'è un sovraccarico che ti permette di passare il serializzatore, ma se lo fai qui avrai un altro problema:dato che sei all'interno di un convertitore e stai usando JToken.FromObject() per provare a serializzare l'oggetto genitore, entrerai in un ciclo ricorsivo infinito. (JToken.FromObject() chiama il serializzatore, che chiama il tuo convertitore, che chiama JToken.FromObject() , ecc.)

Per aggirare questo problema, è necessario gestire manualmente l'oggetto padre. Puoi farlo senza troppi problemi usando un po' di riflessione per enumerare le proprietà del genitore:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    JObject jo = new JObject();
    Type type = value.GetType();
    jo.Add("type", type.Name);

    foreach (PropertyInfo prop in type.GetProperties())
    {
        if (prop.CanRead)
        {
            object propVal = prop.GetValue(value, null);
            if (propVal != null)
            {
                jo.Add(prop.Name, JToken.FromObject(propVal, serializer));
            }
        }
    }
    jo.WriteTo(writer);
}

Violino:https://dotnetfiddle.net/sVWsE4


Ho riscontrato questo problema utilizzando due convertitori personalizzati per un tipo padre e figlio. Un metodo più semplice che ho trovato è che poiché un sovraccarico di JToken.FromObject() prende un serializer come parametro, puoi passare il serializzatore che ti è stato fornito in WriteJson() . Tuttavia è necessario rimuovere il convertitore dal serializzatore per evitare una chiamata ricorsiva ad esso (ma aggiungerlo nuovamente dopo):

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    serializer.Converters.Remove(this);
    JToken jToken = JToken.FromObject(value, serializer);
    serializer.Converters.Add(this);

    // Perform any necessary conversions on the object returned
}

Ecco un'idea, invece di riflettere su ogni proprietà, scorrere il JObject normalmente serializzato e quindi modificare il token delle proprietà che ti interessano.

In questo modo puoi ancora sfruttare tutti gli attributi ''JsonIgnore'' e altre interessanti funzionalità integrate.

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    JToken jToken = JToken.FromObject(value);

    if (jToken.Type == JTokenType.Object)
    {
        JObject jObject = (JObject)jToken;
        ...
        AddRemoveSerializedProperties(jObject, val);
        ...
    }
    ...
}

E poi

private void AddRemoveSerializedProperties(JObject jObject, MahMan baseContract)
   {
       jObject.AddFirst(....);

        foreach (KeyValuePair<string, JToken> propertyJToken in jObject)
        {
            if (propertyJToken.Value.Type != JTokenType.Object)
                continue;

            JToken nestedJObject = propertyJToken.Value;
            PropertyInfo clrProperty = baseContract.GetType().GetProperty(propertyJToken.Key);
            MahMan nestedObjectValue = clrProperty.GetValue(baseContract) as MahMan;
            if(nestedObj != null)
                AddRemoveSerializedProperties((JObject)nestedJObject, nestedObjectValue);
        }
    }