Search code examples
c#json.netsystem.reflection

How to get Json Property name using reflection in C#


I have a class as mentioned below:

public class Employee {

    [JsonProperty("emp_id")]
    public int Id {get; set;}

    [JsonProperty("emp_fname")]
    public string Name {get;set;}

    [JsonProperty("emp_lname")]
    public string LastName {get;set;} 
}

In the above class, I have assigned Newtonsoft Attribute for serialization.

I have a object of class Employee and Now I would like to find the property by JsonProperty and get value of that property.

For example, I would like to get the value of the property for which JsonProprty attribute name is set to emp_lname

Is there a way to find value like this using reflection?


Solution

  • You can use Json.NET's own contract resolver for this purpose. Doing so will correctly handle properties with, and without, [JsonProperty(string name)] attributes added, as well as objects with naming strategies or data contract attributes applied directly.

    First add the following method:

    public static partial class JsonExtensions
    {
        static readonly IContractResolver defaultResolver = JsonSerializer.CreateDefault().ContractResolver;
    
        public static object GetJsonProperty<T>(T obj, string jsonName, bool exact = false, IContractResolver resolver = null)
        {
            if (obj == null)
                throw new ArgumentNullException(nameof(obj));
            resolver = resolver ?? defaultResolver;
            var contract = resolver.ResolveContract(obj.GetType()) as JsonObjectContract;
            if (contract == null)
                throw new ArgumentException(string.Format("{0} is not serialized as a JSON object", obj));
            var property = contract.Properties.GetProperty(jsonName, exact ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
            if (property == null)
                throw new ArgumentException(string.Format("Property {0} was not found.", jsonName));
            return property.ValueProvider.GetValue(obj); // Maybe check JsonProperty.Readable first, and throw an exception if not?
        }
    }
    

    And now you can do:

    var employee = new Employee
    {
        LastName = "last name",
    };
    
    Console.WriteLine("Value of {0} is {1}.", "emp_lname", 
                      JsonExtensions.GetJsonProperty(employee, "emp_lname")); // Prints Value of emp_lname is last name.
    

    If your app uses camel casing for JSON serialization by default, you can pass a CamelCasePropertyNamesContractResolver in for resolver like so:

    Console.WriteLine("Value of {0} is {1}.", "emp_lname", 
                      JsonExtensions.GetJsonProperty(employee, "emp_lname", resolver : new CamelCasePropertyNamesContractResolver())); 
    

    If you need to get a list of all JSON property names for a given type, see Get a list of JSON property names from a class to use in a query string:

    public static partial class JsonExtensions
    {
        public static string [] PropertyNames(Type type)
        {
            return PropertyNames(defaultResolver, type);
        }
    
        //Taken from this answer https://stackoverflow.com/a/45829514/3744182
        //To https://stackoverflow.com/questions/33616005/get-a-list-of-json-property-names-from-a-class-to-use-in-a-query-string
        public static string [] PropertyNames(this IContractResolver resolver, Type type)
        {
            if (resolver == null || type == null)
                throw new ArgumentNullException();
            var contract = resolver.ResolveContract(type) as JsonObjectContract;
            if (contract == null)
                return new string[0];
            return contract.Properties.Where(p => !p.Ignored).Select(p => p.PropertyName).ToArray();
        }
    }
    

    Demo fiddle here.