web-dev-qa-db-fra.com

Spécification d'un nom de propriété personnalisé lors de la liaison d'un objet au point de terminaison de l'API Web

J'ai une API Web .Net Core. Il mappe automatiquement les modèles lorsque les propriétés du modèle correspondent au corps de la demande. Par exemple, si vous avez cette classe:

public class Package
{
    public string Carrier { get; set; }
    public string TrackingNumber { get; set; }
}

Il le lierait correctement à un point de terminaison POST si le corps de la demande est le JSON suivant:

{
    carrier: "fedex",
    trackingNumber: "123123123"
}

Ce que je dois faire, c'est spécifier une propriété personnalisée à mapper. Par exemple, en utilisant la même classe ci-dessus, j'ai besoin de pouvoir mapper vers JSON si le TrackingNumber arrive en tant que tracking_number.

Comment je fais ça?

22
im1dermike

Modifiez votre classe de package et ajoutez une décoration JsonProperty pour chaque champ que vous souhaitez mapper à un champ json différent.

public class Package
{
    [JsonProperty(PropertyName = "carrier")]
    public string Carrier { get; set; }

    [JsonProperty(PropertyName = "trackingNumber")]
    public string TrackingNumber { get; set; }
}
18
TejSoft

Je pense que cela devrait aussi fonctionner:

using Microsoft.AspNetCore.Mvc;
public class Package
{
     [BindProperty(Name ="carrier")]
     public string Carrier { get; set; }

     [BindProperty(Name ="trackingNumber")]
     public string TrackingNumber { get; set; }
}
7
Milos

Pour DotnetCore3.1, nous pouvons utiliser

forfait classe publique

{

[JsonProperty("carrier")]
public string Carrier { get; set; }

[JsonProperty("trackingNumber")]
public string TrackingNumber { get; set; }

}

0
Amit Saxena

Dans mon cas, je ne souhaite pas modifier le nom de la propriété Carrier & TrackingNumber

donc j'ajoute juste new JsonSerializerSettings() sur la réponse JsonResult

public JsonResult GetJQXGridData(){
    var Data = .......
    return Json(Data, new JsonSerializerSettings()) //change here
}

Sans utiliser JsonSerializerSettings Sortie

{
    carrier: "fedex",
    trackingNumber: "123123123"
}

En utilisant JsonSerializerSettings Sortie

{
    Carrier: "fedex",
    TrackingNumber: "123123123"
}
0
Ravi Makwana

En utilisant un convertisseur personnalisé, vous pourrez obtenir ce dont vous avez besoin.
La suite de composants suivante, basée sur des attributs, peut convenir à vos besoins et est assez générique au cas où vous souhaiteriez l'étendre.

classe d'attribut de base

Définit le IsMatch qui vous permet de définir si la propriété d'objet correspond à la propriété json.

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public abstract class JsonDeserializationPropertyMatchAttribute : Attribute
{
    protected JsonDeserializationPropertyMatchAttribute() { }

    public abstract bool IsMatch(JProperty jsonProperty);
}

exemple d'implémentation: noms de désérialisation multiple

Définit un attribut qui vous permet d'avoir plusieurs noms associés à une propriété. L'implémentation IsMatch les parcourt simplement et essaie de trouver une correspondance.

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public class JsonDeserializationNameAttribute : JsonDeserializationPropertyNameMatchAttribute
{
    public string[] PropertyNames { get; private set; }

    public JsonDeserializationNameAttribute(params string[] propertyNames)
    {
        this.PropertyNames = propertyNames;
    }

    public override bool IsMatch(JProperty jsonProperty)
    {
        return PropertyNames.Any(x => String.Equals(x, jsonProperty.Name, StringComparison.InvariantCultureIgnoreCase));
    }
}

The Converter afin de lier les deux attributs à la désérialisation json, le convertisseur suivant est requis:

public class JsonDeserializationPropertyMatchConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsClass;
    }

    public override bool CanWrite
    {
        get
        {
            return false;
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var constructor = objectType.GetConstructor(new Type[0]);
        if (constructor == null)
            throw new JsonSerializationException("A parameterless constructor is expected.");

        var value = constructor.Invoke(null);

        var jsonObject = JObject.Load(reader);
        var jsonObjectProperties = jsonObject.Properties();

        PropertyInfo[] typeProperties = objectType.GetProperties();
        var typePropertyTuples = new List<Tuple<PropertyInfo, Func<JProperty, bool>>>();
        foreach (var property in typeProperties.Where(x => x.CanWrite))
        {
            var attribute = property.GetCustomAttribute<JsonDeserializationPropertyMatchAttribute>(true);
            if (attribute != null)
                typePropertyTuples.Add(new Tuple<PropertyInfo, Func<JProperty, bool>>(property, attribute.IsMatch));
            else
                typePropertyTuples.Add(new Tuple<PropertyInfo, Func<JProperty, bool>>(property, (x) => false));
        }

        foreach (JProperty jsonProperty in jsonObject.Properties())
        {
            var propertyTuple = typePropertyTuples.FirstOrDefault(x => String.Equals(jsonProperty.Name, x.Item1.Name, StringComparison.InvariantCultureIgnoreCase) || x.Item2(jsonProperty));
            if (propertyTuple != null)
                propertyTuple.Item1.SetValue(value, jsonProperty.Value.ToObject(propertyTuple.Item1.PropertyType, serializer));
        }

        return value;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

exemple en utilisant les codes collés ci-dessus, et en décorant la classe comme suit, j'ai réussi à désérialiser correctement les objets:

[JsonConverter(typeof(JsonDeserializationPropertyMatchConverter))]
public class Package
{
    public string Carrier { get; set; }

    [JsonDeserializationName("Tracking_Number","anotherName")]
    public string TrackingNumber { get; set; }
}

Sortie 1

var input = "{ carrier: \"fedex\", trackingNumber: \"123123123\" }";
var output = JsonConvert.DeserializeObject<Package>(input); // output.TrackingNumber is "123123123"

Sortie 2

var input = "{ carrier: \"fedex\", tracking_Number: \"123123123\" }";
var output = JsonConvert.DeserializeObject<Package>(input); // output.TrackingNumber is "123123123"

Sortie

var input = "{ carrier: \"fedex\", anotherName: \"123123123\" }";
var output = JsonConvert.DeserializeObject<Package>(input); // output.TrackingNumber is "123123123"
0
StfBln