I have a strange json, which:
- I can not change it, it is from a third party
- It can have up to 75 properties
A simple example of the json:
{
"bookingcode":["ABC","DEF", "GHJ", "TEST"],
"referencenumber":[123, 456]
"bookingdate":["22-07-2022T14:00:30", "23-11-2022T17:00:25"]
}
I am only interested in the last value of the array and want to deserialize into a class called Booking, so in this case bookingcode="TEST"
and bookingdate="23-11-2022T17:00:25"
.
A solution would be define a model:
public class Booking
{
public string BookingCode { get; set; }
public int ReferenceNumber { get; set; }
public DateTime BookingDate { get; set;}
}
public class BookingInput
{
public List<string> BookingCode { get; set;}
public List<int> ReferenceNumber { get; set; }
public List<DateTime> BookingDate { get; set; }
}
var bookinginput = JsonSerializer.Deserialize<BookingInput>(jsonString);
var booking = new Booking
{
BookingCode = bookinginput.BookingCode.Last(),
ReferenceNumber = bookinginput.ReferenceNumber.Last(),
...
}
I think it is very tedious to write out all 75 properties in code like this. Is there a better solution in Json.net or System.Text.Json for this?
CodePudding user response:
Using NewtonSoft.Json, you can create your own JsonConverter
. Below I have created a LastArrayItemJsonConverter
, which takes the last item from an array of a certain type and returns that.
public class LastArrayItemJsonConverter<TItem> : JsonConverter<TItem>
{
private string _formatString;
public LastArrayItemJsonConverter()
{ }
public LastArrayItemJsonConverter(string formatString)
{
_formatString = formatString;
}
public override TItem ReadJson(JsonReader reader, Type objectType, TItem existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (typeof(TItem) == typeof(DateTime) || typeof(TItem) == typeof(DateTime?))
reader.DateFormatString = _formatString;
TItem result = default;
if (reader.TokenType != JsonToken.StartArray)
return default;
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
result = (TItem)Convert.ChangeType(reader.Value, typeof(TItem));
return result;
}
public override void WriteJson(JsonWriter writer, TItem value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
By decorating your model, you can specify that the serializer should use the converter to convert the properties:
public class Booking
{
[JsonConverter(typeof(LastArrayItemJsonConverter<string>))]
public string BookingCode { get; set; }
[JsonConverter(typeof(LastArrayItemJsonConverter<int>))]
public int ReferenceNumber { get; set; }
[JsonConverter(typeof(LastArrayItemJsonConverter<DateTime>), "dd-MM-yyyy\\THH:mm:ss")]
public DateTime BookingDate { get; set; }
}
Now, the model's properties will be populated with the last values from the arrays. Deserialize the json using:
var booking = JsonConvert.DeserializeObject<Booking>(json)
CodePudding user response:
You can define a single Booking
class which includes
- the
BookingInput
's properties - and the last item retrieval logics as well
public class Booking
{
[JsonIgnore]
public string BookingCode => BookingCodes.Last();
[JsonIgnore]
public int ReferenceNumber => ReferenceNumbers.Last();
[JsonIgnore]
public DateTime BookingDate => BookingDates.Last();
[JsonProperty("bookingcode")]
public List<string> BookingCodes { get; set; } = new List<string>();
[JsonProperty("referencenumber")]
public List<int> ReferenceNumbers { get; set; } = new List<int>();
[JsonProperty("bookingdate")]
public List<DateTime> BookingDates { get; set; } = new List<DateTime>();
}
CodePudding user response:
if you want to use your custom c# class
using Newtonsoft.Json;
var jsonParsed = JObject.Parse(json);
foreach (var arr in jsonParsed.Properties())
jsonParsed[arr.Name] = arr.Value.LastOrDefault();
Booking booking = jsonParsed.ToObject<Booking>();
but since you can have up to 75 properties, maybe it would be better to use a dictionary instead of a custom class
Dictionary<string, object> bookingDict = new Dictionary<string, object>();
foreach (var arr in jsonParsed.Properties())
bookingDict.Add(arr.Name, arr.Value.LastOrDefault());
result
{
"bookingcode": "TEST",
"referencenumber": 456,
"bookingdate": "23-11-2022T17:00:25"
}
CodePudding user response:
It's better if you provide your request code too. did you add ReadAsStringAsync(); after the request?
public class Booking
{
[JsonProperty("bookingcode")]
public List<string> BookingCodes { get; set; } = new List<string>();
[JsonProperty("referencenumber")]
public List<int> ReferenceNumbers { get; set; } = new List<int>();
[JsonProperty("bookingdate")]
public List<DateTime> BookingDates { get; set; } = new List<DateTime>();
}
And some web request sample
using (var client = new HttpClient())
{
var response = await client.
GetAsync(apiEndpoint);
var responseText = await response.Content.ReadAsStringAsync();
var compareResult = JsonSerializer.Deserialize<Booking>(responseText)??new Booking();
return compareResult;
}