web-dev-qa-db-ja.com

オブジェクトをWeb APIエンドポイントにバインドするときにカスタムプロパティ名を指定する

.Net Core Web APIを持っています。モデルプロパティがリクエストの本文と一致すると、モデルが自動的にマッピングされます。たとえば、次のクラスがあるとします。

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

これは、POSTエンドポイントにリクエストボディが次のJSONである場合に正しくバインドします。

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

マッピングするカスタムプロパティを指定する必要があります。たとえば、上記と同じクラスを使用して、TrackingNumberがtracking_numberとして入ってくる場合は、JSONにマップできる必要があります。

それ、どうやったら出来るの?

22
im1dermike

パッケージクラスを変更し、別のjsonフィールドにマップするフィールドごとにJsonProperty装飾を追加します。

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

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

これもうまくいくと思います:

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

DotnetCore3.1の場合

パブリッククラスパッケージ

{

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

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

}

0
Amit Saxena

私の場合、プロパティ名を変更したくないCarrierTrackingNumber

jsonResultレスポンスにnew JsonSerializerSettings()を追加するだけです

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

JsonSerializerSettings出力を使用しない場合

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

JsonSerializerSettings出力を使用して

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

カスタムコンバーターを使用すると、必要なものを実現できます。
属性に基づく次の一連のコンポーネントはニーズに合う可能性があり、拡張したい場合のための非常に一般的なものです。

基本属性クラス

オブジェクトプロパティがjsonプロパティと一致するかどうかを定義できるIsMatchを定義します。

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

    public abstract bool IsMatch(JProperty jsonProperty);
}

サンプル実装:複数の逆シリアル化名

プロパティに複数の名前を関連付けることができる属性を定義します。 IsMatch実装は単にそれらをループして、一致を見つけようとします。

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

コンバータ両方の属性をjson逆シリアル化にバインドするには、次のコンバータが必要です。

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

Sample上に貼り付けたコードを使用して、次のようにクラスを装飾することで、オブジェクトを適切に逆シリアル化することができました。

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

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

出力1

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

出力2

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

出力

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