3

I have been trying to get this working for 4 days now but I just cant seem to figure it out. Im receiving a json string through an api and want to parse the data into different strings and ints:

Example Json String:

"[{\"Entry_number\":\"4\",\"Entry_date\":\"2019-01-10 18:22:55\",\"Customer_number\":\"16\",\"Entry_value\":\"13\",\"Comment\":\"Nu gaat ie t GVD doen\"},
    {\"Entry_number\":\"5\",\"Entry_date\":\"2019-01-12 14:34:23\",\"Customer_number\":\"16\",\"Entry_value\":\"10\",\"Comment\":\"TextBox\"},
    {\"Entry_number\":\"6\",\"Entry_date\":\"2019-01-12 14:34:31\",\"Customer_number\":\"16\",\"Entry_value\":\"10\",\"Comment\":\"Onrustig\"},
    {\"Entry_number\":\"7\",\"Entry_date\":\"2019-01-12 14:34:37\",\"Customer_number\":\"16\",\"Entry_value\":\"10\",\"Comment\":\"Ziek\"}]"

What im trying to convert to:

public class SleepEntry
{
    string Entry_number;
    string Entry_date;
    string Customer_number;
    string Entry_value;
    string Comment;

    public string Entry_number1 { get => Entry_number; set => Entry_number = value; }

    public string Entry_date1 { get => Entry_date; set => Entry_date = value; }

    public string Customer_number1 { get => Customer_number; set => Customer_number = value; }

    public string Entry_value1 { get => Entry_value; set => Entry_value = value; }

    public string Comment1 { get => Comment; set => Comment = value; }
}

public class SleepData
{
    private List<SleepEntry> plants; 

    public List<SleepEntry> Plants { get => plants; set => plants = value; }
}

Code that reads the json:

    public void Get_Monthly_Data()
    {


        StreamReader reader = new StreamReader(@"C:\Users\Ruben\source\repos\Health App Goede\Health App Goede\Resources\Cutstomer_ID.txt");
        Customernumber = reader.ReadLine();
        reader.Close();
        //string json = entrys();

        //convert json to series objects
        SleepData sleepdata = JsonConvert.DeserializeObject<SleepData>(entrys());

    }

    public string entrys()
    {
        string json = get.get_customer_monitoring_entry("sleep", Customernumber);

        return json;
    }

Now I want to try and Check for each entry if the dat was this week. Then just get the Entry_value of eacht entry from this week and for now show it in a textbox. Any help or tips would be really appreciated.

im_ Ruben
  • 87
  • 2
  • 10
  • Have you tried `SleepData[] sleepdata = JsonConvert.DeserializeObject(entrys());`? The example data you showed is an array(`[ { ... }, { ... } ]`) – Mathias Jan 13 '19 at 08:12
  • "Now I want to try and Check for each entry if the dat was this week. Then just get the Entry_value of eacht entry from this week and for now show it in a textbox" - Could you elloborate this part ? – Anu Viswan Jan 13 '19 at 08:18
  • @Mathias that seems to work but how do I then hshow specifically sleepdata.Entry_Value for all the entries? – im_ Ruben Jan 13 '19 at 08:23
  • You can go through the array with an for or foreach loop. If you are just interested in the first one you could also do a `sleepdata.FirstOrDefault()` – Mathias Jan 13 '19 at 08:30

2 Answers2

5

You don't actually need those backing fields. You can just write them as automatic properties with { get; set; }.

Your JSON has some quite annoying things in it, namely dates and numbers as strings. Therefore, I recommend you to use something like QuickType to have the C# model class generated for you.

Here is the result:

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

public partial class SleepEntry
{
    [JsonProperty("Entry_number")]
    [JsonConverter(typeof(ParseStringConverter))]
    public long EntryNumber { get; set; }

    [JsonProperty("Entry_date")]
    public DateTimeOffset EntryDate { get; set; }

    [JsonProperty("Customer_number")]
    [JsonConverter(typeof(ParseStringConverter))]
    public long CustomerNumber { get; set; }

    [JsonProperty("Entry_value")]
    [JsonConverter(typeof(ParseStringConverter))]
    public long EntryValue { get; set; }

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

public partial class SleepEntry
{
    public static SleepEntry[] FromJson(string json) => JsonConvert.DeserializeObject<SleepEntry[]>(json, QuickType.Converter.Settings);
}

public static class Serialize
{
    public static string ToJson(this SleepEntry[] self) => JsonConvert.SerializeObject(self, QuickType.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 }
        },
    };
}

internal class ParseStringConverter : JsonConverter
{
    public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);

    public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null) return null;
        var value = serializer.Deserialize<string>(reader);
        long l;
        if (Int64.TryParse(value, out l))
        {
            return l;
        }
        throw new Exception("Cannot unmarshal type long");
    }

    public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
    {
        if (untypedValue == null)
        {
            serializer.Serialize(writer, null);
            return;
        }
        var value = (long)untypedValue;
        serializer.Serialize(writer, value.ToString());
        return;
    }

    public static readonly ParseStringConverter Singleton = new ParseStringConverter();
}

Usage:

// sleepEntries is a SleepEntry[]
var sleepEntries = SleepEntry.FromJson(jsonString);

Now I want to try and Check for each entry if the dat was this week. Then just get the Entry_value of eacht entry from this week and for now show it in a textbox.

To figure out if two date times are in the same week, we can use this method:

private bool DatesAreInTheSameWeek(DateTime date1, DateTime date2)
{
    var cal = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar;
    var d1 = date1.Date.AddDays(-1 * (int)cal.GetDayOfWeek(date1));
    var d2 = date2.Date.AddDays(-1 * (int)cal.GetDayOfWeek(date2));

    return d1 == d2;
}

copied from this question.

Then this can be done with a little bit of LINQ:

List<long> list = sleepEntries.Where(x => DatesAreInTheSameWeek(x.EntryDate.DateTime, DateTime.Now)).Select(x => x.EntryValue).ToList();
David Clarke
  • 12,888
  • 9
  • 86
  • 116
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • This seems it would do exactly what I want to do. But how do I include Quicktype cant find any dll to download thanks in advance!! – im_ Ruben Jan 13 '19 at 08:34
  • @im_Ruben It's a website that generates C# code for you. Click on the link in the answer. The address is https://quicktype.io. The code in my answer is copied and pasted from QuickType, so you can just copy an paste that into an empty file and enjoy it. – Sweeper Jan 13 '19 at 08:39
  • Oh yeah I checked that but the Quicktype.Converter.Settings says it doesnt exist in the current context – im_ Ruben Jan 13 '19 at 08:41
  • @im_Ruben Change `QuickType` to whatever namespace you are in. It should be `Health_App_Goede`. – Sweeper Jan 13 '19 at 08:44
  • Thanks a million dude! Once I took out the date filter it worked like a charm. If the date filter is in the code it returns 0 entries tho so will have to look into that some more – im_ Ruben Jan 13 '19 at 09:03
  • do you by any chance know how I can the two dates as yyyy-mm-dd instead of the current dd/mm/yyyy – im_ Ruben Jan 13 '19 at 09:54
  • @im_Ruben This should help; https://stackoverflow.com/questions/18635599/specifying-a-custom-datetime-format-when-serializing-with-json-net – Sweeper Jan 13 '19 at 09:58
  • 1
    ParseStringConverter not in Newtonsoft.Json.Converters ? – Kiquenet Oct 07 '20 at 15:27
  • @Kiquenet It's a custom class generated by QuickType. You can see its declaration if you scroll down the first code snippet a bit. – Sweeper Oct 07 '20 at 23:48
2

Your Json string is an array, so you need to use

var result = JsonConvert.DeserializeObject<IEnumerable<SleepEntry>>(str);

Where SleepEntry is modified as

public class SleepEntry
{
string Entry_number;
string Entry_date;
string Customer_number;
string Entry_value;
string Comment;

[JsonProperty("Entry_number")]
public string Entry_number1 { get => Entry_number; set => Entry_number = value; }
[JsonProperty("Entry_date")]
public string Entry_date1 { get => Entry_date; set => Entry_date = value; }

 [JsonProperty("Custom_number1")]
public string Customer_number1 { get => Customer_number; set => Customer_number = value; }

[JsonProperty("Entry_value")]
public string Entry_value1 { get => Entry_value; set => Entry_value = value; }

[JsonProperty("Comment")]
public string Comment1 { get => Comment; set => Comment = value; }
}

PS: You can always remove backing fields and use Automatic Properties, unless you have used it for purpose

For getting value of first entry in current week.

var today = DateTime.Now;
var startOfWeek = today.AddDays((int)DateTime.Now.DayOfWeek * -1);


var value = result.Where(x=>DateTime.Parse(x.Entry_date1) > startOfWeek 
                        && DateTime.Parse(x.Entry_date1) < today.AddDays(7))
                  .Select(x=>x.Entry_value1).FirstOrDefault();
Anu Viswan
  • 17,797
  • 2
  • 22
  • 51
  • When I convert the var result to a string and show it in a textbox it returns this "System.Collections.Generic.List`1[Health_App_Goede.SleepEntry]" and not the data that was in the json – im_ Ruben Jan 13 '19 at 08:21
  • As mentioned, your JSON is a collection. Do you need to anything in particular from that json ? – Anu Viswan Jan 13 '19 at 08:22
  • Yes I want the Entry_Value which I will show in a textbox and the Entry_Date which I will use to filter – im_ Ruben Jan 13 '19 at 08:29
  • @im_Ruben If am correct, i think believe you want to get value of Entry_Value for date in current week and display it in a textbox. I have updated the answer with same. Since there is a possibility that there could be more than one entry in week, i have selected first one. But you can change it according to your rquirement. If my understanding of your requirement is wrong, kindly let me know – Anu Viswan Jan 13 '19 at 08:38