When I try to use CsvHelper to parse the below CSV, I get a "conversion cannot be performed" error (full error is below). It looks like I'm missing something about how to deal with reading values as decimals. Have seen some other answers relating to setting the culture, but that doesn't seem to have helped.
The CSV data is:
Title,Amount,NHS,Reference,GoCardless ID,email,surname,firstname,Full Name,DOB,Age,Right Lens,Left Lens,RightLensMonthlyAmount,LeftLensMonthlyAmount,LensMonthlyAmount,FeeMonthlyAmount,VAT Basis,LensBespokePrice,CareOnly,Notes
Mrs,24.3,N,100247,CUXXX,email#gmail.com,User,Test,Test User,17/09/1957,64,DAILIES® AquaComfort PLUS 30 Pack,DAILIES® AquaComfort PLUS 30 Pack,16.5,16.5,33,6.35,,,,
My class to map this data to properties is:
public class Payer
{
public string Title { get; set; }
public decimal Amount { get; set; }
[BooleanTrueValues("Y")]
[BooleanFalseValues("N")]
public bool NHS { get; set; }
public string Reference { get; set; }
[Name("GoCardless ID")]
public string GoCardless_ID { get; set; }
public string email { get; set; }
public string surname { get; set; }
public string firstname { get; set; }
[Name("Full Name")]
public string Fullname { get; set; }
[Name("DOB")]
public string Dob { get; set; }
public int Age { get; set; }
[Name("Right Lens")]
public string RightLens { get; set; }
[Name("Left Lens")]
public string LeftLens { get; set; }
public decimal RightLensMonthlyAmount { get; set; }
public decimal LeftLensMonthlyAmount { get; set; }
public decimal LensMonthlyAmount { get; set; }
public decimal FeeMonthlyAmount { get; set; }
[Name("VAT Basis")]
public string VATBasis { get; set; }
public decimal LensBespokePrice { get; set; }
[BooleanTrueValues("Y")]
public bool CareOnly { get; set; }
}
My code related to parsing the CSV is:
static void Main(string[] args)
{
var culture = new CultureInfo("en-GB");
var config = new CsvHelper.Configuration.CsvConfiguration(culture);
using (var reader = new StreamReader("test.csv"))
using (var csv = new CsvReader(reader, config))
{
var records = csv.GetRecords<Payer>();
Console.WriteLine("Got records"); //this prints on the console
foreach (var payer in records)
{
Console.WriteLine(payer);
}
}
}
The error only happens with the foreach loop, not the actual GetRecords() method.
Full error:
CsvHelper.TypeConversion.TypeConverterException: "The conversion cannot be performed.\n Text: ''\n MemberType: System.Decimal\n TypeConverter: 'CsvHelper.TypeConversion.DecimalConverter'\nIReader state:\n ColumnCount: 0\n CurrentIndex: 18\n HeaderRecord:\n["Title","Amount","NHS","Reference","GoCardless ID","email","surname","firstname","Full Name","DOB","Age","Right Lens","Left Lens","RightLensMonthlyAmount","LeftLensMonthlyAmount","LensMonthlyAmount","FeeMonthlyAmount","VAT Basis","LensBespokePrice","CareOnly","Notes"]\nIParser state:\n ByteCount: 0\n CharCount: 392\n Row: 2\n RawRow: 2\n Count: 21\n RawRecord:\nMrs,24.3,N,100247,CUXXX,email#gmail.com,User,Test,Test User,17/09/1957,64,DAILIES® AquaComfort PLUS 30 Pack,DAILIES® AquaComfort PLUS 30 Pack,16.5,16.5,33,6.35,,,,\r\n\n"
at CsvHelper.TypeConversion.DefaultTypeConverter.ConvertFromString(String text, IReaderRow row, MemberMapData memberMapData)\n at CsvHelper.TypeConversion.DecimalConverter.ConvertFromString(String text, IReaderRow row, MemberMapData memberMapData)\n at CsvHelper.Expressions.RecordCreator.CreateT\n at CsvHelper.Expressions.RecordManager.CreateT\n at CsvHelper.CsvReader.d__87`1.MoveNext()\n at dd_journal.Program.Main(String[] args) in /Users/abhi/Documents/Practice/dd-journal/Program.cs:22
So the issue is that CSVHelper doesn't understand how to convert an empty field for LensBespokePrice to a decimal value. There are two options you can use here:
Update the CSV file to add a default value to the empty fields (i.e. 0 for LensBespokePrice).
Create a Type Conversion to handle an empty cell to a decimal.
Do you have the ability to modify the CSV file? If so, then #1 works by changing your CSV to be (note the change for LensBespokePrice and CareOnly):
Title,Amount,NHS,Reference,GoCardless ID,email,surname,firstname,Full Name,DOB,Age,Right Lens,Left Lens,RightLensMonthlyAmount,LeftLensMonthlyAmount,LensMonthlyAmount,FeeMonthlyAmount,VAT Basis,LensBespokePrice,CareOnly,Notes
Mrs,24.3,N,100247,CUXXX,email#gmail.com,User,Test,Test User,17/09/1957,64,DAILIES® AquaComfort PLUS 30 Pack,DAILIES® AquaComfort PLUS 30 Pack,16.5,16.5,33,6.35,,0,N,
If not, you'll need a type converter for both the empty decimal and empty boolean. For example, with all your code in a single file, that may look like:
using CsvHelper;
using CsvHelper.Configuration;
using CsvHelper.Configuration.Attributes;
using CsvHelper.TypeConversion;
using System;
using System.Globalization;
using System.IO;
using System.Text.Json;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var culture = new CultureInfo("en-GB");
var config = new CsvConfiguration(culture);
using (var reader = new StreamReader("test.csv"))
using (var csv = new CsvReader(reader, config))
{
var records = csv.GetRecords<Payer>();
Console.WriteLine("Got records"); //this prints on the console
foreach (var payer in records)
{
var j = JsonSerializer.Serialize(payer);
Console.WriteLine(j);
}
}
}
}
public class CustomDecimalConverter : DecimalConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if(decimal.TryParse(text, out var result))
{
return result;
} else
{
return decimal.Zero;
}
}
}
public class CustomBooleanConverter : BooleanConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if (bool.TryParse(text, out var result))
{
return result;
}
else
{
return false;
}
}
}
public class Payer
{
public string Title { get; set; }
public decimal Amount { get; set; }
[BooleanTrueValues("Y")]
[BooleanFalseValues("N")]
public bool NHS { get; set; }
public string Reference { get; set; }
[Name("GoCardless ID")]
public string GoCardless_ID { get; set; }
public string email { get; set; }
public string surname { get; set; }
public string firstname { get; set; }
[Name("Full Name")]
public string Fullname { get; set; }
[Name("DOB")]
public string Dob { get; set; }
public int Age { get; set; }
[Name("Right Lens")]
public string RightLens { get; set; }
[Name("Left Lens")]
public string LeftLens { get; set; }
public decimal RightLensMonthlyAmount { get; set; }
public decimal LeftLensMonthlyAmount { get; set; }
public decimal LensMonthlyAmount { get; set; }
public decimal FeeMonthlyAmount { get; set; }
[Name("VAT Basis")]
public string VATBasis { get; set; }
[TypeConverter(typeof(CustomDecimalConverter))]
public decimal LensBespokePrice { get; set; }
[BooleanTrueValues("Y")]
[BooleanFalseValues("N")]
[TypeConverter(typeof(CustomBooleanConverter))]
public bool CareOnly { get; set; }
}
}
Please note that I added the JsonSerializer.Serialize(payer); in the foreach loop within the Main method so that you can view the JSON result from the console.
I added in two custom converters (CustomBooleanConverter and CustomDecimalConverter). The payer class is then updated to have attributes added to the LensBespokePrice and CareOnly properties. Additionally, you didn't have an attribute on CareOnly for false values and while not required is a good practice.
To clarify why this is happening only in your foreach loop and not var records = csv.GetRecords<Payer>(); is because the values aren't actually converted into your payer class until the records are enumerated.
Payer is a whole class of values. It looks like it is trying to convert when you write to the console. I believe you will need to tell it what part of payer you are wanting to print like:
Console.WriteLine(payer.surname);
I'm trying to deserialize the JSON from the weather API, I have created C# classes but I can't seem to get it working. Most sites display this JSON as invalid format, so I'm not really sure whats wrong with it. Here is the JSON string and my class for Deserializing.Visual studio displays it like any other regular JSON.
"[\"cod\":\"200\",\"message\":0,\"cnt\":40,\"list\":[[\"dt\":1574175600,\"main\":[\"temp\":284.79,\"temp_min\":282.63,\"temp_max\":284.79,\"pressure\":1021,\"sea_level\":1021,\"grnd_level\":958,\"humidity\":88,\"temp_kf\":2.16],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3,\"deg\":51],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-19 15:00:00\"],[\"dt\":1574186400,\"main\":[\"temp\":282.92,\"temp_min\":281.3,\"temp_max\":282.92,\"pressure\":1021,\"sea_level\":1021,\"grnd_level\":958,\"humidity\":94,\"temp_kf\":1.62],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.93,\"deg\":53],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-19 18:00:00\"],[\"dt\":1574197200,\"main\":[\"temp\":282.6,\"temp_min\":281.52,\"temp_max\":282.6,\"pressure\":1021,\"sea_level\":1021,\"grnd_level\":957,\"humidity\":93,\"temp_kf\":1.08],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.84,\"deg\":64],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-19 21:00:00\"],[\"dt\":1574208000,\"main\":[\"temp\":281.67,\"temp_min\":281.13,\"temp_max\":281.67,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":956,\"humidity\":94,\"temp_kf\":0.54],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.83,\"deg\":65],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-20 00:00:00\"],[\"dt\":1574218800,\"main\":[\"temp\":280.97,\"temp_min\":280.97,\"temp_max\":280.97,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":954,\"humidity\":96,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.9,\"deg\":57],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-20 03:00:00\"],[\"dt\":1574229600,\"main\":[\"temp\":280.72,\"temp_min\":280.72,\"temp_max\":280.72,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":953,\"humidity\":96,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":90],\"wind\":[\"speed\":3.65,\"deg\":65],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-20 06:00:00\"],[\"dt\":1574240400,\"main\":[\"temp\":282.34,\"temp_min\":282.34,\"temp_max\":282.34,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":953,\"humidity\":91,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":1.32,\"deg\":78],\"rain\":[\"3h\":1.19],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-20 09:00:00\"],[\"dt\":1574251200,\"main\":[\"temp\":283.44,\"temp_min\":283.44,\"temp_max\":283.44,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":952,\"humidity\":87,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.16,\"deg\":79],\"rain\":[\"3h\":1.94],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-20 12:00:00\"],[\"dt\":1574262000,\"main\":[\"temp\":282.5,\"temp_min\":282.5,\"temp_max\":282.5,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":952,\"humidity\":90,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.21,\"deg\":75],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-20 15:00:00\"],[\"dt\":1574272800,\"main\":[\"temp\":281.27,\"temp_min\":281.27,\"temp_max\":281.27,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":953,\"humidity\":88,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10n\"]],\"clouds\":[\"all\":80],\"wind\":[\"speed\":1.94,\"deg\":105],\"rain\":[\"3h\":0.38],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-20 18:00:00\"],[\"dt\":1574283600,\"main\":[\"temp\":280.14,\"temp_min\":280.14,\"temp_max\":280.14,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":954,\"humidity\":90,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10n\"]],\"clouds\":[\"all\":0],\"wind\":[\"speed\":1.72,\"deg\":131],\"rain\":[\"3h\":0.19],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-20 21:00:00\"],[\"dt\":1574294400,\"main\":[\"temp\":279.7,\"temp_min\":279.7,\"temp_max\":279.7,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":954,\"humidity\":89,\"temp_kf\":0],\"weather\":[[\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"]],\"clouds\":[\"all\":0],\"wind\":[\"speed\":1.53,\"deg\":122],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-21 00:00:00\"],[\"dt\":1574305200,\"main\":[\"temp\":279.29,\"temp_min\":279.29,\"temp_max\":279.29,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":954,\"humidity\":89,\"temp_kf\":0],\"weather\":[[\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"]],\"clouds\":[\"all\":0],\"wind\":[\"speed\":1.71,\"deg\":110],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-21 03:00:00\"],[\"dt\":1574316000,\"main\":[\"temp\":278.99,\"temp_min\":278.99,\"temp_max\":278.99,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":90,\"temp_kf\":0],\"weather\":[[\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"]],\"clouds\":[\"all\":0],\"wind\":[\"speed\":1.76,\"deg\":106],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-21 06:00:00\"],[\"dt\":1574326800,\"main\":[\"temp\":284.12,\"temp_min\":284.12,\"temp_max\":284.12,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":954,\"humidity\":71,\"temp_kf\":0],\"weather\":[[\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"]],\"clouds\":[\"all\":0],\"wind\":[\"speed\":1.91,\"deg\":94],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-21 09:00:00\"],[\"dt\":1574337600,\"main\":[\"temp\":286.38,\"temp_min\":286.38,\"temp_max\":286.38,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":953,\"humidity\":62,\"temp_kf\":0],\"weather\":[[\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"]],\"clouds\":[\"all\":21],\"wind\":[\"speed\":2.19,\"deg\":66],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-21 12:00:00\"],[\"dt\":1574348400,\"main\":[\"temp\":282.01,\"temp_min\":282.01,\"temp_max\":282.01,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":953,\"humidity\":91,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.67,\"deg\":46],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-21 15:00:00\"],[\"dt\":1574359200,\"main\":[\"temp\":280.86,\"temp_min\":280.86,\"temp_max\":280.86,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":954,\"humidity\":94,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":86],\"wind\":[\"speed\":2.78,\"deg\":49],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-21 18:00:00\"],[\"dt\":1574370000,\"main\":[\"temp\":280.55,\"temp_min\":280.55,\"temp_max\":280.55,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":92,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.52,\"deg\":56],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-21 21:00:00\"],[\"dt\":1574380800,\"main\":[\"temp\":280.04,\"temp_min\":280.04,\"temp_max\":280.04,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":953,\"humidity\":95,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.6,\"deg\":53],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-22 00:00:00\"],[\"dt\":1574391600,\"main\":[\"temp\":280.1,\"temp_min\":280.1,\"temp_max\":280.1,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":953,\"humidity\":96,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.54,\"deg\":49],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-22 03:00:00\"],[\"dt\":1574402400,\"main\":[\"temp\":281.29,\"temp_min\":281.29,\"temp_max\":281.29,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":953,\"humidity\":97,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":2.24,\"deg\":38],\"rain\":[\"3h\":0.44],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-22 06:00:00\"],[\"dt\":1574413200,\"main\":[\"temp\":280.84,\"temp_min\":280.84,\"temp_max\":280.84,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":93,\"temp_kf\":0],\"weather\":[[\"id\":501,\"main\":\"Rain\",\"description\":\"moderate rain\",\"icon\":\"10d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.21,\"deg\":33],\"rain\":[\"3h\":3.88],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-22 09:00:00\"],[\"dt\":1574424000,\"main\":[\"temp\":279.71,\"temp_min\":279.71,\"temp_max\":279.71,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":93,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.37,\"deg\":41],\"rain\":[\"3h\":2.81],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-22 12:00:00\"],[\"dt\":1574434800,\"main\":[\"temp\":278.48,\"temp_min\":278.48,\"temp_max\":278.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":93,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.59,\"deg\":49],\"rain\":[\"3h\":1.88],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-22 15:00:00\"],[\"dt\":1574445600,\"main\":[\"temp\":278.11,\"temp_min\":278.11,\"temp_max\":278.11,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":955,\"humidity\":93,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.55,\"deg\":49],\"rain\":[\"3h\":0.81],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-22 18:00:00\"],[\"dt\":1574456400,\"main\":[\"temp\":278.1,\"temp_min\":278.1,\"temp_max\":278.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":955,\"humidity\":93,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.67,\"deg\":49],\"rain\":[\"3h\":1.38],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-22 21:00:00\"],[\"dt\":1574467200,\"main\":[\"temp\":277.43,\"temp_min\":277.43,\"temp_max\":277.43,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":955,\"humidity\":93,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.15,\"deg\":47],\"rain\":[\"3h\":0.75],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-23 00:00:00\"],[\"dt\":1574478000,\"main\":[\"temp\":277.23,\"temp_min\":277.23,\"temp_max\":277.23,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":955,\"humidity\":92,\"temp_kf\":0],\"weather\":[[\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10n\"]],\"clouds\":[\"all\":98],\"wind\":[\"speed\":3.5,\"deg\":59],\"rain\":[\"3h\":0.56],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-23 03:00:00\"],[\"dt\":1574488800,\"main\":[\"temp\":276.54,\"temp_min\":276.54,\"temp_max\":276.54,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":955,\"humidity\":95,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":98],\"wind\":[\"speed\":3.32,\"deg\":59],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-23 06:00:00\"],[\"dt\":1574499600,\"main\":[\"temp\":278.93,\"temp_min\":278.93,\"temp_max\":278.93,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":955,\"humidity\":86,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.36,\"deg\":56],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-23 09:00:00\"],[\"dt\":1574510400,\"main\":[\"temp\":280.06,\"temp_min\":280.06,\"temp_max\":280.06,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":954,\"humidity\":80,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.74,\"deg\":53],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-23 12:00:00\"],[\"dt\":1574521200,\"main\":[\"temp\":277.41,\"temp_min\":277.41,\"temp_max\":277.41,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":954,\"humidity\":89,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.84,\"deg\":55],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-23 15:00:00\"],[\"dt\":1574532000,\"main\":[\"temp\":276.83,\"temp_min\":276.83,\"temp_max\":276.83,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":92,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":96],\"wind\":[\"speed\":3.75,\"deg\":56],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-23 18:00:00\"],[\"dt\":1574542800,\"main\":[\"temp\":277.04,\"temp_min\":277.04,\"temp_max\":277.04,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":90,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":100],\"wind\":[\"speed\":3.55,\"deg\":61],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-23 21:00:00\"],[\"dt\":1574553600,\"main\":[\"temp\":275.99,\"temp_min\":275.99,\"temp_max\":275.99,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":96,\"temp_kf\":0],\"weather\":[[\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":81],\"wind\":[\"speed\":3.19,\"deg\":55],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-24 00:00:00\"],[\"dt\":1574564400,\"main\":[\"temp\":276.56,\"temp_min\":276.56,\"temp_max\":276.56,\"pressure\":1017,\"sea_level\":1017,\"grnd_level\":953,\"humidity\":96,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"]],\"clouds\":[\"all\":91],\"wind\":[\"speed\":3.02,\"deg\":62],\"sys\":[\"pod\":\"n\"],\"dt_txt\":\"2019-11-24 03:00:00\"],[\"dt\":1574575200,\"main\":[\"temp\":277.36,\"temp_min\":277.36,\"temp_max\":277.36,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":95,\"temp_kf\":0],\"weather\":[[\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":86],\"wind\":[\"speed\":2.99,\"deg\":62],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-24 06:00:00\"],[\"dt\":1574586000,\"main\":[\"temp\":280.51,\"temp_min\":280.51,\"temp_max\":280.51,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":954,\"humidity\":82,\"temp_kf\":0],\"weather\":[[\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"]],\"clouds\":[\"all\":74],\"wind\":[\"speed\":3.05,\"deg\":64],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-24 09:00:00\"],[\"dt\":1574596800,\"main\":[\"temp\":282.87,\"temp_min\":282.87,\"temp_max\":282.87,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":953,\"humidity\":74,\"temp_kf\":0],\"weather\":[[\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"]],\"clouds\":[\"all\":42],\"wind\":[\"speed\":3.21,\"deg\":50],\"sys\":[\"pod\":\"d\"],\"dt_txt\":\"2019-11-24 12:00:00\"]],\"city\":[\"id\":787657,\"name\":\"Nis\",\"coord\":[\"lat\":43.3247,\"lon\":21.9033],\"country\":\"RS\",\"timezone\":3600,\"sunrise\":1574141412,\"sunset\":1574175927]]"
And my class for deserializing:
public class WeatherInfo
{
public class root
{
public string cod { get; set; }
public string message { get; set; }
public string cnt { get; set; }
public allLists list { get; set; }
public city city { get; set; }
}
public class allLists
{
allinfo[] allinfos { get; set; }
}
public class allinfo
{
public string dt { get; set; }
public main main { get; set; }
public allWeathers weather { get; set; }
public string dt_txt { get; set; }
}
public class main
{
public double temp { get; set; }
public double temp_min { get; set; }
public double temp_max { get; set; }
public double pressure { get; set; }
public double sea_level { get; set; }
public double grnd_level { get; set; }
public double humidity { get; set; }
public double temp_kf { get; set; }
}
public class allWeathers
{
public weather[] weathers { get; set; }
}
public class weather
{
public int id { get; set; }
public string main { get; set; }
public string description { get; set; }
public string icon { get; set; }
}
public class clouds
{
public double all { get; set; }
}
public class wind
{
public double speed { get; set; }
public double deg { get; set; }
}
public class sys
{
public string pod { get; set; }
}
public class city
{
public int id { get; set; }
public string name { get; set; }
public coord coord { get; set; }
public string country { get; set; }
public string timezone { get; set; }
public string sunrise { get; set; }
public string sunset { get; set; }
}
public class coord
{
public double lat { get; set; }
public double lon { get; set; }
}
}
Your JSON is not valid.
The main thing is that you are using brackets [] where you should be using braces {}.
In JSON [] is an array, while {} is an object. There are a couple of places where you need to have an array (e.g. list) so you can't simply do a find-replace to fix this.
An easy way to resolve this in the future is to create an instance of your WeatherInfo class, populate it with data, and then serialize it to JSON. You can then compare that with the JSON you have (using a diff tool like KDiff or WinMerge) to identify where your source JSON is different from your generated JSON.
A valid JSON always starts with a [ or a { and ends with the same, where square bracket [ represents an array and curly bracket { represents an object.
Looking at your C# class, your JSON lacks the curly brace to start with for objects and is also missing names for the arrays like allinfos.
You should start building your JSON like this:
var json = JToken.Parse
("{\"cod\":\"200\",\"message\":0,\"cnt\":40,\"list\":{\"allinfos\":[{\"dt\":1574175600, \"main\":{\"temp\":284.79,\"temp_min\":282.63,\"temp_max\":284.79,\"pressure\":1021,\"sea_level\":1021,\"grnd_level\":958,\"humidity\":88,\"temp_kf\":2.16}}]}}").ToString(Formatting.Indented);
This will give a formatted, easy to read output like this:
{
"cod": "200",
"message": 0,
"cnt": 40,
"list": {
"allinfos": [
{
"dt": 1574175600,
"main": {
"temp": 284.79,
"temp_min": 282.63,
"temp_max": 284.79,
"pressure": 1021,
"sea_level": 1021,
"grnd_level": 958,
"humidity": 88,
"temp_kf": 2.16
}
}
]
}
}
Update: The JSON was actually valid, the problem is that I was trying to work with debugging version of the string. The debugger automatically adds escape characters and "" quotes. Also some of the classes I had didn't follow up the JSON format correctly, so that error stopped me from seeing the real issue here.