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?
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; }
}
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; }
}
Pour DotnetCore3.1, nous pouvons utiliser
forfait classe publique
{
[JsonProperty("carrier")]
public string Carrier { get; set; }
[JsonProperty("trackingNumber")]
public string TrackingNumber { get; set; }
}
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"
}
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"