web-dev-qa-db-fra.com

Obtention d'une liste de noms de propriétés JSON d'une classe à utiliser dans une chaîne de requête

Si j'ai une classe de modèle C # qui est utilisée par JSON.net pour lier des données à partir d'une chaîne JSON sérialisée, existe-t-il un moyen de créer une chaîne de requête à partir de cette classe afin de faire la demande initiale?

Exemple de classe de modèle:

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

Exemple de chaîne de requête:

baseUrl + uri + "&fields=id,some_string" + token

Donc l'essentiel de ce que j'essaie de faire est de rassembler à la fois "id" et "some_string" à partir de l'objet modèle afin que je puisse créer dynamiquement les arguments "& fields". Merci!

15
CostelloNicho

@Leigh Shepperson a la bonne idée; cependant, vous pouvez le faire avec moins de code en utilisant LINQ. Je créerais une méthode d'aide comme celle-ci:

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));
}

Vous pouvez l'utiliser comme ceci:

var fields = "&fields=" + GetFields(typeof(model));

MODIFIER

Si vous utilisez la version 3.5 du .Net Framework de manière à ne pas disposer de la méthode générique GetCustomAttribute<T>, Vous pouvez faire la même chose avec la méthode non générique GetCustomAttributes() à la place, en l'utilisant avec SelectMany et Cast<T>:

    return string.Join(",",
        modelType.GetProperties()
                 .SelectMany(p => p.GetCustomAttributes(typeof(JsonPropertyAttribute))
                                   .Cast<JsonPropertyAttribute>())
                 .Select(jp => jp.PropertyName)
                 .ToArray());
22
Brian Rogers

Vous pouvez le faire en utilisant la réflexion. C'est l'idée générale:

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;
                }
            }
        }
    }
}
6
Leigh Shepperson

Dans les cas où le modèle n'est que partiellement annoté avec des attributs [JsonProperty(PropertyName = "XXX")], ou est annoté avec attributs de contrat de données , ou a ignoré propriétés, vous pouvez utiliser Json Propre .NET résolveur de contrat pour obtenir la liste des noms de propriété sérialisés. Tout d'abord, introduisez la méthode d'extension suivante:

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();
    }
}

Alors fais:

// 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);

Pour resolver utilisez CamelCasePropertyNamesContractResolver si vous mettez des chameaux dans les noms de vos propriétés (ce que fait l'API Web ASP.NET Core par défaut ); sinon utilisez DefaultContractResolver .

Exemple violon .

4
dbc

Une petite variante de la solution @Brian Rogers qui résout le problème des exceptions nulles:

IEnumerable<string> props = typeof(T).GetProperties()
                                     .Select(p => p.GetCustomAttribute<JsonPropertyAttribute>())
                                     .Where(jp => jp != null)
                                     .Select(jp => jp.PropertyName);

string propsList = string.Join(',', props);
0
Rafael Jiménez