How to exclude property from Json Serialization
Asked Answered
H

9

357

I have a DTO class which I Serialize

Json.Serialize(MyClass)

How can I exclude a public property of it?

(It has to be public, as I use it in my code somewhere else)

Hypotension answered 16/4, 2012 at 6:34 Comment(5)
Which serialization framework do you use?Ludwog
IgnoreDataMember ScriptIgnore JsonIgnore depending on the serializer you useRoughrider
also noteworthy is the [NonSerialized] attribute, which is only applicable to fields (not properties), but otherwise has the same effect as JsonIgnore.Kinsey
Trynko's comment is very useful.... if you use IgnoreDataMember on a field there will be no error, but it will not be applied.Dispatch
Watch out for your namespaces. The [JsonIgnore] attribute exists in both Newtonsoft.Json and System.Text.Json.Serialization namespaces. It is easy to use Newtonsoft.Json.JsonIgnore on the model but then System.Text.Json.Serialization.JsonSerializer.Serialize to serialize your model (or vice versa). Then the JsonIgnore attribute gets ignored. :)Sloop
P
145

EDIT 2023-06-29: updated answer and added info about .NET core and System.Text.Json


If you don't want to decorate properties with some attributes, or if you have no access to the class, or if you want to decide what to serialize during runtime, here's how you do it:

1. In Newtonsoft.Json

Newtonsoft solution is pretty simple:

//short helper class to ignore some properties from serialization
public class IgnorePropertiesResolver : DefaultContractResolver
{
    private readonly HashSet<string> ignoreProps;
    public IgnorePropertiesResolver(IEnumerable<string> propNamesToIgnore)
    {
        this.ignoreProps = new HashSet<string>(propNamesToIgnore);
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (this.ignoreProps.Contains(property.PropertyName))
        {
            property.ShouldSerialize = _ => false;
        }
        return property;
    }
}

Usage

JsonConvert.SerializeObject(YourObject, new JsonSerializerSettings()
        { ContractResolver = new IgnorePropertiesResolver(new[] { "Prop1", "Prop2" }) });

Make sure you cache the ContractResolver object if you decide to use this answer, otherwise performance may suffer.

I've published the code here in case anyone wants to add anything: https://github.com/jitbit/JsonIgnoreProps

2. In System.Text.Json

.NET core uses System.Text.Json by default, it's faster, but you don't have all the flexibility of Newtonsoft. However here some solutions for excluding properties at runtime:

  1. In .NET 7 and above you can control which properties get serialized like described here: https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-7/#example-conditional-serialization

  2. In .NET 6 (and below) - you can cast to an interface (which I personally find the cleanest) or use a mapper. Both options are descibed in this answer https://mcmap.net/q/93897/-how-to-exclude-a-property-from-being-serialized-in-system-text-json-jsonserializer-serialize-using-a-jsonconverter

Pu answered 7/12, 2019 at 15:9 Comment(10)
Works like a charm. Note that if you have need to combine with another resolver (such as CamelCasePropertyNamesContractResolver, just take your IgnorePropertiesResolver (likely renaming to something more accurate considering the combination) and inherit from CamelCasePropertyNamesContractResolver instead of directly from DefaultContractResolver.Epidemiology
I made a small change for myself... instead of the constructor taking IEnumerable<string>, mine takes IEnumerable<PropertyInfo>... that way you can't pass in a misspelled property name. The caller needs to use Type.GetProperty to get the PropertyInfo from a stringCoincidence
Brilliant answer! You can also use public IgnorePropertiesResolver(params string[] propNamesToIgnore) as your constructor so that the implementer can say new IgnorePropertiesResolver("Prop1", "Prop2")Dewitt
I'm just trying this; I think you have an unwanted semicolon 3 chars from the end?Phagy
This is a great answer if you can't hard-code whether to exclude a property.Phagy
Thanks great answer, I want to add that it can be used also for ignore deserialization, This is the all the properties that are recommended to make sure property is ignored from deserialization as well. property.ShouldSerialize = _ => false; property.Ignored = true; property.Readable = false; property.ShouldDeserialize = _ => false; property.Writable = false;Steffi
I needed exactly this because I have no access to the original class nor the ability to hardcode it with the attributes, but this will allow me to get around that and still not have Json.net crap out on me each time it hits a snag, thank you.Piapiacenza
This is great as I don't want to alter the generated model class by Entity Framework! Thx a bunch!Proviso
Especially useful when combining this with DeclaringType (https://mcmap.net/q/93898/-newtonsoft-json-shouldserialize-and-inheritance). I've create it by passing declaringType to constructor and using it from CreatePropertyCumuliform
This is great and works as of .Net6. Solved my problem when using a DTO library in a package whereby I couldn't alter the class definitions. Thanks Alex!Headdress
H
497

If you are using Json.Net attribute [JsonIgnore] will simply ignore the field/property while serializing or deserialising.

public class Car
{
  // included in JSON
  public string Model { get; set; }
  public DateTime Year { get; set; }
  public List<string> Features { get; set; }

  // ignored
  [JsonIgnore]
  public DateTime LastModified { get; set; }
}

Or you can use DataContract and DataMember attribute to selectively serialize/deserialize properties/fields.

[DataContract]
public class Computer
{
  // included in JSON
  [DataMember]
  public string Name { get; set; }
  [DataMember]
  public decimal SalePrice { get; set; }

  // ignored
  public string Manufacture { get; set; }
  public int StockCount { get; set; }
  public decimal WholeSalePrice { get; set; }
  public DateTime NextShipmentDate { get; set; }
}

Refer http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size for more details

Hercule answered 29/8, 2014 at 10:24 Comment(6)
If I were the OP, I would prefer this answer over the chosen [ScriptIgnore] solution. Primarily due to the congruency of a Json solution so a Json problem. Why involve System.Web.Extensions when the library you are using provides a solution? The absolute best IMHO is the [IgnoreDataMember] attribute, as System.Runtime.Serialization should be compatible with every serializer should you wish to swap out Json.Ponderous
IgnoreDataMember does not work with the default JsonResult serializer.Prerequisite
@user123456 why would you want to ignore when deserialize if value is null? Why not just have a null value for a property, or create a property that handles the null value elegantly?Nestornestorian
Watch out for your namespaces. The [JsonIgnore] attribute exists in both Newtonsoft.Json and System.Text.Json.Serialization namespaces. It is easy to use Newtonsoft.Json.JsonIgnore on the model but then System.Text.Json.Serialization.JsonSerializer.Serialize to serialize your model (or vice versa). Then the JsonIgnore attribute gets ignored. :)Sloop
I found that [JsonIgnore] did not work for me. I had to do the [DataContract] and attribute every member with [DataMember] except the one I didn't want. I don't know why this should be different. I ended up using System.Text.Json but I also tried Newtonsoft.Gilbertson
[JsonIgnore] is also a valid attribute in System.Text.Json.Serialization for ASP.NET CoreBasuto
C
163

If you are using System.Web.Script.Serialization in the .NET framework you can put a ScriptIgnore attribute on the members that shouldn't be serialized. See the example taken from here:

Consider the following (simplified) case:

public class User {
    public int Id { get; set; }
    public string Name { get; set; }
    [ScriptIgnore]
    public bool IsComplete
    {
        get { return Id > 0 && !string.IsNullOrEmpty(Name); }
    } 
} 

In this case, only the Id and the Name properties will be serialized, thus the resulting JSON object would look like this:

{ Id: 3, Name: 'Test User' }

PS. Don't forget to add a reference to "System.Web.Extensions" for this to work

Causeway answered 16/4, 2012 at 6:37 Comment(2)
I found ScriptIgnore in System.Web.Script.Serialization namespace.Predatory
I discovered that System.Web.Controller.Json() (i.e. returning a JsonResult in MVC) only works with [ScriptIgnore], NOT [JsonIgnore]. So use this one for JsonResult types. And yes the correct reference is System.Web.Script.Serialization.Testudo
P
145

EDIT 2023-06-29: updated answer and added info about .NET core and System.Text.Json


If you don't want to decorate properties with some attributes, or if you have no access to the class, or if you want to decide what to serialize during runtime, here's how you do it:

1. In Newtonsoft.Json

Newtonsoft solution is pretty simple:

//short helper class to ignore some properties from serialization
public class IgnorePropertiesResolver : DefaultContractResolver
{
    private readonly HashSet<string> ignoreProps;
    public IgnorePropertiesResolver(IEnumerable<string> propNamesToIgnore)
    {
        this.ignoreProps = new HashSet<string>(propNamesToIgnore);
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (this.ignoreProps.Contains(property.PropertyName))
        {
            property.ShouldSerialize = _ => false;
        }
        return property;
    }
}

Usage

JsonConvert.SerializeObject(YourObject, new JsonSerializerSettings()
        { ContractResolver = new IgnorePropertiesResolver(new[] { "Prop1", "Prop2" }) });

Make sure you cache the ContractResolver object if you decide to use this answer, otherwise performance may suffer.

I've published the code here in case anyone wants to add anything: https://github.com/jitbit/JsonIgnoreProps

2. In System.Text.Json

.NET core uses System.Text.Json by default, it's faster, but you don't have all the flexibility of Newtonsoft. However here some solutions for excluding properties at runtime:

  1. In .NET 7 and above you can control which properties get serialized like described here: https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-7/#example-conditional-serialization

  2. In .NET 6 (and below) - you can cast to an interface (which I personally find the cleanest) or use a mapper. Both options are descibed in this answer https://mcmap.net/q/93897/-how-to-exclude-a-property-from-being-serialized-in-system-text-json-jsonserializer-serialize-using-a-jsonconverter

Pu answered 7/12, 2019 at 15:9 Comment(10)
Works like a charm. Note that if you have need to combine with another resolver (such as CamelCasePropertyNamesContractResolver, just take your IgnorePropertiesResolver (likely renaming to something more accurate considering the combination) and inherit from CamelCasePropertyNamesContractResolver instead of directly from DefaultContractResolver.Epidemiology
I made a small change for myself... instead of the constructor taking IEnumerable<string>, mine takes IEnumerable<PropertyInfo>... that way you can't pass in a misspelled property name. The caller needs to use Type.GetProperty to get the PropertyInfo from a stringCoincidence
Brilliant answer! You can also use public IgnorePropertiesResolver(params string[] propNamesToIgnore) as your constructor so that the implementer can say new IgnorePropertiesResolver("Prop1", "Prop2")Dewitt
I'm just trying this; I think you have an unwanted semicolon 3 chars from the end?Phagy
This is a great answer if you can't hard-code whether to exclude a property.Phagy
Thanks great answer, I want to add that it can be used also for ignore deserialization, This is the all the properties that are recommended to make sure property is ignored from deserialization as well. property.ShouldSerialize = _ => false; property.Ignored = true; property.Readable = false; property.ShouldDeserialize = _ => false; property.Writable = false;Steffi
I needed exactly this because I have no access to the original class nor the ability to hardcode it with the attributes, but this will allow me to get around that and still not have Json.net crap out on me each time it hits a snag, thank you.Piapiacenza
This is great as I don't want to alter the generated model class by Entity Framework! Thx a bunch!Proviso
Especially useful when combining this with DeclaringType (https://mcmap.net/q/93898/-newtonsoft-json-shouldserialize-and-inheritance). I've create it by passing declaringType to constructor and using it from CreatePropertyCumuliform
This is great and works as of .Net6. Solved my problem when using a DTO library in a package whereby I couldn't alter the class definitions. Thanks Alex!Headdress
H
35

You can use [ScriptIgnore]:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    [ScriptIgnore]
    public bool IsComplete
    {
        get { return Id > 0 && !string.IsNullOrEmpty(Name); }
    }
}

In this case the Id and then name will only be serialized

Headband answered 16/4, 2012 at 6:37 Comment(1)
I know it is an old comment, but yes, use [ScriptIgnore] in MVC Controller. Be warned though, if you are using SignalR, then you should use [JsonIgnore] too.Judaea
C
20

If you are not so keen on having to decorate code with Attributes as I am, esp when you cant tell at compile time what will happen here is my solution.

Using the Javascript Serializer

public static class JsonSerializerExtensions
{
    public static string ToJsonString(this object target,bool ignoreNulls = true)
    {
        var javaScriptSerializer = new JavaScriptSerializer();
        if(ignoreNulls)
        {
            javaScriptSerializer.RegisterConverters(new[] { new PropertyExclusionConverter(target.GetType(), true) });
        }

        return javaScriptSerializer.Serialize(target);
    }
        
    public static string ToJsonString(this object target, Dictionary<Type, List<string>> ignore, bool ignoreNulls = true)
    {
        var javaScriptSerializer = new JavaScriptSerializer();
        foreach (var key in ignore.Keys)
        {
            javaScriptSerializer.RegisterConverters(new[] { new PropertyExclusionConverter(key, ignore[key], ignoreNulls) });
        }
        return javaScriptSerializer.Serialize(target);
    }
 }
    
    
public class PropertyExclusionConverter : JavaScriptConverter
{
    private readonly List<string> propertiesToIgnore;
    private readonly Type type;
    private readonly bool ignoreNulls;
    
    public PropertyExclusionConverter(Type type, List<string> propertiesToIgnore, bool ignoreNulls)
    {
        this.ignoreNulls = ignoreNulls;
        this.type = type;
        this.propertiesToIgnore = propertiesToIgnore ?? new List<string>();
    }
    
    public PropertyExclusionConverter(Type type, bool ignoreNulls)
        : this(type, null, ignoreNulls){}
    
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { this.type })); }
    }
    
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
       var result = new Dictionary<string, object>();
       if (obj == null)
       {
           return result;
       }
       var properties = obj.GetType().GetProperties();
       foreach (var propertyInfo in properties)
       {
           if (!this.propertiesToIgnore.Contains(propertyInfo.Name))
           {
               if(this.ignoreNulls && propertyInfo.GetValue(obj, null) == null)
               {
                     continue;
               }
               result.Add(propertyInfo.Name, propertyInfo.GetValue(obj, null));
           }
        }
        return result;
    }
    
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException(); //Converter is currently only used for ignoring properties on serialization
    }
}
Capitulation answered 29/7, 2015 at 7:1 Comment(2)
A minor change in the logic and the PropertyExclusionConverter can be turned into a PropertyInclusionConverter.Dollarfish
One potential issue with this is that it has to do the name-matching and exclusion work over and over each time an object is serialized. However, once compiled, a type's properties won't change--you should make this pre-calculate, per type, the names that should be included and just reuse the list on each row. For a very massive JSON serialization job, caching could make a noticeable difference in performance.Oversight
S
20

For C# 9's records it's [property: JsonIgnore]

using System.Text.Json.Serialization;

public record R(
   string Text2
   [property: JsonIgnore] string Text2)

For the classic style it's still just [JsonIgnore].

using System.Text.Json.Serialization;

public record R
{
   public string Text {get; init; }

   [JsonIgnore] 
   public string Text2 { get; init; }
}
Shep answered 25/3, 2022 at 4:49 Comment(2)
What if I don't own the model I'm deserializing? How can Ignore a specific only when I control the deserialization?Interrelated
This is what I was looking for, thanks! records seem to have this implicit issue with them when convertingCadency
S
17

If you are using System.Text.Json then you can use [JsonIgnore].
FQ: System.Text.Json.Serialization.JsonIgnoreAttribute

Official Microsoft Docs: JsonIgnoreAttribute

As stated here:

The library is built-in as part of the .NET Core 3.0 shared framework.
For other target frameworks, install the System.Text.Json NuGet package. The package supports:

  • .NET Standard 2.0 and later versions
  • .NET Framework 4.6.1 and later versions
  • .NET Core 2.0, 2.1, and 2.2
Synergism answered 21/11, 2019 at 18:8 Comment(0)
A
0

You can also use the [NonSerialized] attribute

[Serializable]
public struct MySerializableStruct
{
    [NonSerialized]
    public string hiddenField;
    public string normalField;
}

From the MS docs:

Indicates that a field of a serializable class should not be serialized. This class cannot be inherited.


If you're using Unity for example (this isn't only for Unity) then this works with UnityEngine.JsonUtility

using UnityEngine;

MySerializableStruct mss = new MySerializableStruct 
{ 
    hiddenField = "foo", 
    normalField = "bar" 
};
Debug.Log(JsonUtility.ToJson(mss)); // result: {"normalField":"bar"}
Acculturize answered 20/11, 2019 at 15:9 Comment(1)
This attribute is not valid for properties, which is what the OP asked about.Testudo
P
0

Add System.Text.Json Version for dotnet core

For compile time, add [JsonIgnore] as suggested in the above answer.

For run time, JsonConverter needs to be added into the options.

First, create a JsonConverter for the type you want to exclude, for example ICollection<LabMethod> below

public class LabMethodConverter : JsonConverter<ICollection<LabMethod>>
{
    public override ICollection<LabMethod> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        //deserialize JSON into a ICollection<LabMethod>
        return null;
    }

    public override void Write(Utf8JsonWriter writer, ICollection<LabMethod> value, JsonSerializerOptions options)
    {
        //serialize a ICollection<LabMethod> object
        writer.WriteNullValue();
    }
}

Then add to options when you serialize Json

var options = new JsonSerializerOptions();
options.Converters.Add(new LabMethodConverter());
var new_obj = Json(new { rows = slice, total = count }, options);
Parrotfish answered 7/8, 2021 at 13:23 Comment(1)
For anyone using the Serialize method instead of the Json method used in this answer, you can still pass in the options object using the appropriate Serialize method overload.Reconstruct

© 2022 - 2024 — McMap. All rights reserved.