Nous avons des fichiers de configuration qui ont été générés en sérialisant des objets C # avec Json.net.
Nous souhaitons que l'une des propriétés de la classe sérialisée ne soit plus une propriété enum mais une propriété de classe.
Un moyen simple de le faire serait de laisser l'ancienne propriété enum sur la classe et de demander à Json.net de lire cette propriété lorsque nous chargerons la configuration, mais de ne pas la sauvegarder à nouveau lors de la prochaine sérialisation de l'objet. Nous allons traiter la génération de la nouvelle classe à partir de l’ancien enum séparément.
Existe-t-il un moyen simple de marquer (avec des attributs, par exemple) une propriété d'un objet C #, de sorte que Json.net l'ignore UNIQUEMENT lors de la sérialisation, tout en s'en occupant lors de la désérialisation?
Il existe en fait plusieurs approches assez simples que vous pouvez utiliser pour obtenir le résultat souhaité.
Supposons, par exemple, que vos classes soient actuellement définies comme ceci:
class Config
{
public Fizz ObsoleteSetting { get; set; }
public Bang ReplacementSetting { get; set; }
}
enum Fizz { Alpha, Beta, Gamma }
class Bang
{
public string Value { get; set; }
}
Et vous voulez faire ceci:
string json = @"{ ""ObsoleteSetting"" : ""Gamma"" }";
// deserialize
Config config = JsonConvert.DeserializeObject<Config>(json);
// migrate
config.ReplacementSetting =
new Bang { Value = config.ObsoleteSetting.ToString() };
// serialize
json = JsonConvert.SerializeObject(config);
Console.WriteLine(json);
Pour obtenir ceci:
{"ReplacementSetting":{"Value":"Gamma"}}
Json.NET a la capacité de sérialiser des propriétés de manière conditionnelle en recherchant les méthodes ShouldSerialize
correspondantes dans la classe.
Pour utiliser cette fonctionnalité, ajoutez une méthode booléenne ShouldSerializeBlah()
à votre classe, où Blah
est remplacé par le nom de la propriété que vous ne souhaitez pas sérialiser. Faire que l'implémentation de cette méthode retourne toujours false
.
class Config
{
public Fizz ObsoleteSetting { get; set; }
public Bang ReplacementSetting { get; set; }
public bool ShouldSerializeObsoleteSetting()
{
return false;
}
}
Remarque: si vous aimez cette approche mais que vous ne voulez pas brouiller l'interface publique de votre classe en introduisant une méthode ShouldSerialize
, vous pouvez utiliser une IContractResolver
pour faire la même chose par programme. Voir Sérialisation des propriétés conditionnelles dans la documentation.
Au lieu d'utiliser JsonConvert.SerializeObject
pour effectuer la sérialisation, chargez l'objet config dans un JObject
, puis supprimez simplement la propriété non désirée du JSON avant de l'écrire. C'est juste quelques lignes de code supplémentaires.
JObject jo = JObject.FromObject(config);
// remove the "ObsoleteSetting" JProperty from its parent
jo["ObsoleteSetting"].Parent.Remove();
json = jo.ToString();
[JsonIgnore]
à la propriété que vous ne souhaitez pas numéroter.[JsonProperty]
à l'autre utilisateur, en lui attribuant le même nom JSON que la propriété d'origine.Voici la classe Config
révisée:
class Config
{
[JsonIgnore]
public Fizz ObsoleteSetting { get; set; }
[JsonProperty("ObsoleteSetting")]
private Fizz ObsoleteSettingAlternateSetter
{
// get is intentionally omitted here
set { ObsoleteSetting = value; }
}
public Bang ReplacementSetting { get; set; }
}
J'aime coller avec les attributs sur celle-ci, voici la méthode que j'utilise pour désérialiser une propriété mais pas pour la sérialiser ou vice versa.
ÉTAPE 1 - Créer l'attribut personnalisé
public class JsonIgnoreSerializationAttribute : Attribute { }
ETAPE 2 - Créer un contrat personnalisé Reslover
class JsonPropertiesResolver : DefaultContractResolver
{
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
//Return properties that do NOT have the JsonIgnoreSerializationAttribute
return objectType.GetProperties()
.Where(pi => !Attribute.IsDefined(pi, typeof(JsonIgnoreSerializationAttribute)))
.ToList<MemberInfo>();
}
}
ÉTAPE 3 - Ajouter un attribut là où la sérialisation n'est pas nécessaire mais la désérialisation est
[JsonIgnoreSerialization]
public string Prop1 { get; set; } //Will be skipped when serialized
[JsonIgnoreSerialization]
public string Prop2 { get; set; } //Also will be skipped when serialized
public string Prop3 { get; set; } //Will not be skipped when serialized
ÉTAPE 4 - Utilisez-le
var sweet = JsonConvert.SerializeObject(myObj, new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() });
J'espère que cela t'aides! En outre, il est à noter que cela ignorera également les propriétés lorsque la désérialisation se produit, lorsque je désérialise, j'utilise simplement le convertisseur de manière classique.
JsonConvert.DeserializeObject<MyType>(myString);
Utilisez la propriété setter:
[JsonProperty(nameof(IgnoreOnSerializing))]
public string IgnoreOnSerializingSetter { set { _ignoreOnSerializing = value; } }
[JsonIgnore]
private string _ignoreOnSerializing;
[JsonIgnore]
public string IgnoreOnSerializing
{
get { return this._ignoreOnSerializing; }
set { this._ignoreOnSerializing = value; }
}
J'espère que cette aide.
Après avoir passé assez de temps à chercher comment marquer une propriété de classe comme étant dé-sérialisable et non sérialisable, j'ai constaté qu'il n'y a rien de tel pour le faire; Je propose donc une solution combinant deux bibliothèques ou techniques de sérialisation différentes (System.Runtime.Serialization.Json & Newtonsoft.Json) et fonctionne comme suit:
puis Sérialiser en utilisant "Newtonsoft.Json.JsonConvert.SerializeObject" et Sérialiser en utilisant "System.Runtime.Serialization.Json.DataContractJsonSerializer".
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
namespace LUM_Win.model
{
[DataContract]
public class User
{
public User() { }
public User(String JSONObject)
{
MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(JSONObject));
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(User));
User user = (User)dataContractJsonSerializer.ReadObject(stream);
this.ID = user.ID;
this.Country = user.Country;
this.FirstName = user.FirstName;
this.LastName = user.LastName;
this.Nickname = user.Nickname;
this.PhoneNumber = user.PhoneNumber;
this.DisplayPicture = user.DisplayPicture;
this.IsRegistred = user.IsRegistred;
this.IsConfirmed = user.IsConfirmed;
this.VerificationCode = user.VerificationCode;
this.Meetings = user.Meetings;
}
[DataMember(Name = "_id")]
[JsonProperty(PropertyName = "_id")]
public String ID { get; set; }
[DataMember(Name = "country")]
[JsonProperty(PropertyName = "country")]
public String Country { get; set; }
[DataMember(Name = "firstname")]
[JsonProperty(PropertyName = "firstname")]
public String FirstName { get; set; }
[DataMember(Name = "lastname")]
[JsonProperty(PropertyName = "lastname")]
public String LastName { get; set; }
[DataMember(Name = "nickname")]
[JsonProperty(PropertyName = "nickname")]
public String Nickname { get; set; }
[DataMember(Name = "number")]
[JsonProperty(PropertyName = "number")]
public String PhoneNumber { get; set; }
[DataMember(Name = "thumbnail")]
[JsonProperty(PropertyName = "thumbnail")]
public String DisplayPicture { get; set; }
[DataMember(Name = "registered")]
[JsonProperty(PropertyName = "registered")]
public bool IsRegistred { get; set; }
[DataMember(Name = "confirmed")]
[JsonProperty(PropertyName = "confirmed")]
public bool IsConfirmed { get; set; }
[JsonIgnore]
[DataMember(Name = "verification_code")]
public String VerificationCode { get; set; }
[JsonIgnore]
[DataMember(Name = "meeting_ids")]
public List<Meeting> Meetings { get; set; }
public String toJSONString()
{
return JsonConvert.SerializeObject(this, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
}
}
}
J'espère que cela pourra aider ...
Pour toute situation dans laquelle il est acceptable que votre propriété réservée à la désérialisation soit marquée comme étant interne, il existe une solution remarquablement simple qui ne dépend pas du tout des attributs. Marquez simplement la propriété comme get interne, mais ensemble public:
public class JsonTest {
public string SomeProperty { internal get; set; }
}
Cela aboutit à une désérialisation correcte à l'aide des paramètres/résolveurs par défaut/etc., Mais la propriété est supprimée de la sortie sérialisée.
en référence à la solution de @ ThoHo, utiliser le setter est en fait tout ce qui est nécessaire, sans balises supplémentaires.
Pour moi, j’avais auparavant un seul ID de référence, que je voulais charger et ajouter à la nouvelle collection d’ID de référence. En modifiant la définition de l'ID de référence pour ne contenir qu'une méthode de définition, qui a ajouté la valeur à la nouvelle collection. Json ne peut pas écrire la valeur si la propriété n'a pas get; méthode.
// Old property that I want to read from Json, but never write again. No getter.
public Guid RefId { set { RefIds.Add(value); } }
// New property that will be in use from now on. Both setter and getter.
public ICollection<Guid> RefIds { get; set; }
Cette classe est désormais rétro-compatible avec la version précédente et enregistre uniquement RefIds pour les nouvelles versions.
Si vous utilisez JsonConvert, IgnoreDataMemberAttribute est ok.Ma bibliothèque standard ne référence pas Newton.Json et j'utilise [IgnoreDataMember] pour contrôler la sérialisation des objets.
De Newton.net document d'aide.
Pour construire sur la réponse de Tho Ho, cela peut également être utilisé pour les champs.
[JsonProperty(nameof(IgnoreOnSerializing))]
public string IgnoreOnSerializingSetter { set { IgnoreOnSerializing = value; } }
[JsonIgnore]
public string IgnoreOnSerializing;
En fonction de l'endroit où cela se produit dans l'application et s'il ne s'agit que d'une propriété, vous pouvez le faire de manière manuelle en définissant la valeur de la propriété sur null, puis sur le modèle, vous pouvez spécifier que la propriété est ignoré si la valeur est null:
[JsonProperty(NullValueHandling = NullValue.Ignore)]
public string MyProperty { get; set; }
Si vous travaillez sur une application Web ASP.NET Core, vous pouvez le définir globalement pour toutes les propriétés de tous les modèles en le définissant dans votre fichier Startup.cs:
public void ConfigureServices(IServiceCollection services) {
// other configuration here
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore);
}
Existe-t-il un moyen simple de marquer (avec des attributs, par exemple) une propriété d'un objet C #, de sorte que Json.net l'ignore UNIQUEMENT lors de la sérialisation, tout en s'en occupant lors de la désérialisation?
Le moyen le plus simple que j'ai trouvé au moment d'écrire ces lignes est d'inclure cette logique dans votre IContractResolver .
Exemple de code du lien ci-dessus copié ici pour la postérité:
public class Employee
{
public string Name { get; set; }
public Employee Manager { get; set; }
public bool ShouldSerializeManager()
{
// don't serialize the Manager property if an employee is their own manager
return (Manager != this);
}
}
public class ShouldSerializeContractResolver : DefaultContractResolver
{
public new static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(Employee) && property.PropertyName == "Manager")
{
property.ShouldSerialize =
instance =>
{
Employee e = (Employee)instance;
return e.Manager != e;
};
}
return property;
}
}
Toutes les réponses sont bonnes mais cette approche semblait être la plus propre. En fait, je l'ai implémenté en recherchant un attribut sur la propriété pour SkipSerialize et SkipDeserialize afin que vous puissiez simplement marquer toute classe que vous contrôlez. Bonne question!