How to manipulate objects after JSON list deserialization - c#

I'm trying to work with JSON files to store a Class and I'm stuck with the deserialization.
I'm using the following NameSpace:
using System.Text.Json.Serialization;
I have a very simple class, made of 2 properties:
public EnumOfType Type { get; set; }
public double Price { get; set; }
I have 4 instances of this classe that I store in a list. When quiting the application, this list is saved in a JSON file.
string jsonString;
jsonString = JsonSerializer.Serialize(myListOfInstances);
File.WriteAllText(FileName, jsonString);
When I'm opening the Application, I want the JSON file to be loaded to recreate the instances.
I'm using the following method, which apparently works well.
string jsonString = File.ReadAllText(FileName);
myListOfInstances = JsonSerializer.Deserialize<List<MyClass>>(jsonString);
So far so good. When I check the content of the list, it is correctly populated and my 4 instances are there.
But then... how to use them?
Before the JSON, I was creating each instance (for example:)
MyClass FirstInstance = New MyClass();
FirstInstance.Type = EnumOfType.Type1;
FirstInstance.Price = 100.46;
Then I could manipulate it easily, simply calling FirstInstance.
myWindow.Label1.Content = FirstInstance.Price.ToString("C");
FirstInstance.Method1...
Now that the instances are in my list, I don't know how to manipulate them individually because I don't know how to call them.
It's probably obvious to most, but I'm still in the learning process.
Thank you for your help,
Fab

Based on how you have loaded the JSON file into your program, it looks like your variable myListOfInstances already contains all four MyClass objects ready to go. At this point you can use List accessors (or Linq if you want to be fancy) and do things such as the following:
myListOfInstances[0] //Gives you the first item in the list accessed by index
myListOfInstances.First() //Gives you the first item in the list (using linq)
foreach(var item in myListOfInstances) {
// this will iterate through all four items in the list storing each instance in
//the 'item' variable
}
etc...
EDIT: From my comment below. If you need to access values in a a list directly, you can search for specific conditions in the list using linq with the 'Where' method. The syntax is something like this:
myListOfInstances.Where(x => x.Property == SomePropertyToMatch)

Related

RestSharp v107 Parameter question adding nested JSON / objects

I'm attempting to update my RestSharp calls to v107 and noticed a slight difference in how parameters are added. What I have working in 106 doesn't appear to work in 107.
What I have is that I'm adding an object with nested objects to a POST request. My object looks like this:
class CallParameters
{
public CallResources Resources {get;set;}
public CallFilters Filters {get;set;}
}
class CallResources
{
public bool IncludeOrgData {get;set;}
public bool IncludeDemoData {get;set}
}
class CallFilters
{
public string LastModified {get;set}
public List<string> Users {get;set;}
}
I know I can serialize that (once I set the fields) to look like:
{"Resources" : {"IncludeOrgData" : true, "IncludeDemoData" : true}, "Filters" : { "LastModifed" : "1/1/21", "Users" : ["User1", User2", "User3"]}}
With 106, I was able to create my rest call by serializing my object class to a string and adding it via AddJsonBody like this
CallParameters NewCallParameters = new CallParameters();
...Set the fields within the class...
string JsonBody = JsonConvert.SerializeObject(NewCallParameters);
var request = new RestRequest { Method = Method.POST };
var client = new RestClient();
var response = client.Execute(request.AddJsonBody(JsonBody));
Worked great. Passed over all the parameters right
In 107 I know it's slightly different. Using the same serialize and AddJsonObject, I show a single parameter is added with no name, and the value of the whole serialized object. This causes my call to return
The request is invalid - An error has occurred
If I use 'AddObject' to add the entire class CallParamters class as a whole, when I trace through things and look at my request parameters collection, I do see two parameters listed. They are named correctly ('Resources' and 'Filters') but the values are 'MyApp.CallResources' and 'MyApp.CallFilters'. It's like they are not serializing when adding. This returns:
At least one additional resource is required: IncludeOrgData, IncludeDemoData
If I add the objects separately as 'CallResourses' and 'CallFilters', I wind up with four parameters names for all the fields within. Value is correct aside from the Users List, which just shows 'System.Collections.Generic.List[System.String]'. Also having four parameters doesn't seem right either and the call also fails with invalid parameters. This returns
The request is invalid - Resources field is required
I have experimented with 'AddParamter' some. If I add the whole class as a parameter I'm not sure what to name it. Also the call fails since it has no name. If I add them separately like this:
string MyResources = JsonSerializer.Serialize(NewCallParameters.Resources);
string MyFilters = JsonSerializer.Serialize(NewCallParameters.Filters);
request.AddParamter("Resources", MyResources );
request.AddParamter("Filters", MyFilters);
I do get two parameters named correctly. The values look good and show all the entries. The return result though from the Rest service I'm calling states
At least one additional resource is required: IncludeOrgData, IncludeDemoData'
So it seems it's not seeing the values in the 'Resources' parameter. Do I need to add each as a separate parameter? How would I add nested parameters that way? I feel like I'm close but not getting something.
It helps to read the documentation. RestSharp has embedded serialization. Don't serialize your object when using AddJsonBody. As you need Pascal-case fields, you'd need to either change JSON options for the default serializer or use the RestSharp.Serializers.NewtonsoftJson package.
If you prefer to add a pre-serialized string, use AddStringBody

How to Pass a JSON Values to Nunit Testcase Data

I am reading a JSON file and stores the values as a object
Car : Name, Cost, Yearmodel
Now I need to pass these 3 JSON object values to this Testcasedata.
Likewise I need to pass multiple values while reading the JSON file data.
Any idea explaining on how to do this?
public string JSONParser()
{
StreamReader r = new StreamReader("ESAggregationQuery.json");
string jsonString = r.ReadToEnd();
m = JsonConvert.DeserializeObject<AggModel>(jsonString);
carName = m.carName;
costPrice = m.costPrice;
modelYear = m.modelYear;
return "1";
}
private static IEnumerable<TestCaseData> ESAggregativeTestData
{
get
{
yield return new TestCaseData[] { m.carName, m.costPrice, m.modelYear };
}
}
```
You don't "pass" data to your TestCaseData item. The data has to originate there. Try making the following changes...
Call your JSONParser from the getter of ESAggregativeTestData or add the code in there.
Change your yield statement to return a new TestCaseData, not an array. That's not an NUnit thing... it's just how IEnumerable works. If your JSON file, now or in the future, contains multiple test items, you will need to put all this in a loop.
You have not shown us your test code, which uses the data source. To work with the source you have given, it should take three arguments of the appropriate type.
Suggestion... next time provide more complete source code that shows what you are trying to do.

C# - Deserialize Json to Dictionary

Im trying to convert my List code lines to Dictionary since as i understand they are faster, and more easy to manage, like i can get its value with its key value rather than just index.
Thus, im trying to modify my json-deserializing code (which actually,Newtonsoft's), but i have no idea how can i convert raw json to dictionary with my own format.
Dictionary <string,Tag>
Tag class is my own class with member variables, contains tag informations.
it doesnt includes functions for sure.
String should be Tag.Name, a string member variable.
//TODO: Fix "Hacky" solution to deserialized lines into Dictionary
//Which means : Raw Json -> Deserialized data -> List -> Dictionary is very hacky in my perspective
//Should be : Raw Json -> Deserialized data -> Dictionary, but i have no idea to convert directly like that
else if (filename.Contains(".json")) // very janky method to detect json file. dont depend on file extension - rather depend on actual file format.
{
string line = String.Join("", Lines);
List<Tag> lv_list = new List<Tag>();
Dictionary<string,Tag> lv_dict = new Dictionary<string, Tag>();
lv_list = JsonConvert.DeserializeObject<List<Tag>>(line);
gVar.Tags.AddRange(lv_list);
gVar.gTagCount += lv_list.Count();
for (int i = 0; i < lv_list.Count(); ++i)
{
gVar.Tags2.Add(lv_list[i].Name, lv_list[i]);
}
int lv_tagcount = 1;
for (int i = 0; i < gVar.gTagCount; ++i)
{
gVar.Tags[i].TagCount = lv_tagcount;
++lv_tagcount;
}
I wouldn't bother deserializing directly to a Dictionary: if the JSON is formatted like an array, go ahead and deserialize it to a List first. There's nothing "hacky" about the two-step process.
Use LINQ's ToDictionary() method to get a dictionary from a list:
Dictionary<string,Tag> lv_dict = JsonConvert.DeserializeObject<List<Tag>>(line)
.ToDictionary(tag => tag.Name);
You seem to have a habit of initializing a variable with an empty collection that never gets used, and then setting the variable to some other value. This isn't helpful: just declare and set the variable at the same time. But based on this pattern I'm wondering if gVar is an object you're trying to initialize even though your code looks like it's trying to add things to that variable. Do you really want to do something more like this?
gVar.Tags2 = JsonConvert.DeserializeObject<List<Tag>>(line)
.ToDictionary(tag => tag.Name);
I'd also question whether the TagCount property is a good pattern. It looks like you're trying to make each Tag explicitly aware of its own position in the collection that it's found in. This is a code smell. Perhaps now that you're using a Dictionary that won't be necessary because you can look up the tag by its name in the Dictionary?

Convert dictionary to custom json object c#

Here is something i couldn't get around my head even after spending a few hours. Hoping someone will direct me.
I have a Dictionary object which I want to convert to JSON.
Sample code:
Dictionary<String,String> users = new Dictionary<String,String>();
Users look something like this:
{[name1, department1],[name2, department2]}
Here is the custom JSON format for each user:
public class User
{
public string name;
public string dept;
// has get and set methods for each.
}
How can I write the users Dictionary as a JSON object of type user?
Ideally if the dictionary represents a collection of user objects then it in fact should be a collection of user objects. But failing that, it can easily be transformed into one:
users.Select(u => new user { name = u.Key, dept = u.Value });
The resulting enumerable can then be serialized using pretty much any serializer.

Databinding question: DataGridView <=> XDocument (using LINQ-to-XML)

Learning LINQ has been a lot of fun so far, but despite reading a couple books and a bunch of online resources on the topic, I still feel like a total n00b. Recently, I just learned that if my query returns an Anonymous type, the DataGridView I'm populating will be ReadOnly (because, apparently Anonymous types are ReadOnly.)
Right now, I'm trying to figure out the easiest way to:
Get a subset of data from an XML file into a DataGridView,
Allow the user to edit said data,
Stick the changed data back into the XML file.
So far I have Steps 1 and 2 figured out:
public class Container
{
public string Id { get; set; }
public string Barcode { get; set; }
public float Quantity { get; set; }
}
// For use with the Distinct() operator
public class ContainerComparer : IEqualityComparer<Container>
{
public bool Equals(Container x, Container y)
{
return x.Id == y.Id;
}
public int GetHashCode(Container obj)
{
return obj.Id.GetHashCode();
}
}
var barcodes = (from src in xmldoc.Descendants("Container")
where src.Descendants().Count() > 0
select
new Container
{
Id = (string)src.Element("Id"),
Barcode = (string)src.Element("Barcode"),
Quantity = float.Parse((string)src.Element("Quantity").Attribute("value"))
}).Distinct(new ContainerComparer());
dataGridView1.DataSource = barcodes.ToList();
This works great at getting the data I want from the XML into the DataGridView so that the user has a way to manipulate the values.
Upon doing a Step-thru trace of my code, I'm finding that the changes to the values made in DataGridView are not bound to the XDocument object and as such, do not propagate back.
How do we take care of Step 3? (getting the data back to the XML) Is it possible to Bind the XML directly to the DataGridView? Or do I have to write another LINQ statement to get the data from the DGV back to the XDocument?
Suggstions?
So I think the problem that you have is that there is no relationship between the objects you are binding to and the XML source document.
What you are doing is creating a heap of objects, pushing in some strings and a float, and then binding the grid view to that list of objects. All the objects know is that some data was given in the constructor, it has no knowledge of where that data come from. When you call "select new something()" you are creating a new object, that new object doesn't know or care that it was created using LINQ to XML...
The easiest way I can think of to resolve it would be to change the setter of your container properties so that they load the XML, change the element they are supposed to represent, and then save the xml again. Perhaps giving the Container a reference to the element or document would make this easier.
The other way would be to hook into the grid view events so that when rows are edited you can capture the changes and write them to the XML file.

Categories