Wir haben einige Konfigurationsdateien, die durch Serialisieren von C # -Objekten mit Json.net generiert wurden.
Wir möchten eine Eigenschaft der serialisierten Klasse von einer einfachen Enum-Eigenschaft in eine Klasseneigenschaft migrieren.
Eine einfache Möglichkeit, dies zu tun, besteht darin, die alte enum-Eigenschaft in der Klasse zu belassen und Json.net zu veranlassen, diese Eigenschaft beim Laden der Konfiguration zu lesen, sie jedoch beim nächsten Serialisieren des Objekts nicht erneut zu speichern. Wir werden die neue Klasse separat aus der alten Aufzählung generieren.
Gibt es eine einfache Möglichkeit, eine Eigenschaft eines C # -Objekts zu markieren (z. B. mit Attributen), sodass Json.net sie NUR beim Serialisieren ignoriert, beim Deserialisieren jedoch beachtet?
Antworten:
Es gibt tatsächlich mehrere ziemlich einfache Ansätze, mit denen Sie das gewünschte Ergebnis erzielen können.
Nehmen wir zum Beispiel an, Sie haben Ihre Klassen derzeit so definiert:
Und du willst das machen:
Um dies zu bekommen:
Ansatz 1: Fügen Sie eine ShouldSerialize-Methode hinzu
Json.NET kann Eigenschaften bedingt serialisieren, indem nach entsprechenden
ShouldSerialize
Methoden in der Klasse gesucht wird .Um diese Funktion zu verwenden, fügen Sie
ShouldSerializeBlah()
Ihrer Klasse eine boolesche Methode hinzu, dieBlah
durch den Namen der Eigenschaft ersetzt wird, die Sie nicht serialisieren möchten. Lassen Sie die Implementierung dieser Methode immer zurückkehrenfalse
.Hinweis: Wenn Ihnen dieser Ansatz gefällt, Sie aber die öffentliche Oberfläche Ihrer Klasse nicht durch die Einführung einer
ShouldSerialize
Methode verwirren möchten , können Sie eine verwendenIContractResolver
, um dasselbe programmgesteuert auszuführen. Siehe Serielle Serialisierung von Eigenschaften in der Dokumentation.Ansatz 2: Bearbeiten Sie den JSON mit JObjects
Anstatt
JsonConvert.SerializeObject
die Serialisierung zu verwenden, laden Sie das Konfigurationsobjekt in aJObject
und entfernen Sie dann einfach die unerwünschte Eigenschaft aus dem JSON, bevor Sie sie ausschreiben. Es sind nur ein paar zusätzliche Codezeilen.Ansatz 3: Clevere (ab) Verwendung von Attributen
[JsonIgnore]
Attribut auf die Eigenschaft an, die nicht serialisiert werden soll.[JsonProperty]
Attribut auf den alternativen Setter an und geben Sie ihm denselben JSON-Namen wie die ursprüngliche Eigenschaft.Hier ist die überarbeitete
Config
Klasse:quelle
JsonPropertyAttribute
von können Sie ab C # 6.0 dasnameof
Schlüsselwort anstelle von "magischen Zeichenfolgen" verwenden. Dies macht das Refactoring viel einfacher und kinderleicht. Wenn Sie das Umbenennen von Ereignissen verpassen, werden Sie vom Compiler trotzdem gewarnt. In @ Brians Beispiel wäre die Verwendung wie folgt:[JsonProperty(nameof(ObsoleteSetting))]
Für jede Situation, in der es akzeptabel ist, dass Ihre Nur-Deserialisierungseigenschaft als intern markiert wird, gibt es eine bemerkenswert einfache Lösung, die überhaupt nicht von Attributen abhängt. Markieren Sie die Eigenschaft einfach als intern get, aber public set:
Dies führt zu einer korrekten Deserialisierung unter Verwendung der Standardeinstellungen / Resolver / etc., Aber die Eigenschaft wird von der serialisierten Ausgabe entfernt.
quelle
get
Methode beruht .)internal
nochprivate
. Es wird immer serialisiert.Ich mag es, bei Attributen zu bleiben. Hier ist die Methode, die ich verwende, wenn ich eine Eigenschaft deserialisieren muss, aber nicht serialisieren muss oder umgekehrt.
SCHRITT 1 - Erstellen Sie das benutzerdefinierte Attribut
SCHRITT 2 - Erstellen Sie einen benutzerdefinierten Vertrags-Reslover
SCHRITT 3 - Fügen Sie ein Attribut hinzu, bei dem keine Serialisierung erforderlich ist, die Deserialisierung jedoch
SCHRITT 4 - Verwenden Sie es
Hoffe das hilft! Es ist auch erwähnenswert, dass dies auch die Eigenschaften ignoriert, wenn eine Deserialisierung stattfindet. Wenn ich derserialisiere, verwende ich den Konverter nur auf herkömmliche Weise.
quelle
GetSerializableMembers
anstatt sie vollständig zu überschreiben?return base.GetSerializableMembers(objectType).Where(pi => !Attribute.IsDefined(pi, typeof(JsonIgnoreSerializationAttribute))).ToList();
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() }
Verwenden Sie die Setter-Eigenschaft:
Ich hoffe das hilft.
quelle
IgnoreOnSerializing
, der der Eigenschaft entspricht. Ich empfehle die Verwendungnameof(IgnoreOnSerializing)
, um magische Zeichenfolgen im Falle einer Umbenennung zu vermeiden.Nachdem ich ziemlich lange gesucht hatte, wie man eine Klasseneigenschaft als de-serialisierbar und NICHT serialisierbar kennzeichnet, stellte ich fest, dass es so etwas überhaupt nicht gibt. Also habe ich eine Lösung gefunden, die zwei verschiedene Bibliotheken oder Serialisierungstechniken kombiniert (System.Runtime.Serialization.Json & Newtonsoft.Json) und für mich wie folgt funktioniert:
Serialisieren Sie dann mit "Newtonsoft.Json.JsonConvert.SerializeObject" und de-Serialisieren Sie mit "System.Runtime.Serialization.Json.DataContractJsonSerializer".
Hoffentlich hilft das ...
quelle
In Bezug auf die Lösung von @ ThoHo ist die Verwendung des Setters eigentlich alles, was benötigt wird, ohne zusätzliche Tags.
Für mich hatte ich zuvor eine einzige Referenz-ID, die ich laden und zur neuen Sammlung von Referenz-IDs hinzufügen wollte. Durch Ändern der Definition der Referenz-ID, um nur eine Setter-Methode zu enthalten, die den Wert zur neuen Sammlung hinzufügte. Json kann den Wert nicht zurückschreiben, wenn die Eigenschaft kein get hat. Methode.
Diese Klasse ist jetzt abwärtskompatibel mit der vorherigen Version und speichert die RefIds nur für die neuen Versionen.
quelle
Um auf der Antwort von Tho Ho aufzubauen, kann dies auch für Felder verwendet werden.
quelle
Abhängig davon, wo in der Anwendung dies stattfindet und ob es sich nur um eine Eigenschaft handelt, können Sie dies manuell tun, indem Sie den Eigenschaftswert auf null setzen. Anschließend können Sie im Modell angeben, dass die Eigenschaft ignoriert werden soll, wenn der Wert null ist:
Wenn Sie an einer ASP.NET Core-Webanwendung arbeiten, können Sie dies global für alle Eigenschaften in allen Modellen festlegen, indem Sie dies in Ihrer Datei Startup.cs festlegen:
quelle
Wenn Sie JsonConvert verwenden, ignorieren Sie IgnoreDataMemberAttribute ist IgnoreDataMemberAttribute in Meine Standardbibliothek aktualisiert Newton.Json nicht, und ich verwende [IgnoreDataMember], um die Objektserialisierung zu steuern.
Aus dem Newton.net-Hilfedokument .
quelle
Der einfachste Weg, den ich zum Zeitpunkt dieses Schreibens gefunden habe, besteht darin, diese Logik in Ihren IContractResolver aufzunehmen .
Beispielcode vom obigen Link hier für die Nachwelt kopiert:
Alle Antworten sind gut, aber dieser Ansatz schien der sauberste Weg zu sein. Ich habe dies tatsächlich implementiert, indem ich nach einem Attribut in der Eigenschaft für SkipSerialize und SkipDeserialize gesucht habe, damit Sie einfach jede Klasse markieren können, die Sie steuern. Gute Frage!
quelle