Skip to content

Instantly share code, notes, and snippets.

@trbngr
Created August 26, 2012 09:54
Show Gist options
  • Select an option

  • Save trbngr/3476723 to your computer and use it in GitHub Desktop.

Select an option

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

trbngr commented Aug 26, 2012

Copy link
Copy Markdown
Author

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

trbngr commented Aug 26, 2012

Copy link
Copy Markdown
Author

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

@trbngr

trbngr commented Aug 26, 2012

Copy link
Copy Markdown
Author

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

@trbngr

trbngr commented Aug 26, 2012

Copy link
Copy Markdown
Author

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

@trbngr

trbngr commented Aug 26, 2012

Copy link
Copy Markdown
Author

Ditched the ApiResourceAttribute.

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