Json.NET different property names resolving

Hi, boys and girls. Short post about how I resolved little local issue. Maybe someday someone might find this useful.

I’m developing library for 3rd party API for now. Format in which I’m receiving data is json. Trouble was with API answer’s formatting. API returns something like this:

{
    "server_time": "1459218903",
    "auth_user": {...},
    "some_entity_name": {some_entity_data}
}

where some_entity_name could be different for different API methods(“user”, “team” etc). But I wanted to map this field into single property within my generic:

    public class Answer<TEntity> where TEntity : class, IEntity
    {
        [JsonProperty("server_time")]
        public long ServerTime { get; set; }

        [JsonProperty("auth_user")]
        public Object AuthUser { get; set; }

        [JsonProperty("error")]
        public Error Error { get; set; }

        public TEntity Entity { get; set; } // <-- here
    }

Ofc JsonProperty attribute is useless for this case. So after some research I found pretty solution for that situation. I implemented custom ContractResolver and one attribute. So my class implementation for generic parameter becomes:

    [Attributes.JsonPropertyMap("user")]
    public class User : IEntity
    {

Attribute code(nothing special):

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class JsonPropertyMapAttribute : Attribute
    {
        public JsonPropertyMapAttribute(String mapToName)
        {
            MapToName = mapToName;
        }

        public String MapToName { get; set; }
    }

And that’s resolver code:

using ApiLibrary.ApiEntities.Attributes;
using Newtonsoft.Json.Serialization;
using System;
using System.Reflection;

namespace ApiLibrary.ApiEntities.Base
{
    public class EntityContractResolver<TEntity>: DefaultContractResolver where TEntity : class
    {
        protected override string ResolvePropertyName(string propertyName)
        {
            if (propertyName == nameof(Answer.Entity))
            {
                Type entityType = typeof(TEntity);
                var jsonMapAttribute = entityType.GetTypeInfo().GetCustomAttribute<JsonPropertyMapAttribute>();
                if (!String.IsNullOrWhiteSpace(jsonMapAttribute?.MapToName))
                {
                    return jsonMapAttribute.MapToName;
                }
                else
                {
                    return entityType.Name.ToLowerInvariant();
                }
            }
            return base.ResolvePropertyName(propertyName);
        }
    }
}

Note: as I’m developing portable library(PCL) with C#6 you may notice little changed reflection call with entityType.GetTypeInfo()
Now for deserializing I call:

    JsonSerializerSettings settings = new JsonSerializerSettings()
    {
        ContractResolver = new ApiEntities.Base.EntityContractResolver<User>()
    };
    var deserialized = JsonConvert.DeserializeObject<ApiEntities.Base.Answer<User>>(jsonAnswer, settings);

That’s all. If you know how this could be implemented easier, then leave your thoughts in comments please.

Advertisements

Share your thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s