繁体   English   中英

反序列化嵌套的ICollection <BaseType> 在Asp.Net Web API 2控制器中

[英]Deserialize nested ICollection<BaseType> in Asp.Net Web API 2 controller

我有一个像这样的Web Api控制器:

public IHttpActionResult Create(PaymentDTO Payment)

我的DTO是:

public class PaymentDTO
{
    public int Id { get; set; }

    public string type { get; set; }

    public IEnumerable<TransactionDTO> Transactions { get; set; }

}

public class TransactionDTO
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public string CreateTime { get; set; }
        public string UpdateTime { get; set; }
    }

public class SaleDTO : TransactionDTO
{
        public string Total { get; set; }
        public string Currency{ get; set; }
}

public class OrderDTO : TransactionDTO
{
       public string State {get;set;}
}

我收到以下JSON格式的数据:

 { "Type": "sale", "Id": 101, "transactions": [ { "Total": "30.50", "Currency": "USD", "Description": "transaction description" } ] } 

我希望JSON.net根据Type属性实例化IEnumerable<SaleDTO>IEnumerable<OrderDTO>

我可以使用自定义类型转换器,但前提是Type属性位于TransactionDTO 但我希望Type属性位于父对象( PaymentDTO )中

预先感谢您的帮助。

您可以使用PaymentDTO类上的自定义JsonConverter来做到这一点:

public class PaymentDTOConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(PaymentDTO).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var obj = JObject.Load(reader);
        var payment = (PaymentDTO)existingValue ?? new PaymentDTO();

        // Extract the transactions.
        var transactions = obj.Property("transactions") ?? obj.Property("Transactions");
        if (transactions != null)
            transactions.Remove();

        // Populate the remaining regular properties.
        using (var subReader = obj.CreateReader())
            serializer.Populate(subReader, payment);

        if (transactions != null)
        {
            // Deserialize the transactions list.
            var type = PaymentDTO.GetTransactionDTOType(payment.type) ?? typeof(TransactionDTO);
            using (var subReader = transactions.Value.CreateReader())
                // Here we are taking advantage of array covariance.
                payment.Transactions = (IEnumerable<TransactionDTO>)serializer.Deserialize(subReader, type.MakeArrayType());
        }

        return payment;
    }

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

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

然后将其应用于您的PaymentDTO类,如下所示:

[JsonConverter(typeof(PaymentDTOConverter))]
public class PaymentDTO
{
    static Dictionary<string, Type> namesToTransactions;
    static Dictionary<Type, string> transactionsToNames = new Dictionary<Type, string>
    {
        { typeof(SaleDTO), "sale" },
        { typeof(OrderDTO), "order" },
    };

    static PaymentDTO()
    {
        namesToTransactions = transactionsToNames.ToDictionary(p => p.Value, p => p.Key);
    }

    public static string GetTransactionDTOTypeName<TTransactionDTO>() where TTransactionDTO : TransactionDTO
    {
        string name;
        if (transactionsToNames.TryGetValue(typeof(TTransactionDTO), out name))
            return name;
        return null;
    }

    public static Type GetTransactionDTOType(string name)
    {
        Type type;
        if (namesToTransactions.TryGetValue(name, out type))
            return type;
        return null;
    }

    public int Id { get; set; }

    public string type { get; set; }

    [JsonProperty("transactions")]
    public IEnumerable<TransactionDTO> Transactions { get; set; }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM