ReadFromJsonAsync<T>() method does not serialize 2 level nested classes - c#

I am using .aspnetcore 6 and the response object is not correctly searialized.
public class AvailableColumns
{
public List<Column> Columns { get; } = new List<Column>();
}
public class Column
{
public string Name { get; set; }
public List<Value> Values { get; set; } = new List<Value>();
}
public class Value
{
public string InternalValue { get; set; }
public string DisplayName { get; set; }
}
That way the code is read:
// Before this line there are 20 columns in the object T.
response.Data = await response.Content.ReadFromJsonAsync<T>();
// After response.Data has 0 columns
How to fix it?

Not sure how is your api like, be sure your api actually returns AvailableColumns model with data.
Be sure add the set accessor for the Columns property.
public class AvailableColumns
{
public List<Column> Columns { get; set; } = new List<Column>(); //add set accessor here
}

Related

Update list values after update root class object

I have the following classes:
public class Class_A
{
public string my_field { get; set; }
public int id { get; set; }
// etc...
}
public class Class_B
{
public string my_field { get; set; }
public Class_A field_A { get; set; }
// etc...
}
public class Class_C
{
public string my_field { get; set; }
public Class_A field_A { get; set; }
// etc...
}
List<Class_A> list_A = new List<Class_A>(); //and then populate it
List<Class_B> list_B = new List<Class_B>(); //and then populate it
List<Class_C> list_C = new List<Class_C>(); //and then populate it
And then, when I update some element of list_A, for example
Class_A old_a, new_a;
old_a = list_A.Where("some condition").FirstOrDefault();
new_a = new Class_A();//and then initialize it
list_A[list_A.FindIndex(x => x.Equals(old_a))] = new_a;
I need, that all elements of list_B and list_C, which field Class_A equals old_a will be update to new_a.
1. What is the best way to do this? Now I have following variant, but I think, that it's could be better:
list_B.Where(x => x.Class_A.Equals(old_a)).ForEach(x => x.Class_A = new_a);
2. What is the best way to update all values, if I'll have this code?
public class Class_D
{
public string my_field { get; set; }
public List<Class_A> list_A { get; set; }
// etc...
}
List<Class_D> list_D = new List<Class_D>(); //and then populate it
Have a look at ObservableCollection and Item PropertyChanged
You can make from your list_A an observable collection when can be received by Class_B and Class_C.

Show DataGrid columns as sum of two classes

I have DataGrid and I would like to show data from two class:
[DataContract]
public class File
{
[DataMember]
public List<FileRow> radky { get; set; }
}
public class FileRow
{
public int AMOUNT { get; set; }
public string NAME { get; set; } }
//some others variables
}
and
[DataContract]
public class WebService
{
[DataMember]
public List<WSRow> radky { get; set; }
}
public class WSRow
{
public int AMOUNT { get; set; }
public string NAME { get; set; } }
//some others variables
}
These two classes provides data in NAME and AMOUNT variables. Now I need to get data with same NAME in both classes, sum theirs AMOUNT and show in DataGrid. Is here any way how can achieve that? Should I create new class?
You should create a new class in which you calculate the sum of both object's amountvariable. Then you can bind a List<SumOfAmounts> to the ItemsSource property on your DataGrid.
Like this:
SumOfAmounts class :
public class SumOfAmounts
{
private FileRow _fileRow;
private WSRow _webRow;
public int Sum { get; set; }
public SumOfAmounts(FileRow filerow, WSRow webrow)
{
_fileRow = filerow;
_webRow = webrow;
Sum = _fileRow.AMOUNT + _webRow.AMOUNT;
}
}
In some other class where you'll store all the sums :
public class SumStorage
{
// ...
public List<SumOfAmounts> Sums { get; set; }
// ...
public SumStorage(File file, WebService webSvc)
{
Sums = new List<SumOfAmounts>();
foreach(var row in file.radky)
{
var webRow = webSvc.radky.FirstOrDefault(x => x.NAME == row.NAME);
if(webRow != null)
Sums.Add(new SumOfAmounts(row, webRow));
}
}
}
Now you can bind the datagrid ItemsSource property to the Sums property on a SumStorage object.
My imagination is pretty limited for class naming but I hope you get the point.
Also, you should respect C# naming conventions.

how to delete variables instantiated by constructor

public class Row
{
//row
public string name { get; set; }
public string height { get; set; }
public bool sortable { get; set; }
public string classes { get; set; }
public string color { get; set; }
public string data { get; set; }
}
private static List<object> dataList = new List<object>()
{
new Row()
{
name= "Milestones",
height= "3em",
sortable= false,
classes= "gantt-row-milestone",
color= "#45607D",
}
new Row()
{
name= "Milestones",
height= "3em",
color= "#45607D",
}
}
I am trying to create two objects with different number of variables
and my problem is that I don't now how to delete or escape variables instantiated by default (with 0 or null)
There is no way to delete Fields from an object. But you can design your classes as you need.
public class GenericRow
{
public string name { get; set; }
public string height { get; set; }
public string color { get; set; }
public string data { get; set; }
}
public class DetailedRow : GenericRow
{
public bool sortable { get; set; }
public string classes { get; set; }
}
And instantiate your objects as following.
private static List<GenericRow> dataList = new List<GenericRow>()
{
new DetailedRow ()
{
name= "Milestones",
height= "3em",
sortable= false,
classes= "gantt-row-milestone",
color= "#45607D",
},
new GenericRow()
{
name= "Milestones",
height= "3em",
color= "#45607D",
}
};
Just use null to indicate a 'deleted' property:
var row = (Row)dataList[0];
if (row.name == null)
// name is deleted
else
DoSomething(row.name);
For value types use Nullable<>:
public bool? sortable { get; set; }
if (row.sortable == null)
// sortable is deleted
else
DoSomething(row.sortable.Value);

Set element name same as RootElement attribute

[XmlRootAttribute("ls")]
public class Request<T>
{
[XmlAttribute("ver")]
public string Version { get; set; }
[XmlElement("hdr")]
public Header Header { get; set; }
[XmlElement(Type = typeof(class2), ElementName = "ChildClass")]
public T Data { get; set; }
}
[XmlRoot("ChildClass")]
public class class2
{
[XmlElement("login")]
public string Property1{ get; set; }
}
[XmlRoot("ChildClass3")]
public class class3
{
[XmlElement("User")]
public string Property1{ get; set; }
}
When Request<class2> is serialized , Element name is "Data". I want element Name to be "ChildClass". when Request<class3> is serialized , Element name should be "ChildClass3".
How can i do that
As far as I know the element name must be known at compile time and so you can't try and use the Data objects XmlRoot or class name or similar as these aren't known at compile time. You'll need to define every possible type that you could expect Data to be set to. As follows:
[XmlRoot("ls")]
public class Request
{
[XmlAttribute("ver")]
public string Version { get; set; }
[XmlElement("ChildClass2",typeof(class2))]
[XmlElement("ChildClass3",typeof(class3))]
public object Data { get; set; }
}
public class class2
{
[XmlElement("login")]
public string Property1 { get; set; }
}
public class class3
{
[XmlElement("User")]
public string Property1 { get; set; }
}
The following two objects:
var exampleObject = new Request
{
Version = "versionExample",
Data = new class2 { Property1 = "property1Example" }
};
var exampleObject2 = new Request
{
Version = "versionExample",
Data = new class3 { Property1 = "property1Example" }
};
Then serialized to:
<ls ver="versionExample">
<ChildClass2>
<login>property1Example</login>
</ChildClass2>
</ls>
<ls ver="versionExample">
<ChildClass3>
<User>property1Example</User>
</ChildClass3>
</ls>

how to run through each class item and set value to it [duplicate]

This question already has an answer here:
how to make foreach loop in MVC to set new value to items.
(1 answer)
Closed 9 years ago.
I have a class that contains some items of different datatypes. I want to set value to each item and send it from controller to view, and view data in text boxes.
Is it possible to loop through these the objects in the class, check the data type of it, and then assign a value to each one?
Here's a pseudo code example of what I'm trying to accomplish
foreach item in class ItemProduction
{
if data type == string
value of item = " " ;
if data type == int
value of item = 0 ;
if data type == DAte
value of item = date of today ;
}
Here my class definition and the objects inside it.
public class ItemProduction : Common, IDataErrorInfo, INotifyPropertyChanged
{
public string Main{ get; set; }
public DateTime itemDate { get; set; }
public string ItemType{ get; set; }
public string productionId{ get; set; }
public int Quantity { get; set; }
public string Status { get; set; }
}
Its not a good idea to set value based on datatype using if statement.
If you want to simply pass an object of this ItemProduction class as a model to your view, simply have a constructor for your ItemProduction class and initialize your model value with default values and send it to your view
public class ItemProduction
{
public string Main { get; set; }
public DateTime itemDate { get; set; }
public string ItemType { get; set; }
public string productionId { get; set; }
public int Quantity { get; set; }
public string Status { get; set; }
public ItemProduction()
{
Main = "main value";
itemDate =DateTime.Now;
ItemType ="type";
productionId ="productionId";
Quantity =5;
Status = "status";
}
}
if you want to dynamically set values using reflection, refer this question:
c# - How to iterate through classes fields and set properties
You can try this:
List<ItemProduction> items = Enumerable.Range(1, 5).Select(i => new ItemProduction
{
Main = string.Empty,
ItemDate = DateTime.UtcNow,
ItemType = string.Empty,
ProductionId = string.Empty,
Quantity = 0,
Status = string.Empty
}).ToList();
This will create 5 instances of ItemProduction and initialize all of them with the values given as per your need.
The best bet is to have a constructor in your ItemProduction model as below:
public class ItemProduction
{
public string Main { get; set; }
public DateTime TtemDate { get; set; }
public string ItemType { get; set; }
public string ProductionId { get; set; }
public int Quantity { get; set; }
public string Status { get; set; }
public ItemProduction()
{
this.Main = string.Empty;
this.ItemDate = DateTime.UtcNow;
this.ItemType = string.Empty;
this.ProductionId = string.Empty;
this.Quantity = 0;
this.Status = string.Empty;
}
}
So, the above code will simply become
List<ItemProduction> items= Enumerable.Range(1, 5).Select(i => new ItemProduction()).ToList();
Note:
It is a convention to have class properties as PascalCase, so I have amended your class with nest naming convention.You can go through this Property Naming Guidelines.
Update:
If you have many properties, you can do this using reflection as below:
public static T Init<T>(T TObject)
{
var properties = TObject.GetType().GetProperties();
foreach (var property in properties)
{
if (property.PropertyType.Equals(typeof(string)))
{
property.SetValue(TObject, string.Empty);
}
else if (property.PropertyType.Equals(typeof(int)))
{
property.SetValue(TObject, 0);
}
else if (property.PropertyType.Equals(typeof(DateTime)))
{
property.SetValue(TObject, DateTime.UtcNow);
}
}
return TObject;
}

Categories

Resources