How to read values from array of objects in appsettings.json file - c#

My appsettings json file
{
"StudentBirthdays": [
{ "Anne": "01/11/2000"},
{ "Peter": "29/07/2001"},
{ "Jane": "15/10/2001"},
{ "John": "Not Mentioned"}
]
}
I have a seperate config class.
public string GetConfigValue(string key)
{
var value = _configuration["AppSettings:" + key];
return !string.IsNullOrEmpty(value) ? Convert.ToString(value) : string.Empty;
}
What I have tried is,
list= _configHelper.GetConfigValue("StudentBirthdays");
For the above I dont get the values.
How can I read the values(I want to read the name of the student and his birthday seperatly).
Any help is apreciated

You can obtain the birthdays using the following code:
// get the section that holds the birthdays
var studentBirthdaysSection = _configuration.GetSection("StudentBirthdays");
// iterate through each child object of StudentBirthdays
foreach (var studentBirthdayObject in studentBirthdaysSection.GetChildren())
{
// your format is a bit weird here where each birthday is a key:value pair,
// rather than something like { "name": "Anne", "birthday": "01/11/2000" }
// so we need to get the children and take the first one
var kv = studentBirthdayObject.GetChildren().First();
string studentName = kv.Key;
string studentBirthday = kv.Value;
Console.WriteLine("{0} - {1}", studentName, studentBirthday);
}
Try it online

try this
using System.Linq;
public List<Student> GetStudentsFromConfig()
{
return _configuration
.GetSection("StudentBirthdays")
.Get<Dictionary<string, string>[]>()
.SelectMany(i => i)
.Select(ie => new Student {Name=ie.Key, DOB=ie.Value})
.ToList();
}
test
items= _configHelper.GetStudentsFromConfig();
foreach (var item in items) Console.WriteLine($"Name: {item.Name} , DOB: {item.DOB} ");
result
Name: Anne , DOB: 01/11/2000
Name: Peter , DOB: 29/07/2001
Name: Jane , DOB: 15/10/2001
Name: John , DOB: Not Mentioned
class
public class Student
{
public string Name { get; set; }
public string DOB { get; set; }
}

Try this:
Create Model/Class like below:
public class StudentBirthday
{
String Name,
String Birthday
}
Then access values like this :
List<StudentBirthday StudentBirthdays =
_config.GetSection("Main:StudentBirthdays").Get<List<StudentBirthday();

Related

How to properly access object's List<> value in C#?

I am trying to get the object value but I don't know how to do it. I'm new to C# and its giving me syntax error. I want to print it separately via the method "PrintSample" How can I just concatenate or append the whatData variable . Thank you.
PrintSample(getData, "name");
PrintSample(getData, "phone");
PrintSample(getData, "address");
//Reading the CSV file and put it in the object
string[] lines = File.ReadAllLines("sampleData.csv");
var list = new List<Sample>();
foreach (var line in lines)
{
var values = line.Split(',');
var sampleData = new Sample()
{
name = values[0],
phone = values[1],
address = values[2]
};
list.Add(sampleData);
}
public class Sample
{
public string name { get; set; }
public string phone { get; set; }
public string adress { get; set; }
}
//Method to call to print the Data
private static void PrintSample(Sample getData, string whatData)
{
//THis is where I'm having error, how can I just append the whatData to the x.?
Console.WriteLine( $"{getData. + whatData}");
}
In C# it's not possible to dynamically evaluate expression like
$"{getData. + whatData}"
As opposed to languages like JavaScript.
I'd suggest to use rather switch expression or Dictionary<string, string>
public void PrintData(Sample sample, string whatData)
{
var data = whatData switch
{
"name" => sample.name,
"phone" => sample.phone,
"address" => sample.address
_ => throw new ArgumentOutOfRangeException(nameof(whatData)),
};
Console.WriteLine(data);
}
I'm not sure what you are trying to achieve. Perhaps this will help you:
private static void PrintSample(Sample getData, string whatData)
{
var property = getData.GetType().GetProperty(whatData);
string value = (string)property?.GetValue(getData) ?? "";
Console.WriteLine($"{value}");
}
What PO really needs is
private static void PrintSamples(List<Sample> samples)
{
foreach (var sample in samples)
Console.WriteLine($"name : {sample.name} phone: {sample.phone} address: {sample.address} ");
}
and code
var list = new List<Sample>();
foreach (var line in lines)
{
......
}
PrintSamples(list);
it is radicolous to use
PrintSample(getData, "name");
instead of just
PrintSample(getData.name)
You can do this using reflection. However, it's known to be relatively slow.
public static void PrintSample(object getData, string whatData)
{
Console.WriteLine( $"{getData.GetType().GetProperty(whatData).GetValue(getData, null)}");
}

How to query multiple json nodes?

I have the following json:
{
"key445" : {
"text" : "cat",
"id" : 445
},
"key457" : {
"text" : "mouse",
"id" : 457
},
"key458" : {
"text" : "rodent",
"id" : 458
}
}
I am trying extract text and id into a List<TextIdentifier> (a class with string and an int), or even separately into List<string> and List<int>.
I read the text into JObject using JObject.Parse method. However, I can't figure out how to get to the text and id nodes. I've tried the following but it returns nothing.
var textTokens = o.SelectTokens("/*/text");
var idTokens = o.SelectTokens("/*/id");
How can I get to the tokens I want?
I would just convert the whole JSON into a Dictionary<string, TextIdentifier> instead of trying to use JsonPath at all:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
public class TextIdentifier
{
public string Text { get; set; }
public int Id { get; set; }
public override string ToString() => $"Id: {Id}; Text: {Text}";
}
public class Test
{
static void Main()
{
var json = File.ReadAllText("test.json");
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, TextIdentifier>>(json);
foreach (var pair in dictionary)
{
Console.WriteLine($"{pair.Key} => {pair.Value}");
}
}
}
Output:
key445 => Id: 445; Text: cat
key457 => Id: 457; Text: mouse
key458 => Id: 458; Text: rodent
If you don't care about the keys, you can use dictionary.Values.ToList() to get a List<TextIdentifier> although you shouldn't rely on the order of them.

sort custom array list with a specific field

i would like to sort by postal address but i am unable to i have seen some Linq functions tried them but i can't seem to get all the required parameters needed.
for example i saw this one example
list.Sort((p, q) => p.Category.CompareTo(q.Category)); /*has and error that says cannot convert lamba expressions to type '|Comparer' because it is not a delegate*/
but i dont seem to understand how to use it.
MyCustomList.cs
class MyCustomList
{
private string name;
private string postalAddress;
public MyCustomList(string name, string postalAddress)
{
this.name = name;
this.postalAddress = postalAddress;
}
//getters and setters
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public string PostalAddress
{
get
{
return postalAddress;
}
set
{
postalAddress = value;
}
}
}
Form1.cs
ArrayList list = new ArrayList();
list.Add(new MyCustomList("A somename","A Fake Postal Address");
list.Add(new MyCustomList("B somename","B Fake Postal Address");
list.Sort(); // Sort by Postal adress
Do you really need to use ArrayList?
It's a relic from the pre-generics days of .NET, and you should really be using an implementation of IEnumerable<T> where possible e.g. List<T>.
LINQ operates on IEnumerable<T>, so won't work with your ArrayList, and the method you are looking for is OrderBy or OrderByDescending.
Example:
var list = new List<MyCustomList>();
list.Add(new MyCustomList("A somename","A Fake Postal Address"));
list.Add(new MyCustomList("B somename","B Fake Postal Address"));
list.OrderBy(cl => cl.Postcode); // Sort by Postal address
First stop using ArrayList - its as good as obsolete.
Either using Array like this
var list = MyCustomList[2];
list[0] = new MyCustomList(...
list[1] = new MyCustomList(....
or use something like the List<T> class
var list = new List<MyCustomList>();
list.Add(new MyCustomList(...
list.Add(new MyCustomList(...
If you use array then the Sort function that takes an instance of Comparison<T> is static
see the documentation here https://learn.microsoft.com/en-us/dotnet/api/system.array.sort?view=netframework-4.8#System_Array_Sort__1___0___System_Comparison___0__
you need to call it like so:
Array.Sort(list, (a,b) => a.PostalAddress.CompareTo(b.PostalAddress))
or use linq on your List or Array and use OrderBy
var orderedList = list.OrderBy(a => a.PostalAddress);
Already approved by many https://stackoverflow.com/a/57371579/6923146
For order wise sorting with a specific field in c# using linq
list = list.OrderByDescending(x => x.Name).ToList();
list = list.OrderBy(x => x.Name).ToList();
//list.OrderBy(x => x.YourClassSpecificField).ToList()
Example:
please try to run following code in fiddle :
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<MyCustomList> list = new List<MyCustomList>();
list.Add(new MyCustomList("A somename", "A Fake Postal Address"));
list.Add(new MyCustomList("B somename", "B Fake Postal Address"));
//list.Sort();
Console.WriteLine("descending order");
list = list.OrderByDescending(x => x.Name).ToList();
foreach (MyCustomList o in list)
{
Console.WriteLine(o.Name + " -- " + o.PostalAddress );
}
Console.WriteLine("ascending order");
list = list.OrderBy(x => x.Name).ToList();
foreach (MyCustomList o in list)
{
Console.WriteLine(o.Name + " -- " + o.PostalAddress );
}
}
public class MyCustomList
{
private string name;
private string postalAddress;
public string Name
{
get { return name; }
set { name = value; }
}
public string PostalAddress
{
get { return postalAddress; }
set { postalAddress = value; }
}
public MyCustomList(string name, string postalAddress)
{
this.name = name;
this.postalAddress = postalAddress;
}
}
}

How to split string and assign as column and row in table

I have a input strings example
str1 = ""Type":"#Microsoft.Azure","Email":"abc#tmail.com","DisplayName":"abc","Dpt":"home"";
str2 = ""Type":"#Microsoft.Azure","Email":"xyz#tmail.com","DisplayName":"xyz","Dpt":"home"";
In compileable form it looks like this:
string str = #"""Type"":""#Microsoft.Azure"",""Email"":""abc#tmail.com"",""DisplayName"":""abc"",""Dpt"":""home""";
Can i split on "," delimiter and assign left to ":" as columns and right to ":" as rows in table.
Example:
"Type" "Email" "DisplayName" "Dpt"
"#Microsoft.Azure" "abc#tmail.com" "abc" "home"
"#Microsoft.Azure" "xyz#tmail.com" "xyz" "home"
i tried something like this
string str = ' "name":"abd","":""m"":"" ';
string[] strS1 = str.split(',');
foreach(string S1 in strS1){
string[] strS2 = str.split(':');
foreach(string S2 in strS2){
console.write(s2)
}
}
You can try something like this : Demo
The Json Way.
You assume it's a Json.
Join the line with },{. Add a Starting [{ and Ending }]. Bim, You are ready to go.
Deserilise to you custom type : I ignored Type property here
JsonConvert.DeserializeObject<List<CsvItem>>(myJSON);
public class CsvItem
{
public string Email { get; set; }
public string DisplayName { get; set; }
public string Dpt { get; set; }
}
Your parsing way: String Split.
After the S1.Split(':'), you end up with a small array the first value is the property name the second the value.
Trim the ", compare and assign.
if (strS2[0].Trim('"') == "Email") temp.Email = strS2[1].Trim('"');
if (strS2[0].Trim('"') == "DisplayName") temp.DisplayName = strS2[1].Trim('"');
if (strS2[0].Trim('"') == "Dpt") temp.Dpt = strS2[1].Trim('"');
Same thing in LinQ:
At this point it's not faster, easier to maintain, not even easier to read. It's just compact
lines
.Select(x => x.Split(','))
.Select(x =>
new CsvItem
{
Email = x[1].Split(':')[1].Trim('"'),
DisplayName = x[2].Split(':')[1].Trim('"'),
Dpt = x[3].Split(':')[1].Trim('"')
})
What's left?
Regex like : "(\w+)":"(.+?)", could easy replace the split. With a more detailed regex you can catch only the value you need.
What solution in the end?
Depending on the quality of the file. If it's human generated and can containt error.
You way to handle the error: Do you reject the whole file in case of error? Do you return only the list of valid data? etc.
I will choose either Solution #1 or #2. #1 for sometime broken file. #2 for meticulous error handleing and debugging.
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
string inputCSV = #"""Type"":""#Microsoft.Azure"",""Email"":""abc#tmail.com"",""DisplayName"":""abc"",""Dpt"":""home""
""Type"":""#Microsoft.Azure"",""Email"":""xyz#tmail.com"",""DisplayName"":""xyz"",""Dpt"":""home""";
// ReadAllLines mock
string[] lines = inputCSV.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
{ // The Json Way
var bringJsonBack = "[\n{" + string.Join("},\n{", lines) + "}\n]";
var results = JsonConvert.DeserializeObject<List<CsvItem>>(bringJsonBack);
results.Dump();
}
{ // Your working way
var results = new List<CsvItem>();
foreach (var line in lines)
{
var temp = new CsvItem();
string[] strS1 = line.Split(',');
foreach (string S1 in strS1)
{
string[] strS2 = S1.Split(':');
// You have a part Before the : and one after we just string check to know what property we re on.
if (strS2[0].Trim('"') == "Email")
{
temp.Email = strS2[1].Trim('"');
}
if (strS2[0].Trim('"') == "DisplayName")
{
temp.DisplayName = strS2[1].Trim('"');
}
if (strS2[0].Trim('"') == "Dpt")
{
temp.Dpt = strS2[1].Trim('"');
}
}
results.Add(temp);
}
results.Dump();
}
{ // LinQ Version of your algo.
var results = lines
.Select(x => x.Split(','))
.Select(x =>
new CsvItem
{
Email = x[1].Split(':')[1].Trim('"'),
DisplayName = x[2].Split(':')[1].Trim('"'),
Dpt = x[3].Split(':')[1].Trim('"')
})
.ToList();
results.Dump();
}
}
public class CsvItem
{
public string Email { get; set; }
public string DisplayName { get; set; }
public string Dpt { get; set; }
}
}
Your original string looks suspiciously like it was extracted from a JSON response. You should just deserialize the original JSON response directly into a DataTable with Newtonsoft.Json, ala:
//Install-Package Newtonsoft.Json
using Newtonsoft.Json;
using System.Data;
namespace Split_string_and_assign_as_table
{
class Program
{
static void Main(string[] args)
{
string json = #"[
{
""Type"": ""#Microsoft.Azure"",
""Email"": ""abc#tmail.com"",
""DisplayName"": ""abc"",
""Dpt"": ""home""
},
{
""Type"": ""#Microsoft.Azure"",
""Email"": ""xyz#tmail.com"",
""DisplayName"": ""xyz"",
""Dpt"": ""home""
}
]";
var dataTable = JsonConvert.DeserializeObject<DataTable>(json);
}
}
}

How to iterate through JObject Properties via Foreach/LINQ

I have an established JObject object. Trying to loop through it to acquire a Key/value based on anothers Key/value (example of json below with code currently stuck on)
For a tad more detail - looking to loop through "value", get the "KeyID" based on "MailState"
definitely feel like I am missing the step of filtering by MailState/ColName apparently - I have searched through threads a bunch but if someone knows of one that answered this that i was unable to find i will happily pull this down/reference it
// JSON DATA
{
"odata.metadata": "https://..com/odata/$metadata#JCJMCDXes",
"value": [
{
"KeyID": "10379",
"MailCity": "Chicago",
"MailState": "IL"
},
{
"KeyID": "9846",
"MailCity": "Chicago",
"MailState": "IL"
},
{
"KeyID": "2234",
"MailCity": "Madison",
"MailState": "WI"
}]
}
// Current code example
// class in play
public class datastorage
{
public string ID { get; set; }
public string Col { get; set; }
}
public class listData
{
public string ColName {get;set;}
}
// getVPData is a string response from a call to an API
getVPData.Replace(System.Environment.NewLine, "");
JObject jobj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(getVPData);
List<datastorage> data = new List<datastorage>();
// Loop
foreach(var r in listData) // has distinct State abeviations so only 1 occurence
{
foreach (var j in jobj) // This the right path?
{
//add KeyID into ID
data.add(new datastorage
{
ID = ,//add KeyID into ID
Col = r.ColName
});
}
}
You can use Newtonsoft.Json library to parse and loop to the items of value
here is a sample code:
dynamic json = JsonConvert.DeserializeObject(getVPData);
foreach (dynamic item in json["value"])
{
//you can access the fields inside value.
var KeyID = item["KeyID"];
var MailCity = item["MailCity"];
var MailState = item["MailState"];
//just for showing...
Console.WriteLine("KeyID:{0}, MailCity:{1}, MailState:{2}", KeyID, MailCity, MailState);
}
Let me know if the snippet works.
Straightforward ways are:
using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ConsoleApp7
{
internal class Program
{
private static void Main(string[] args)
{
var mailStates = new[] {"IL", "WI"};
var jObject = (JObject) JsonConvert.DeserializeObject(json);
var values = (JArray) jObject["value"];
// 1st way
foreach (var mailState in mailStates)
{
var key = values
.Where(v => mailState == v.SelectToken("MailState").Value<string>())
.Select(v => v.Value<string>("KeyID"))
.FirstOrDefault();
Console.WriteLine($"1st case: {mailState} - {key}");
}
/* 2nd way based on JSONPath
* api: https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm
* dox: https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html
* tester: https://jsonpath.curiousconcept.com/
*/
foreach (var mailState in mailStates)
{
var key = values.SelectTokens($"$[?(#.MailState == '{mailState}')].KeyID")
.Select(v => v.ToString())
.FirstOrDefault();
Console.WriteLine($"2nd case: {mailState} - {key}");
}
Console.ReadKey();
}
private static string json = #"
{
""odata.metadata"": ""https://cdxapiclient.palmercg.com/odata/$metadata#JCJMCDXes"",
""value"": [
{
""KeyID"": ""10379"",
""MailCity"": ""Chicago"",
""MailState"": ""IL""
},
{
""KeyID"": ""9846"",
""MailCity"": ""Chicago"",
""MailState"": ""IL""
},
{
""KeyID"": ""2234"",
""MailCity"": ""Madison"",
""MailState"": ""WI""
}]
}";
}
}

Categories

Resources