Skip to content

Instantly share code, notes, and snippets.

@trbngr
Created August 26, 2012 09:54
Show Gist options
  • Save trbngr/3476723 to your computer and use it in GitHub Desktop.
Save trbngr/3476723 to your computer and use it in GitHub Desktop.
Demonstrating how to skip fields that aren't decorated with a certain attribute using json.net.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using GuessWho;
using NUnit.Framework;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
namespace ConsoleApplication1
{
[TestFixture]
public class ApiResourceSerializationTests
{
#region Setup/Teardown
[SetUp]
public void Setup()
{
var generator = new NameGenerator();
GeneratedName name = generator.NextName();
_person = new Person
{
Id = Guid.NewGuid(),
FirstName = name.GivenName,
LastName = name.Surname
};
for (int i = 0; i < 2; i++)
{
name = generator.NextName();
_person.Contacts.Add(new Contact
{
Id = Guid.NewGuid(),
FirstName = name.GivenName,
LastName = name.Surname
});
}
_serializerSettings = new JsonSerializerSettings {ContractResolver = new MyContractResolver()};
}
#endregion
private Person _person;
private JsonSerializerSettings _serializerSettings;
[Test]
public void will_only_serialize_api_resource_properties()
{
string json = JsonConvert.SerializeObject(_person, Formatting.Indented, _serializerSettings);
JObject obj = JObject.Parse(json);
Console.Out.WriteLine(json);
Assert.That(obj["Id"], Is.Null);
Assert.That(obj["first_name"], Is.Not.Null.And.InstanceOf<JValue>());
Assert.That(obj["LastName"], Is.Not.Null.And.InstanceOf<JValue>());
JToken contacts = obj["Contacts"];
Assert.That(contacts, Is.Not.Null.And.InstanceOf<JArray>());
var array = (JArray) contacts;
Assert.That(array[0]["Id"], Is.Null);
Assert.That(array[0]["FirstName"], Is.Not.Null.And.InstanceOf<JValue>());
Assert.That(array[0]["LastName"], Is.Not.Null.And.InstanceOf<JValue>());
Assert.That(array[1]["Id"], Is.Null);
Assert.That(array[1]["FirstName"], Is.Not.Null.And.InstanceOf<JValue>());
Assert.That(array[1]["LastName"], Is.Not.Null.And.InstanceOf<JValue>());
}
}
public class MyContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
var attribute = member.GetCustomAttribute<ApiResourcePropertyAttribute>();
if (string.IsNullOrWhiteSpace(attribute.Name))
return property;
property.PropertyName = attribute.Name;
return property;
}
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
var members = base.GetSerializableMembers(objectType);
return members.Where(p => p.GetCustomAttributes<ApiResourcePropertyAttribute>(false).Any()).ToList();
}
}
[DataContract]
public class Person
{
public Person()
{
Contacts = new List<Contact>();
}
[DataMember]
public Guid Id { get; set; }
[DataMember, ApiResourceProperty(Name = "first_name")]
public string FirstName { get; set; }
[DataMember, ApiResourceProperty]
public string LastName { get; set; }
[DataMember, ApiResourceProperty]
public List<Contact> Contacts { get; set; }
}
[DataContract]
public class Contact
{
[DataMember]
public Guid Id { get; set; }
[DataMember, ApiResourceProperty]
public string FirstName { get; set; }
[DataMember, ApiResourceProperty]
public string LastName { get; set; }
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class ApiResourcePropertyAttribute : Attribute
{
public string Name { get; set; }
}
}
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="GuessWho.Top1000" version="1.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="4.5.8" targetFramework="net45" />
<package id="NUnit" version="2.6.1" targetFramework="net45" />
</packages>
@trbngr
Copy link
Author

trbngr commented Aug 26, 2012

Only serializes properties decorated with ApiResourcePropertyAttribute in objects decorated with ApiResourceAttribute. You can also control the output property name with the Name property of ApiResourcePropertyAttribute.

This allows separate serialization formats for our API and our internal application; while using the same model classes. Yay!

@trbngr
Copy link
Author

trbngr commented Aug 26, 2012

Of course, this only works with JSON for now. If we decide to support XML formatting, I'll worry about that then.

@trbngr
Copy link
Author

trbngr commented Aug 26, 2012

Switched to a ContractResolver. With the exception of the reflection hack in MyContractResolver.SelectName, it's much cleaner than the JsonConverter version

@trbngr
Copy link
Author

trbngr commented Aug 26, 2012

Discovered a new overload and got rid of the reflection hack. :)

@trbngr
Copy link
Author

trbngr commented Aug 26, 2012

Ditched the ApiResourceAttribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment