I have the following model structure:
public class A
{
[JsonProperty("id")]
public string Id { get { return "A:ID"; } }
[JsonProperty("CompKey")]
public string CompKey { get; set; }
}
public class B : A
{
[JsonProperty("id")]
public string Id { get { return "B:ID"; } }
[JsonProperty("name")]
public string Name { get; set; }
}
I want to serialize an instance of class B but only want the Id property of class A to be visible.
I created a contract resolver to pass to Newtonsoft:
public class DatabaseEntryResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = instance => property.DeclaringType == typeof(A);
return property;
}
}
I use this in the following manner:
var someObject = new A();
var json = JsonConvert.SerializeObject(someObject, new JsonSerializerSettings
{
ContractResolver = new DatabaseEntryResolver()
});
However, neither of the ID properties are being created in the JSON structure. Anyone might shed some insight on this issue I am having?
Json.NET will never serialize two properties with the same name. If DefaultContractResolver encounters two identically named properties, it chooses to serialize the most derived property that is not ignored. Notably, this decision is based on static metadata such as the presence of absence of [JsonIgnore] -- and not on runtime state such as the return from ShouldSerialize.
Thus, to make A.Id supersede B.Id when serializing an instance of B, you must override CreateProperty() as follows:
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (member.ReflectedType == typeof(B)) // Use (typeof(A).IsAssignableFrom(member.ReflectedType)) if you want this to apply to all subclasses of A
{
// Make A.Id supersede B.Id
if (member.Name == nameof(A.Id) && member.DeclaringType != typeof(A))
property.Ignored = true;
}
return property;
}
In addition, if you want really ony want the Id property of class A to be visible when serializing an instance of B, you must in addition remove or ignore everything else in CreateProperties():
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
if (type == typeof(B)) // Use typeof(A).IsAssignableFrom(type)) if you want to only serialize the Id property of A and all its subclasses
{
// Remove everything except Id. You could also Ignore everything except Id.
properties = properties.Where(p => p.UnderlyingName == nameof(A.Id)).ToList();
}
return properties;
}
Notes:
Presumably Newtonsoft does not check ShouldSerialize to determine which Id property to bind to JSON because ShouldSerialize cannot be called during deserialization.
If you really just want to serialize { "id": "A:ID" } for every instance of A or any subclass of A, use typeof(A).IsAssignableFrom() where I mention it in code comments.
You should mark B.Id with the new modifier to avoid a compilation warning.
public class B : A
{
[JsonProperty("id")]
public new string Id { get { return "B:ID"; } } // Fixed compilation
For more see Knowing When to Use Override and New Keywords (C# Programming Guide).
Demo fiddle here;
For whoever has encountered this issue, an explanation was given by the guys who developer Netwonsoft.JSON here, such that my new contract resolver is the following:
public class DatabaseEntryResolver : DefaultContractResolver
{
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
return base.GetSerializableMembers(objectType).Where(member => member.DeclaringType == typeof(A);
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = instance => property.DeclaringType == typeof(A);
return property;
}
}
Note how I still decided to leave the overloaded CreateProperty method, even though technically it is not needed as the overloaded GetSerializableMembers method already filters out the properties I need. I decided to this just in case but without it the solution still works.
Related
We have some web API and some clients to consume the output.
One api return this:
public class InstrumentInfoV11 : InstrumentInfoBase
{
[JsonProperty("InstrumentType")]
public string InstrumentTypeCode { get; set; }
}
basically our API output property InstrumentType and we want our c# client to have a property called InstrumentTypeCode instead. JsonProperty did work and the c# property is populated.
However, when we try to output the result from the client:
InstrumentInfoV11 response = await Client.InstrumentInfoAsync(theRequest);
return JsonConvert.SerializeObject(response, Formatting.Indented);
The property InstrumentTypeCode becomes InstrumentType again
{
"InstrumentType": "X",
...
}
Is there a way to tell newton that when SerializeObject, it should ignore JsonProperty("InstrumentType") and when deSerializeObject, it should take it into consideration?
Usually serializers want to be able to store and reload the same data, so if you store something as X, it wants to read it as X, otherwise the assumption is that it can't do the job of loading data it wrote.
However, you could perhaps have two properties - allow either to read, and only ever write one; i.e.
// the real property
public string InstrumentTypeCode { get; set; }
// conditional serialization
[Browsable(false)]
public bool ShouldSerializeInstrumentTypeCode() => false;
// shim property
[Browsable(false)]
public string InstrumentType {
get => InstrumentTypeCode;
set => InstrumentTypeCode = value;
}
You could use a Custom Contract Resolver for the purpose. For example,
public class IgnorePropertyNameContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
foreach (JsonProperty prop in list)
{
prop.PropertyName = prop.UnderlyingName;
}
return list;
}
}
You could use Deserialize using Json Property Name
var jsonResponse = "{'InstrumentType':'abc'}";
var instance = JsonConvert.DeserializeObject<InstrumentInfoV11>(jsonResponse);
And Serialize ignoring the Json Property Name
JsonSerializerSettings settings = new JsonSerializerSettings{ContractResolver = new IgnorePropertyNameContractResolver()};
var serialized = JsonConvert.SerializeObject(instance,settings);
Output
{"InstrumentTypeCode":"abc"}
How do I ignore certain properties when deserializing a json string.
Say I have a string
{"Id": 123, "name":"Test", "Description":"desc123ds"}
and a class with the same properties.
In some cases I don't want to return "Id".
I have tried a custom ContractResolver but the only thing it does is sets the default value and the property remains present in the json string.
public class CoreJsonContractResolver<T> : DefaultContractResolver
{
public static CoreJsonContractResolver<T> Instance { get; } = new CoreJsonContractResolver<T>();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if(property.DeclaringType == typeof(T))
{
if (property.PropertyName == "Id")
property.Ignored = true;
}
return property;
}
}
EDIT:
The reason why I didn't use [JsonIgnore] property is because I need to ignore properties only in certain cases.
Have a look at JsonIgnore attribure and have a look at this article
I am failing at a task to encrypt certain fields when serializing into JSON and decrypt those fields during deserialization into a specific C# class.
I reduced the problem to its most basic issue, which is that I cannot customize the deserialization of specific fields by manipulating the value, and I don't know the reason. I am using a custom contract resolver and a custom value provider for each field. I can see that the GetValue function is executed but the SetValue is never executed.
The code sample:
class Program
{
static void Main(string[] args)
{
var text = "This is text";
var number = 1;
var anotherText = "This is another text";
var anotherNumber = 2;
var sampleInner = new SampleInner(anotherText, anotherNumber);
var sample = new SampleMessage(text, number, sampleInner);
var myCustomContractResolver = new MyCustomContractResolver();
var jsonSettings = GetJsonSettings(myCustomContractResolver);
Console.WriteLine("Serializing..");
var json = JsonConvert.SerializeObject(sample, jsonSettings);
Console.WriteLine(json);
Console.WriteLine("Deserializing..");
var sampleDeserialized = JsonConvert.DeserializeObject(json, typeof(SampleMessage), jsonSettings);
Console.WriteLine(sampleDeserialized);
Console.ReadLine();
}
private static JsonSerializerSettings GetJsonSettings(IContractResolver contractResolver)
{
var jsonSettings =
new JsonSerializerSettings
{
ContractResolver = contractResolver
};
return jsonSettings;
}
}
the custom contract resolver:
public class MyCustomContractResolver
: DefaultContractResolver
{
public MyCustomContractResolver()
{
NamingStrategy = new CamelCaseNamingStrategy();
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var jsonProperties = base.CreateProperties(type, memberSerialization);
foreach (var jsonProperty in jsonProperties)
{
var propertyInfo = type.GetProperty(jsonProperty.UnderlyingName);
var defaultValueProvider = jsonProperty.ValueProvider;
jsonProperty.ValueProvider = new MyValueProvider(defaultValueProvider);
}
return jsonProperties;
}
}
and the custom value provider whose SetValue is never executed during deserialization:
public class MyValueProvider
: IValueProvider
{
private readonly IValueProvider _valueProvider;
public MyValueProvider(IValueProvider valueProvider)
{
_valueProvider = valueProvider;
}
public void SetValue(object target, object value)
{
//This is not executed during deserialization. Why?
_valueProvider.SetValue(target, value);
Console.WriteLine($"Value set: {value}");
}
public object GetValue(object target)
{
var value = _valueProvider.GetValue(target);
Console.WriteLine($"Value get: {value}");
return value;
}
}
Here is the sample code to reproduce it in case it's needed.
Hopefully somebody can let me know what am I missing :)
UPDATE 1: The object I serialize/deserialize is immutable (no public setters) and that's a requirement because I need to support such objects. As a comment points out, then it makes sense there is no SetValue executed
UPDATE 2: Thanks to #dbc for the brilliant answer no I know a good workaround for deserialization into immutable object. The final version code after the accepted answer.
UPDATE 3: The chosen answer is absolutely correct given the question. However, after investigating further I decided to go with a slightly different approach that works for both immutable and mutable classes in case somebody is in a similar situation. Instead using value providers I use now a combination of contract resolver and json converter so that with the contract resolver I can decide how to serialize/deserialize based on the type, and with the json converter I can access the value during serialization/deserialization and manipulate as desired.
Basically, on my contract resolver I override the method to create properties (where I can access my original Type properties) and selectively I specify which json converter to use.
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var jsonProperties = base.CreateProperties(type, memberSerialization);
//Filter here based on type, attribute or whatever and if want to customize a specific property type:
foreach (var jsonProperty in jsonProperties)
{
jsonProperty.Converter = new MyJsonConverter();
}
return jsonProperties;
}
and in the MyJsonConverter we can choose what to do when writing into json or when reading from json:
public class MyJsonConverter
: JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//I can do whatever with value
var finalValue = $"{value}-edited";
writer.WriteValue(finalValue);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// I can do whatever with the value
var value = (string)reader.Value;
var newValue = "whatever";
return newValue;
}
public override bool CanWrite => true;
public override bool CanRead => true;
public override bool CanConvert(Type objectType)
{
return true;
}
}
The reason that IValueProvider.SetValue is not called for the properties of SampleInner is that SampleInner is immutable and so there are no set methods to be called. Instead, the JSON properties are matched to arguments of the type's single parameterized constructor by name (modulo case), deserialized to the type of the matched argument, and then passed into the constructor as explained here.
Even if you were to make the properties mutable the setter will not be called for properties already passed into the constructor, as Json.NET makes the (reasonable) assumption that passing a property value into the constructor is sufficient to set the property's value.
So, what are your options?
Firstly, you could make your types mutable with a default constructor. The setters and constructor could be private as long as they are marked with appropriate attributes:
public class SampleInner
{
[JsonProperty] // Adding this attribute informs Json.NET that the private setter can be called.
public string AnotherText { get; private set; }
[JsonProperty]
public int AnotherNumber { get; private set; }
[JsonConstructor] // Adding this attribute informs Json.NET that this private constructor can be called
private SampleInner() { }
public SampleInner(string anotherText, int anotherNumber)
{
this.AnotherText = anotherText;
this.AnotherNumber = anotherNumber;
}
}
Now that there are setters to be called, your MyValueProvider.SetValue() will get invoked. Demo fiddle #1 here.
Secondly, if you cannot so modify your types, you could wrap the constructor method called in some decorator that does the necessary pre-processing, however this is made difficult by the fact that JsonObjectContract.ParameterizedCreator is nonpublic. Thus you cannot get direct access to the parameterized constructor that Json.NET has chosen, in order to decorate it. You can, however, determine its arguments, which are specified by JsonObjectContract.CreatorParameters. When this collection is populated then either OverrideCreator is set or the (secret) ParameterizedCreator is set. This allows the necessary logic to be inserted as follows:
public class MyCustomContractResolver : DefaultContractResolver
{
public MyCustomContractResolver() { NamingStrategy = new CamelCaseNamingStrategy(); }
static ObjectConstructor<Object> GetParameterizedConstructor(JsonObjectContract contract)
{
if (contract.OverrideCreator != null)
return contract.OverrideCreator;
// Here we assume that JsonSerializerSettings.ConstructorHandling == ConstructorHandling.Default
// If you would prefer AllowNonPublicDefaultConstructor then you need to remove the check on contract.DefaultCreatorNonPublic
if (contract.CreatorParameters.Count > 0 && (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic))
{
// OK, Json.NET has a parameterized constructor stashed away in JsonObjectContract.ParameterizedCreator
// https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs#L100
// But, annoyingly, this value is internal so we cannot get it!
// But because CreatorParameters.Count > 0 and OverrideCreator == null we can infer that such a constructor exists, and so call it using Activator.CreateInstance
return (args) => Activator.CreateInstance(contract.CreatedType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, args, CultureInfo.InvariantCulture);
}
return null;
}
static ObjectConstructor<Object> CustomizeConstructor(JsonObjectContract contract, ObjectConstructor<Object> constructor)
{
if (constructor == null)
return null;
return (args) =>
{
// Add here your customization logic.
// You can match creator parameters to properties by property name if needed.
foreach (var pair in args.Zip(contract.CreatorParameters, (a, p) => new { Value = a, Parameter = p }))
{
// Get the corresponding property in case you need to, e.g., check its attributes:
var property = contract.Properties[pair.Parameter.PropertyName];
if (property == null)
Console.WriteLine("Argument {0}: Value {1}", pair.Parameter.PropertyName, pair.Value);
else
Console.WriteLine("Argument {0} (corresponding to JsonProperty {1}): Value {2}", pair.Parameter.PropertyName, property, pair.Value);
}
return constructor(args);
};
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
contract.OverrideCreator = CustomizeConstructor(contract, GetParameterizedConstructor(contract));
return contract;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var jsonProperties = base.CreateProperties(type, memberSerialization);
foreach (var jsonProperty in jsonProperties)
{
var defaultValueProvider = jsonProperty.ValueProvider;
jsonProperty.ValueProvider = new MyValueProvider(defaultValueProvider);
}
return jsonProperties;
}
}
Notes:
If a default constructor exists but is nonpublic, the above contract resolver assumes that it is not used. If you would prefer nonpublic default constructors to be used, you will need to set JsonSerializerSettings.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor and also modify the code in GetParameterizedConstructor() above to remove the check on contract.DefaultCreatorNonPublic:
if (contract.CreatorParameters.Count > 0 && contract.DefaultCreator == null)
It would be reasonable to request an enhancement to allow access to, and customization of, JsonObjectContract.ParameterizedCreator.
(I suppose you could try to access JsonObjectContract.ParameterizedCreator directly via reflection...)
Demo fiddle #2 here.
I have the following class structure:
[JsonObject]
public class Polygon : IEnumerable<Point>
{
public List<Point> Vertices { get; set; }
public AxisAlignedRectangle Envelope { get; set; }
}
public class AxisAlignedRectangle : Polygon {
public double Left { get; set; }
...
}
I am serializing the Polygon class, but when I do, I get a JsonSerializationException, with the message
Self referencing loop detected for property 'Envelope' with type 'MyNamespace.AxisAlignedRectangle'.
If I add [JsonObject(IsReference = true)] (as described here) to AxisAlignedRectangle, the code runs fine, but I get an auto-assigned $id field in each instance of AxisAlignedRectangle, and a $ref field when that instance is re-referenced. For example, when I serialize a polygon, I get:
{
Vertices: [ ... ],
Envelope: {
$id: '1',
Left: -5,
...
Vertices: [ ... ],
Envelope: {
$ref: '1'
}
}
}
My desire is to remove the Polygon properties entirely when I serialize an AxisAlignedRectangle. I tried adding a DataContractAttribute to the AxisAlignedRectangle class (along with appropriate DataMemberAttribute attributes), but all the properties of Polygon were still being serialized. This was unexpected, since there is an example in the Json.NET documentation that appears to indicate such an approach should work.
Does anyone know a way to explicitly remove (most importantly) the Envelope property from the resulting Json.NET serialization, when the type being serialized is AxisAlignedRectangle? Thanks.
Most simple way to do it is simply decorate the AxisAlignedRectangle object with [JsonObject(MemberSerialization.OptIn)].
In a sentence, it will serialize only properties decorated with [JsonProperty] attribute.
You can read more here: MemberSerialization Enumeration.
Another option is to decorate the Polygon properties with JsonIgnoreAttribute Class.
I've run into the same thing. The JsonIgnoreAttribute is a good solution if a certain property should always be ingored and you have access to the class containing the property. But if you want to determine which properties should be serialized at serialization-time, you can use a ContractResolver.
Here's an implementation that allows you to serialize properties starting with the most derived class and stopping at a given base class. In my case, I wanted to serialize the properties of my custom CMS (EPiServer) page types, but didn't want to serialize all of the built-in properties of the page classes.
public class DerivedClassContractResolver : DefaultContractResolver
{
private Type _stopAtBaseType;
public DerivedClassContractResolver(Type stopAtBaseType)
{
_stopAtBaseType = stopAtBaseType;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
Type originalType = GetOriginalType(type);
IList<JsonProperty> defaultProperties = base.CreateProperties(type, memberSerialization);
List<string> includedProperties = Utilities.GetPropertyNames(originalType, _stopAtBaseType);
return defaultProperties.Where(p => includedProperties.Contains(p.PropertyName)).ToList();
}
private Type GetOriginalType(Type type)
{
Type originalType = type;
//If the type is a dynamic proxy, get the base type
if (typeof(Castle.DynamicProxy.IProxyTargetAccessor).IsAssignableFrom(type))
originalType = type.BaseType ?? type;
return originalType;
}
}
public class Utilities
{
/// <summary>
/// Gets a list of all public instance properties of a given class type
/// excluding those belonging to or inherited by the given base type.
/// </summary>
/// <param name="type">The Type to get property names for</param>
/// <param name="stopAtType">A base type inherited by type whose properties should not be included.</param>
/// <returns></returns>
public static List<string> GetPropertyNames(Type type, Type stopAtBaseType)
{
List<string> propertyNames = new List<string>();
if (type == null || type == stopAtBaseType) return propertyNames;
Type currentType = type;
do
{
PropertyInfo[] properties = currentType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
foreach (PropertyInfo property in properties)
if (!propertyNames.Contains(property.Name))
propertyNames.Add(property.Name);
currentType = currentType.BaseType;
} while (currentType != null && currentType != stopAtBaseType);
return propertyNames;
}
}
This let's me do something like this:
JsonConvert.SerializeObject(page, new JsonSerializerSettings()
{
ContractResolver = new DerivedClassContractResolver(typeof(EPiServer.Core.PageData))
}));
to get the properties I have defined on my own class(es) without getting the slew of properties inherited from EPiServer.Core.PageData. Note: You don't need the GetOriginalType() code if you're not using the Castle DynamicProxy project (which the EPiServer CMS does.)
You can use conditional property serialization, by defining your classes like this:
[JsonObject]
public class Polygon : IEnumerable<Point>
{
public List<Point> Vertices { get; set; }
public AxisAlignedRectangle Envelope { get; set; }
public virtual bool ShouldSerializeEnvelope()
{
return true;
}
}
public class AxisAlignedRectangle : Polygon
{
public double Left { get; set; }
...
public override bool ShouldSerializeEnvelope()
{
return false;
}
}
I have posted the full solution at:
https://github.com/thiagoavelino/VisualStudio_C/blob/master/VisualStudio_C/StackOverFlow/ParsingJason/EnvelopePolygonProblem.cs
In WPF its common to want to ignore Observables
public class TypeOnlyContractResolver<T> : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = instance =>
{
return !property.DeclaringType.AssemblyQualifiedName.Contains("Observable");
};
property.ShouldDeserialize = instance =>
{
return !property.DeclaringType.AssemblyQualifiedName.Contains("Observable");
};
return property;
}
}
This will ignore anything with the base class ObservableObject etc.
I need to be able to control how/whether certain properties on a class are serialized. The simplest case is [ScriptIgnore]. However, I only want these attributes to be honored for this one specific serialization situation I am working on - if other modules downstream in the application also want to serialize these objects, none of these attributes should get in the way.
So my thought is to use a custom attribute MyAttribute on the properties, and initialize the specific instance of JsonSerializer with a hook that knows to look for that attribute.
At first glance, I don't see any of the available hook points in JSON.NET will provide the PropertyInfo for the current property to do such an inspection - only the property's value. Am I missing something? Or a better way to approach this?
Here's a generic reusable "ignore property" resolver based on the accepted answer:
/// <summary>
/// Special JsonConvert resolver that allows you to ignore properties. See https://stackoverflow.com/a/13588192/1037948
/// </summary>
public class IgnorableSerializerContractResolver : DefaultContractResolver {
protected readonly Dictionary<Type, HashSet<string>> Ignores;
public IgnorableSerializerContractResolver() {
this.Ignores = new Dictionary<Type, HashSet<string>>();
}
/// <summary>
/// Explicitly ignore the given property(s) for the given type
/// </summary>
/// <param name="type"></param>
/// <param name="propertyName">one or more properties to ignore. Leave empty to ignore the type entirely.</param>
public void Ignore(Type type, params string[] propertyName) {
// start bucket if DNE
if (!this.Ignores.ContainsKey(type)) this.Ignores[type] = new HashSet<string>();
foreach (var prop in propertyName) {
this.Ignores[type].Add(prop);
}
}
/// <summary>
/// Is the given property for the given type ignored?
/// </summary>
/// <param name="type"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
public bool IsIgnored(Type type, string propertyName) {
if (!this.Ignores.ContainsKey(type)) return false;
// if no properties provided, ignore the type entirely
if (this.Ignores[type].Count == 0) return true;
return this.Ignores[type].Contains(propertyName);
}
/// <summary>
/// The decision logic goes here
/// </summary>
/// <param name="member"></param>
/// <param name="memberSerialization"></param>
/// <returns></returns>
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (this.IsIgnored(property.DeclaringType, property.PropertyName)
// need to check basetype as well for EF -- #per comment by user576838
|| this.IsIgnored(property.DeclaringType.BaseType, property.PropertyName)) {
property.ShouldSerialize = instance => { return false; };
}
return property;
}
}
And usage:
var jsonResolver = new IgnorableSerializerContractResolver();
// ignore single property
jsonResolver.Ignore(typeof(Company), "WebSites");
// ignore single datatype
jsonResolver.Ignore(typeof(System.Data.Objects.DataClasses.EntityObject));
var jsonSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ContractResolver = jsonResolver };
Use the JsonIgnore attribute.
For example, to exclude Id:
public class Person {
[JsonIgnore]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
You have a few options. I recommend you read the Json.Net documentation article on the subject before reading below.
The article presents two methods:
Create a method that returns a bool value based on a naming convention that Json.Net will follow to determine whether or not to serialize the property.
Create a custom contract resolver that ignores the property.
Of the two, I favor the latter. Skip attributes altogether -- only use them to ignore properties across all forms of serialization. Instead, create a custom contract resolver that ignores the property in question, and only use the contract resolver when you want to ignore the property, leaving other users of the class free to serialize the property or not at their own whim.
Edit To avoid link rot, I'm posting the code in question from the article
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 =>
{
// replace this logic with your own, probably just
// return false;
Employee e = (Employee)instance;
return e.Manager != e;
};
}
return property;
}
}
Here is a method based on drzaus' excellent serializer contract which uses lambda expressions. Simply add it to the same class. After all, who doesn't prefer the compiler to do the checking for them?
public IgnorableSerializerContractResolver Ignore<TModel>(Expression<Func<TModel, object>> selector)
{
MemberExpression body = selector.Body as MemberExpression;
if (body == null)
{
UnaryExpression ubody = (UnaryExpression)selector.Body;
body = ubody.Operand as MemberExpression;
if (body == null)
{
throw new ArgumentException("Could not get property name", "selector");
}
}
string propertyName = body.Member.Name;
this.Ignore(typeof (TModel), propertyName);
return this;
}
You can now ignore properties easily and fluently:
contract.Ignore<Node>(node => node.NextNode)
.Ignore<Node>(node => node.AvailableNodes);
I don't care to set the property names as strings, in case they ever change it would break my other code.
I had several "view modes" on the objects I needed to serialized, so I ended up doing something like this in the contract resolver (view mode provided by constructor argument):
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (viewMode == ViewModeEnum.UnregisteredCustomer && member.GetCustomAttributes(typeof(UnregisteredCustomerAttribute), true).Length == 0)
{
property.ShouldSerialize = instance => { return false; };
}
return property;
}
Where my objects look like this:
public interface IStatement
{
[UnregisteredCustomer]
string PolicyNumber { get; set; }
string PlanCode { get; set; }
PlanStatus PlanStatus { get; set; }
[UnregisteredCustomer]
decimal TotalAmount { get; }
[UnregisteredCustomer]
ICollection<IBalance> Balances { get; }
void SetBalances(IBalance[] balances);
}
The downside to this would be the bit of reflection in the resolver, but I think it's worth it to have more maintainable code.
I had good results with the combination of both drzaus and Steve Rukuts answers. However, I face a problem when I set JsonPropertyAttribute with a different name or caps for the property. For example:
[JsonProperty("username")]
public string Username { get; set; }
Include UnderlyingName into consideration solves the problem:
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (this.IsIgnored(property.DeclaringType, property.PropertyName)
|| this.IsIgnored(property.DeclaringType, property.UnderlyingName)
|| this.IsIgnored(property.DeclaringType.BaseType, property.PropertyName)
|| this.IsIgnored(property.DeclaringType.BaseType, property.UnderlyingName))
{
property.ShouldSerialize = instance => { return false; };
}
return property;
}
If you are willing to use F# (or simply use an API not optimized for C#), the FSharp.JsonSkippable library allows you to control in a simple and strongly typed manner whether to include a given property when serializing (and determine whether a property was included when deserializing), and moreover, to control/determine exclusion separately of nullability. (Full disclosure: I'm the author of the library.)