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.

4
  • Have you tried SleepData[] sleepdata = JsonConvert.DeserializeObject<SleepData[]>(entrys());? The example data you showed is an array([ { ... }, { ... } ]) Commented Jan 13, 2019 at 8: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 ? Commented Jan 13, 2019 at 8:18
  • @Mathias that seems to work but how do I then hshow specifically sleepdata.Entry_Value for all the entries? Commented Jan 13, 2019 at 8: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() Commented Jan 13, 2019 at 8:30

2 Answers 2

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();
Sign up to request clarification or add additional context in comments.

9 Comments

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 It's a website that generates C# code for you. Click on the link in the answer. The address is 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.
Oh yeah I checked that but the Quicktype.Converter.Settings says it doesnt exist in the current context
@im_Ruben Change QuickType to whatever namespace you are in. It should be Health_App_Goede.
ParseStringConverter not in Newtonsoft.Json.Converters ?
|
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();

4 Comments

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
As mentioned, your JSON is a collection. Do you need to anything in particular from that json ?
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 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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.