从类中获取要在查询字符串中使用的JSON属性名称列表

Cos*_*cho 13 c# json json.net .net-3.5 query-string

如果我有一个CSON模型类,JSON.net使用它来绑定序列化JSON字符串中的数据,有没有办法可以从该类创建一个查询字符串以便发出初始请求?

模型类示例:

public class model
{
   [JsonProperty(PropertyName = "id")]
   public long ID { get; set; }
   [JsonProperty(PropertyName = "some_string")]
   public string SomeString {get; set;} 
}
Run Code Online (Sandbox Code Playgroud)

查询字符串示例:

baseUrl + uri + "&fields=id,some_string" + token
Run Code Online (Sandbox Code Playgroud)

所以我想要做的就是从模型对象中收集"id"和"some_string",这样我就可以动态地创建一个"&fields"参数.谢谢!

Bri*_*ers 23

@Leigh Shepperson有正确的想法; 但是,使用LINQ可以用更少的代码完成.我会创建一个这样的辅助方法:

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));
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

var fields = "&fields=" + GetFields(typeof(model));
Run Code Online (Sandbox Code Playgroud)

编辑

如果您在.Net Framework的3.5版本下运行,使得您没有GetCustomAttribute<T>可用的通用方法,则可以使用非泛型GetCustomAttributes()方法执行相同的操作,并使用SelectManyCast<T>:

    return string.Join(",",
        modelType.GetProperties()
                 .SelectMany(p => p.GetCustomAttributes(typeof(JsonPropertyAttribute))
                                   .Cast<JsonPropertyAttribute>())
                 .Select(jp => jp.PropertyName)
                 .ToArray());
Run Code Online (Sandbox Code Playgroud)


dbc*_*dbc 7

如果模型仅部分使用[JsonProperty(PropertyName = "XXX")]属性进行注释,或者使用数据契约属性进行注释,或者忽略了属性,您可以使用 Json.NET 自己的契约解析器来获取序列化的属性名称列表。首先介绍如下扩展方法:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后做:

// Allocate the relevant contract resolver. 
// Options are CamelCasePropertyNamesContractResolver() or DefaultContractResolver().
IContractResolver resolver = new DefaultContractResolver(); 

// Get properties
var propertyNames = resolver.PropertyNames(typeof(model));
var fields = "&fields=" + String.Join(",", propertyNames);
Run Code Online (Sandbox Code Playgroud)

对于resolver使用CamelCasePropertyNamesContractResolver,如果你是camel大小写的属性名(其中ASP.NET核心Web API的功能,在默认情况下); 否则使用DefaultContractResolver.

样品小提琴


Lei*_*son 6

你可以使用反射来做到这一点.这是一般的想法:

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;
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)