Get a list of JSON property names from a class to use in a query string
@Leigh Shepperson has the right idea; however, you can do it with less code using LINQ. I would create a helper method like this:
using System.Linq;using System.Reflection;using Newtonsoft.Json;...public static string GetFields(Type modelType){ return string.Join(",", modelType.GetProperties() .Select(p => p.GetCustomAttribute<JsonPropertyAttribute>()) .Select(jp => jp.PropertyName));}
You can use it like this:
var fields = "&fields=" + GetFields(typeof(model));
EDIT
If you're running under the 3.5 version of the .Net Framework such that you don't have the generic GetCustomAttribute<T>
method available to you, you can do the same thing with the non-generic GetCustomAttributes()
method instead, using it with SelectMany
and Cast<T>
:
return string.Join(",", modelType.GetProperties() .SelectMany(p => p.GetCustomAttributes(typeof(JsonPropertyAttribute)) .Cast<JsonPropertyAttribute>()) .Select(jp => jp.PropertyName) .ToArray());
You can do this using reflection. This is the general idea:
using Newtonsoft.Json;using Newtonsoft.Json.Serialization;using System.Reflection;namespace ConsoleApplication8{ public class model { [JsonProperty(PropertyName = "id")] public long ID { get; set; } [JsonProperty(PropertyName = "some_string")] public string SomeString { get; set; } } internal class Program { private static void Main(string[] args) { var model = new model(); var result = string.Empty; PropertyInfo[] props = typeof(model).GetProperties(); foreach (PropertyInfo prop in props) { foreach (object attr in prop.GetCustomAttributes(true)) { result += (attr as JsonPropertyAttribute).PropertyName; } } } }}
In cases where the model is only partially annotated with [JsonProperty(PropertyName = "XXX")]
attributes, or is annotated with data contract attributes, or has ignored properties, you can use Json.NET's own contract resolver to obtain the list of serialized property names. First, introduce the following extension method:
public static class JsonExtensions{ 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(); }}
Then, do:
// Allocate the relevant contract resolver. // Options are CamelCasePropertyNamesContractResolver() or DefaultContractResolver().IContractResolver resolver = new DefaultContractResolver(); // Get propertiesvar propertyNames = resolver.PropertyNames(typeof(model));var fields = "&fields=" + String.Join(",", propertyNames);
For resolver
use CamelCasePropertyNamesContractResolver
if you are camel casing your property names (which ASP.NET Core Web API does by default); otherwise use DefaultContractResolver
.
Sample fiddle.