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

时间:2016-03-28 16:36:24

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

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

public void pan(float x, float y) {
    Vector3 current = new Vector3(camera.position);
    camera.translate(-x, y);
    camera.update(true);
    if (camera.frustum.boundsInFrustum(world.boundLeft) || camera.frustum.boundsInFrustum(world.boundRight)) {
        camera.position.x = current.x; // Broke bounds on x axis, set camera back to old x
        camera.update();
    }
    if (camera.frustum.boundsInFrustum(world.boundLow) || camera.frustum.boundsInFrustum(world.boundUp)) {
        camera.position.y = current.y; // Broke bounds on y axis, set camera back to old y
        camera.update();
    }
    game.batch.setProjectionMatrix(camera.combined);
}

我的DTO是:

public IHttpActionResult Create(PaymentDTO Payment)

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

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.net基于{ "Type": "sale", "Id": 101, "transactions": [ { "Total": "30.50", "Currency": "USD", "Description": "transaction description" } ] } 属性实例化IEnumerable<SaleDTO>IEnumerable<OrderDTO>

我可以使用自定义类型转换器,但仅当Type属性位于Type时。但我希望TransactionDTO属性位于父对象(Type

提前感谢您的帮助。

1 个答案:

答案 0 :(得分: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; }
}