【问题标题】:Deserialize nested ICollection<BaseType> in Asp.Net Web API 2 controller在 Asp.Net Web API 2 控制器中反序列化嵌套的 ICollection<BaseType>
【发布时间】:2016-03-28 16:36:24
【问题描述】:

我有一个像这样的 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&lt;SaleDTO&gt;IEnumerable&lt;OrderDTO&gt;

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

提前感谢您的帮助。

【问题讨论】:

    标签: c# json asp.net-mvc json.net asp.net-web-api2


    【解决方案1】:

    您可以在 PaymentDTO 类上使用 custom 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; }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-04
      • 2012-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-24
      相关资源
      最近更新 更多