Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making a property deserialize but not serialize with json.net

Tags:

c#

json.net

People also ask

How can you prevent a property from being serialized?

You can prevent member variables from being serialized by marking them with the NonSerialized attribute as follows. If possible, make an object that could contain security-sensitive data nonserializable. If the object must be serialized, apply the NonSerialized attribute to specific fields that store sensitive data.

Which of the following attribute should be used to indicate the property must not be serialized while using JSON serializer?

Apply a [JsonIgnore] attribute to the property that you do not want to be serialized. Add an alternate, private property setter to the class with the same type as the original property. Make the implementation of that property set the original property.

Do we need to serialize JSON?

The purpose of serializing it into JSON is so that the message will be a format that can be understood and from there, deserialize it into an object type that makes sense for the consumer.

What is the difference between serialize and deserialize?

Serialization is a mechanism of converting the state of an object into a byte stream. Deserialization is the reverse process where the byte stream is used to recreate the actual Java object in memory. This mechanism is used to persist the object. The byte stream created is platform independent.


There are actually several fairly simple approaches you can use to achieve the result you want.

Let's assume, for example, that you have your classes currently defined like this:

class Config
{
    public Fizz ObsoleteSetting { get; set; }
    public Bang ReplacementSetting { get; set; }
}

enum Fizz { Alpha, Beta, Gamma }

class Bang
{
    public string Value { get; set; }
}

And you want to do this:

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);

To get this:

{"ReplacementSetting":{"Value":"Gamma"}}

Approach 1: Add a ShouldSerialize method

Json.NET has the ability to conditionally serialize properties by looking for corresponding ShouldSerialize methods in the class.

To use this feature, add a boolean ShouldSerializeBlah() method to your class where Blah is replaced with the name of the property that you do not want to serialize. Make the implementation of this method always return false.

class Config
{
    public Fizz ObsoleteSetting { get; set; }

    public Bang ReplacementSetting { get; set; }

    public bool ShouldSerializeObsoleteSetting()
    {
        return false;
    }
}

Note: if you like this approach but you don't want to muddy up the public interface of your class by introducing a ShouldSerialize method, you can use an IContractResolver to do the same thing programmatically. See Conditional Property Serialization in the documentation.

Approach 2: Manipulate the JSON with JObjects

Instead of using JsonConvert.SerializeObject to do the serialization, load the config object into a JObject, then simply remove the unwanted property from the JSON before writing it out. It's just a couple of extra lines of code.

JObject jo = JObject.FromObject(config);

// remove the "ObsoleteSetting" JProperty from its parent
jo["ObsoleteSetting"].Parent.Remove();

json = jo.ToString();

Approach 3: Clever (ab)use of attributes

  1. Apply a [JsonIgnore] attribute to the property that you do not want to be serialized.
  2. Add an alternate, private property setter to the class with the same type as the original property. Make the implementation of that property set the original property.
  3. Apply a [JsonProperty] attribute to the alternate setter, giving it the same JSON name as the original property.

Here is the revised Config class:

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; }
}

For any situation where it's acceptable to have your deserialization-only property be marked internal, there's a remarkably simple solution that doesn't depend on attributes at all. Simply mark the property as internal get, but public set:

public class JsonTest {

    public string SomeProperty { internal get; set; }

}

This results in correct deserialization using default settings/resolvers/etc., but the property is stripped from serialized output.


I like sticking with attributes on this one, here is the method I use when needing to deserialize a property but not serialize it or vice versa.

STEP 1 - Create the custom attribute

public class JsonIgnoreSerializationAttribute : Attribute { }

STEP 2 - Create a custom Contract 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>();
    }
}

STEP 3 - Add attribute where serialization is not needed but deserialization is

    [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

STEP 4 - Use it

var sweet = JsonConvert.SerializeObject(myObj, new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() });

Hope this helps! Also it's worth noting that this will also ignore the properties when Deserialization happens, when I am derserializing I just use the converter in the conventional way.

JsonConvert.DeserializeObject<MyType>(myString);

Use setter property:

[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; }
}

Hope this help.


After i spent a quite long time searching how to flag a class property to be De-Serializable and NOT Serializable i found that there's no such thing to do that at all; so i came up with a solution that combines two different libraries or serialization techniques (System.Runtime.Serialization.Json & Newtonsoft.Json) and it worked for me like the following:

  • flag all your class and sub-classes as "DataContract".
  • flag all the properties of your class and sub-classes as "DataMember".
  • flag all the properties of your class and sub-classes as "JsonProperty" except those you want them not to be serialized.
  • now flag the properties the you do NOT want it to be serialized as "JsonIgnore".
  • then Serialize using "Newtonsoft.Json.JsonConvert.SerializeObject" and De-Serialize using "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 });
            }
        }
    }
    

Hope that helps ...


Depending on where in the application this takes place and if it's just one property, one manual way you can do this is by setting the property value to null and then on the model you can specify that the property be ignored if the value is null:

[JsonProperty(NullValueHandling = NullValue.Ignore)]
public string MyProperty { get; set; }

If you are working on an ASP.NET Core web app, you can globally set this for all properties in all models by setting this in your Startup.cs file:

public void ConfigureServices(IServiceCollection services) {
    // other configuration here
    services.AddMvc()
        .AddJsonOptions(options => options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore);
}