Mamy kilka plików konfiguracyjnych, które zostały wygenerowane przez serializację obiektów C # za pomocą Json.net.
Chcielibyśmy przeprowadzić migrację jednej właściwości klasy serializowanej z prostej właściwości wyliczeniowej do właściwości klasy.
Jednym prostym sposobem na zrobienie tego byłoby pozostawienie starej właściwości enum w klasie i zorganizowanie odczytywania tej właściwości przez Json.net podczas ładowania konfiguracji, ale nie zapisywanie jej ponownie przy następnym serializowaniu obiektu. Oddzielnie zajmiemy się generowaniem nowej klasy ze starego wyliczenia.
Czy istnieje prosty sposób na oznaczenie (np. Atrybutami) właściwości obiektu C #, aby Json.net zignorował ją TYLKO podczas serializacji, ale zajmie się nią podczas deserializacji?
Odpowiedzi:
W rzeczywistości istnieje kilka dość prostych podejść, których możesz użyć, aby osiągnąć pożądany rezultat.
Załóżmy na przykład, że masz obecnie zdefiniowane klasy w następujący sposób:
I chcesz to zrobić:
Aby to uzyskać:
Podejście 1: Dodaj metodę ShouldSerialize
Json.NET może warunkowo serializować właściwości, szukając odpowiednich
ShouldSerialize
metod w klasie.Aby użyć tej funkcji, dodaj
ShouldSerializeBlah()
do klasy metodę logiczną , w którejBlah
zostanie zastąpiona nazwą właściwości, której nie chcesz serializować. Spraw, aby implementacja tej metody zawsze zwracałafalse
.Uwaga: jeśli podoba ci się to podejście, ale nie chcesz zagmatwać publicznego interfejsu swojej klasy przez wprowadzenie
ShouldSerialize
metody, możesz użyć narzędzia an,IContractResolver
aby zrobić to samo programowo. Zobacz Serializacja właściwości warunkowych w dokumentacji.Podejście 2: manipuluj JSON za pomocą JObjects
Zamiast używać
JsonConvert.SerializeObject
do serializacji, załaduj obiekt config do aJObject
, a następnie po prostu usuń niechcianą właściwość z JSON przed jej zapisaniem. To tylko kilka dodatkowych linii kodu.Podejście 3: Sprytne (nad) wykorzystanie atrybutów
[JsonIgnore]
atrybut do właściwości, której nie chcesz serializować.[JsonProperty]
atrybut do alternatywnej metody ustawiającej, nadając jej taką samą nazwę JSON, jak oryginalna właściwość.Oto poprawiona
Config
klasa:źródło
JsonPropertyAttribute
, od C # 6.0 można użyćnameof
słowa kluczowego zamiast używać „magicznych ciągów”. To sprawia, że refaktoryzacja jest o wiele łatwiejsza i niezawodna - a ponadto, jeśli przegapisz zmianę nazwy jakichkolwiek wystąpień, kompilator i tak Cię ostrzeże. Używając przykładu @ Briana, użycie byłoby następujące:[JsonProperty(nameof(ObsoleteSetting))]
W każdej sytuacji, w której właściwość tylko do deserializacji może być oznaczona jako wewnętrzna, istnieje niezwykle proste rozwiązanie, które w ogóle nie zależy od atrybutów. Po prostu oznacz właściwość jako wewnętrzną get, ale publiczną:
Powoduje to poprawną deserializację przy użyciu ustawień domyślnych / programów rozpoznawania nazw / itp., Ale właściwość jest usuwana z serializowanych danych wyjściowych.
źródło
get
metodzie publicznej ).internal
aniprivate
. Jest zawsze serializowany.Lubię trzymać się atrybutów w tym przypadku, oto metoda, której używam, gdy muszę deserializować właściwość, ale nie serializować jej lub odwrotnie.
KROK 1 - Utwórz atrybut niestandardowy
KROK 2 - Utwórz niestandardową umowę Reslover
KROK 3 - Dodaj atrybut tam, gdzie serializacja nie jest potrzebna, ale deserializacja jest
KROK 4 - Użyj go
Mam nadzieję że to pomoże! Warto również zauważyć, że spowoduje to również zignorowanie właściwości, gdy nastąpi deserializacja, kiedy derserializuję, po prostu używam konwertera w konwencjonalny sposób.
źródło
GetSerializableMembers
zamiast całkowicie ją zastąpić?return base.GetSerializableMembers(objectType).Where(pi => !Attribute.IsDefined(pi, typeof(JsonIgnoreSerializationAttribute))).ToList();
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() }
Użyj właściwości ustawiającej:
Mam nadzieję, że to pomoże.
źródło
IgnoreOnSerializing
równą właściwości. Zalecam używanie,nameof(IgnoreOnSerializing)
aby uniknąć magicznego ciągu w przypadku zmiany nazwy.Po tym, jak spędziłem dość długi czas na poszukiwaniu, jak oznaczyć właściwość klasy jako de-serializowalną, a nie serializowalną, stwierdziłem, że w ogóle nie ma czegoś takiego; więc wymyśliłem rozwiązanie, które łączy dwie różne biblioteki lub techniki serializacji (System.Runtime.Serialization.Json i Newtonsoft.Json) i działało dla mnie w następujący sposób:
następnie Serializuj za pomocą „Newtonsoft.Json.JsonConvert.SerializeObject” i De-Serialize za pomocą „System.Runtime.Serialization.Json.DataContractJsonSerializer”.
Mam nadzieję, że to pomoże ...
źródło
w odniesieniu do rozwiązania @ ThoHo, użycie settera to właściwie wszystko, czego potrzeba, bez dodatkowych tagów.
Wcześniej miałem jeden identyfikator referencyjny, który chciałem załadować i dodać do nowej kolekcji identyfikatorów referencyjnych. Zmieniając definicję identyfikatora odwołania, aby zawierała tylko metodę ustawiającą, która dodała wartość do nowej kolekcji. Json nie może zapisać wartości z powrotem, jeśli Property nie ma get; metoda.
Ta klasa jest teraz wstecznie kompatybilna z poprzednią wersją i zapisuje RefIds tylko dla nowych wersji.
źródło
Aby rozwinąć odpowiedź Tho Ho, można to również wykorzystać do pól.
źródło
W zależności od tego, gdzie w aplikacji ma to miejsce i jeśli jest to tylko jedna właściwość, jednym ręcznym sposobem można to zrobić, ustawiając wartość właściwości na null, a następnie w modelu można określić, że właściwość ma być ignorowana, jeśli wartość jest równa null:
Jeśli pracujesz nad aplikacją internetową ASP.NET Core, możesz globalnie ustawić to dla wszystkich właściwości we wszystkich modelach, ustawiając to w pliku Startup.cs:
źródło
Jeśli używasz JsonConvert, IgnoreDataMemberAttribute jest w porządku. Moja standardowa biblioteka nie odwołuje się do Newton.Json i używam [IgnoreDataMember] do sterowania serializacją obiektu.
Z dokumentu pomocy Newton.net .
źródło
Najłatwiejszym sposobem, jaki znalazłem podczas pisania tego tekstu, jest włączenie tej logiki do twojego IContractResolver .
Przykładowy kod z powyższego linku skopiowany tutaj dla potomności:
Wszystkie odpowiedzi są dobre, ale takie podejście wydawało się najczystsze. W rzeczywistości zaimplementowałem to, szukając atrybutu we właściwości dla SkipSerialize i SkipDeserialize, dzięki czemu możesz po prostu oznaczyć dowolną kontrolowaną klasę. Świetne pytanie!
źródło