0

First of all, I'm a hobby coder so the longer and more detailed your answer, the faster I will understand. Thanks in advance for your patience.

The project I'm working on is building a client-side class to talk with the REST API of BitMEX (https://testnet.bitmex.com/api/explorer/#/Order).

I tried to generate the c# code from the swagger specifications found on the BitMEX website but I was not successful in getting it to work, even after getting out some bugs. Unfortunately I don't find a lot of documentation about the code that it generates, but that's another discussion. :)

I'm having a situation here where one class should deserialize a JSON call that can have 3 kind of results. I could either have an array of OrderResponse, a single OrderResponse or an OrderError. What is the best way to handle this situation and what is the best place to do all the conversions?

The class for Orders that I have so far, looks like this:

    namespace BitMEX.JSONClass.Order
    {
        public partial class OrderError
        {
            [JsonProperty("error")]
            public Error Error { get; set; }
        }

        public partial class Error
        {
            [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)]
            public string Message { get; set; }

            [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
            public string Name { get; set; }
        }

        public partial class OrderResponse
        {
            [JsonProperty("orderID", NullValueHandling = NullValueHandling.Ignore)]
            public Guid? OrderId { get; set; }

            [JsonProperty("clOrdID")]
            public string ClOrdId { get; set; }

            ... [code omitted for readability...]
        }

        public partial class OrderError
        {
            public static OrderError FromJson(string json)
            {
                return JsonConvert.DeserializeObject<OrderError>(json, BitMEX.JSONClass.Order.Converter.Settings);
            }
        }

        public partial class OrderResponse
        {
            public static OrderResponse FromJson(string json)
            {
                return JsonConvert.DeserializeObject<OrderResponse>(json, BitMEX.JSONClass.Order.Converter.Settings);
            }
        }

        public partial class OrdersResponse
        {
            public static List<OrderResponse> FromJson(string json)
            {
                return JsonConvert.DeserializeObject<List<OrderResponse>>(json, BitMEX.JSONClass.Order.Converter.Settings);
            }
        }

        internal static class Converter
        {
            public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
            {
                MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
                DateParseHandling = DateParseHandling.None,
                Converters =
                {
                    new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
                },
            };
        }
    }

The method I use to handle this situation looks like this, and I don't really like it because I'm sure it could be cleaner:

    private object ProcessJSONOrderResponse(string res, Boolean isArray = false)
    {
        if (isArray)
        {
            List<OrderResponse> multiOrderResp = OrdersResponse.FromJson(res);

            if (multiOrderResp.Count > 0)
            {
                return multiOrderResp;
            }
            else
            {
                var orderError = OrderError.FromJson(res);

                if (orderError.Error != null)
                {
                    return orderError;
                }
                else
                {
                    orderError = new OrderError();
                    orderError.Error.Name = "Custom error";
                    orderError.Error.Message = "No JSON response received...";
                    return orderError;
                }
            }
        }
        else
        {
            var oderResp = OrderResponse.FromJson(res);

            if (oderResp.OrderId != null)
            {
                return oderResp;
            }
            else
            {
                var orderError = OrderError.FromJson(res);

                if (orderError.Error != null)
                {
                    return orderError;
                }
                else
                {
                    orderError = new OrderError();
                    orderError.Error.Name = "Custom error";
                    orderError.Error.Message = "No JSON response received...";
                    return orderError;
                }
            }
        }
    }

So what I need is a way of handling JSON deserialization to either OrderResponse, an Array of OrderResponse or OrderError in the most efficient way possible with full error handling. Once I know how to do this I will be able to handle many more cases like this and build my API-client.

Many thanks in advance for shedding some light. I will be forever grateful.

AGI_rev
  • 129
  • 10
  • I am guessing you can check if the first JSON character is `[` or `{`, or use custom converter https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n – Slai Jul 14 '19 at 10:29
  • 2
    If you put together [Deserializing polymorphic json classes without type information using json.net](https://stackoverflow.com/q/19307752/3744182) and [How to handle both a single item and an array for the same property using JSON.net](https://stackoverflow.com/q/18994685/3744182) (linked above) you should be able to do what you need. – dbc Jul 14 '19 at 10:36
  • 1
    Thank a lot dbc. I will check it out asap. At first sight it looks pretty much what I am looking for. – AGI_rev Jul 18 '19 at 07:30
  • 1
    Were those answers sufficient, or do you still need help? – dbc Jul 20 '19 at 20:07
  • 1
    I managed to handle the situation in a way that suits my needs. Thanks again for you response. – AGI_rev Jul 21 '19 at 12:50

0 Answers0