I am trying to create an json data similar to this https://cdn.jsdelivr.net/gh/highcharts/highcharts#v7.0.0/samples/data/world-mortality.json
The current output I am getting is like this. The model name is being displayed and child does not seems to work. is t possible to remove the model field name on the serialize?
[{Name:"ABC",
Firstchild:[{Name:"AIR IMPORT",
Secondchild:[{NAME:"SCMBOA00052997",VALUE:69.7500},
{NAME:"SH123",VALUE:-100.0000},
{NAME:"SH456",VALUE:50.0000},
{NAME:"SH789",VALUE:150.0000}]
}]
}{Name:"DEF",
Firstchild:[{Name:"AIR IMPORT",
Secondchild:[{NAME:"SCMBOA00052997",VALUE:69.7500},
{NAME:"SH111",VALUE:-10.0000},
{NAME:"SH222",VALUE:80.0000},
{NAME:"SH333",VALUE:160.0000}]
}]
}]
What I need is like this
{
"ABC": {
"AIR IMPORT":{
"SH123": -100.0000,
"SH456": 50.0000,
"SH789": 150.0000
}
},
"DEF": {
"AIR IMPORT":{
"SH111": -10.0000,
"SH222": 80.0000,
"SH333": 160.0000
}
}
}
MODEL
public class ParentTreemap
{
public string Name { get; set; }
public List<FirstChildTreemap> Firstchild { get; set; }
}
public class FirstChildTreemap
{
public string Name { get; set; }
public List<SecondChildTreemap> Secondchild { get; set; }
}
public class SecondChildTreemap
{
[JsonProperty]
public string Name { get; set; }
[JsonProperty]
public decimal Value { get; set; }
}
Controller
var parent = treemaplist.Where(s => s.Parent == 0);
List<ParentTreemap> plist = new List<ParentTreemap>();
foreach (var item in parent)
{
var firstchild = treemaplist.Where(s => s.Parent == item.Id && s.Value==0);
List<FirstChildTreemap> flist = new List<FirstChildTreemap>();
foreach (var fitem in firstchild)
{
var secondchild = treemaplist.Where(s => s.Parent == fitem.Id && s.Value!=0);
List<SecondChildTreemap> slist = new List<SecondChildTreemap>();
foreach (var sitem in secondchild)
{
SecondChildTreemap model = new SecondChildTreemap();
model.Name = sitem.Name;
model.Value = sitem.Value;
slist.Add(model);
}
FirstChildTreemap child = new FirstChildTreemap();
child.Name = fitem.Name;
child.Secondchild = slist;
flist.Add(child);
}
ParentTreemap pmodel = new ParentTreemap();
pmodel.Name = item.Name;
pmodel.Firstchild = flist;
plist.Add(pmodel);
}
var stringWriter = new StringWriter();
var serializer = new JsonSerializer();
using (var writer = new JsonTextWriter(stringWriter))
{
writer.QuoteName = false;
serializer.Serialize(writer, plist);
}
ViewData["result"] = stringWriter;
Related
Is there any scope for improvement in my program which converts flat db entity to a tree data structure.
I don't want to loose the Generic flexibility as i should be able to use the same method for any other DBEntity class
Interface for db entity class
public interface IDbEntityNode
{
int Id { get; set; }
int ParentId { get; set; }
}
Example of db Entity class
public class ExceptionCategory :IDbEntityNode
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
public ExceptionCategory(string data, int id, int parentId)
{
Id = id;
ParentId = parentId;
Data = data;
}
}
Generic class which holds the structure of tree node
public class GenericNode<T>
{
public T NodeInformation { get; set; }
public GenericNode<T> Parent { get; set; }
public List<GenericNode<T>> Children { get; set; } = new List<GenericNode<T>>();
}
Method which coverts flat list to tree
public static List<GenericNode<T>> CreateGenericTree<T>(List<T> flatDataObject,Func<T,bool> IsRootNode) where T : IDbEntityNode
{
var lookup = new Dictionary<int, GenericNode<T>>();
var rootNodes = new List<GenericNode<T>>();
var noOfElements = flatDataObject.Count;
for (int element = 0; element < noOfElements; element++)
{
GenericNode<T> currentNode;
if (lookup.TryGetValue(flatDataObject[element].Id, out currentNode))
{
currentNode.NodeInformation = flatDataObject[element];
}
else
{
currentNode = new GenericNode<T>() { NodeInformation = flatDataObject[element] };
lookup.Add(flatDataObject[element].Id, currentNode);
}
if (IsRootNode(flatDataObject[element]))
{
rootNodes.Add(currentNode);
}
else
{
GenericNode<T> parentNode;
if (!lookup.TryGetValue(flatDataObject[element].ParentId, out parentNode))
{
parentNode = new GenericNode<T>();
lookup.Add(flatDataObject[element].ParentId, parentNode);
}
parentNode.Children.Add(currentNode);
currentNode.Parent = parentNode;
}
}
return rootNodes;
}
Execution:
private static void Main(string[] args)
{
List<IDbEntityNode> flatDataStructure = new List<IDbEntityNode>
{
new ExceptionCategory("System Exception",1,0),
new ExceptionCategory("Index out of range",2,1),
new ExceptionCategory("Null Reference",3,1),
new ExceptionCategory("Invalid Cast",4,1),
new ExceptionCategory("OOM",5,1),
new ExceptionCategory("Argument Exception",6,1),
new ExceptionCategory("Argument Out Of Range",7,6),
new ExceptionCategory("Argument Null",8,6),
new ExceptionCategory("External Exception",9,1),
new ExceptionCategory("Com",10,9),
new ExceptionCategory("SEH",11,9),
new ExceptionCategory("Arithmatic Exception",12,1),
new ExceptionCategory("DivideBy0",13,12),
new ExceptionCategory("Overflow",14,12),
};
var tree = CreateGenericTree(flatDataStructure, IsRootNode);
}
private static bool IsRootNode(IDbEntityNode dbEntity)
{
bool isRootNode = false;
if (dbEntity.ParentId == 0 )
isRootNode = true;
return isRootNode;
}
Created a generic approach, table objects need to follow the dbSet interface and TreeNode objects need to follow the ITreeNode. I used binarySerach to make this as fast as possible. No recursion needed. The logic ensures that you do not need to have the items in a particular order. I did not throw an error when out of the loop when there are still unassigned objects, this can be easy added.
using System.Collections.Generic;
public interface ITreeNode
{
string ParentId { get; set; }
string Id { get; set; }
dbItem item { get; set; }
List<ITreeNode> Nodes { get; set; }
}
public class TreeNode : ITreeNode
{
public TreeNode()
{ }
public string ParentId { get; set; }
public string Id { get; set; }
public dbItem item { get; set; }
public List<ITreeNode> Nodes { get; set; }
}
public class dbItem
{
public string ParentId { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
class app
{
static void Main()
{
List<dbItem> dbSet = new List<dbItem>();
dbSet.Add(new dbItem() { Id = "5", ParentId = "1", Name = "Jan" });
dbSet.Add(new dbItem() { Id = "25", ParentId = "1", Name = "Maria" });
dbSet.Add(new dbItem() { Id = "1", Name = "John" });
dbSet.Add(new dbItem() { Id = "8", ParentId = "2", Name = "Cornelis" });
dbSet.Add(new dbItem() { Id = "2", Name = "Ilse" });
dbSet.Add(new dbItem() { Id = "3", Name = "Nick" });
dbSet.Add(new dbItem() { Id = "87", ParentId = "5", Name = "Rianne" });
dbSet.Add(new dbItem() { Id = "67", ParentId = "3000", Name = "Rianne" });
dbSet.Add(new dbItem() { Id = "3000", Name = "Max" });
List<TreeNode> result = BuildTree<TreeNode>(dbSet);
}
private class ParentComparer<T> : IComparer<ITreeNode> where T: ITreeNode
{
public int Compare(ITreeNode x, ITreeNode y)
{
if (x.ParentId == null) return -1; //have the parents first
return x.ParentId.CompareTo(y.ParentId);
}
}
private class IdComparer<T> : IComparer<ITreeNode> where T : ITreeNode
{
public int Compare(ITreeNode x, ITreeNode y)
{
return x.Id.CompareTo(y.Id);
}
}
static private List<T> BuildTree<T> (List<dbItem> table) where T: ITreeNode, new()
{
//temporary list of tree nodes to build the tree
List<T> tmpNotAssignedNodes = new List<T>();
List<T> tmpIdNodes = new List<T>();
List<T> roots = new List<T>();
IComparer<T> pc = (IComparer<T>) new ParentComparer<T>();
IComparer<T> ic = (IComparer<T>) new IdComparer<T>();
foreach (dbItem item in table)
{
T newNode = new T() { Id = item.Id, ParentId = item.ParentId, item = item };
newNode.Nodes = new List<ITreeNode>();
T dummySearchNode = new T() { Id = item.ParentId, ParentId = item.ParentId };
if (string.IsNullOrEmpty(item.ParentId))
roots.Add(newNode);
else
{
int parentIndex = tmpIdNodes.BinarySearch(dummySearchNode, ic);//Get the parent
if (parentIndex >=0)
{
T parent = tmpIdNodes[parentIndex];
parent.Nodes.Add(newNode);
}
else
{
parentIndex = tmpNotAssignedNodes.BinarySearch(dummySearchNode, pc);
if (parentIndex < 0) parentIndex = ~parentIndex;
tmpNotAssignedNodes.Insert(parentIndex, newNode);
}
}
dummySearchNode.ParentId = newNode.Id;
//Cleanup Unassigned
int unAssignedChildIndex = tmpNotAssignedNodes.BinarySearch(dummySearchNode, pc);
while (unAssignedChildIndex >= 0 && unAssignedChildIndex < tmpNotAssignedNodes.Count)
{
if (dummySearchNode.ParentId == tmpNotAssignedNodes[unAssignedChildIndex].ParentId)
{
T child = tmpNotAssignedNodes[unAssignedChildIndex];
newNode.Nodes.Add(child);
tmpNotAssignedNodes.RemoveAt(unAssignedChildIndex);
}
else unAssignedChildIndex--;
}
int index = tmpIdNodes.BinarySearch(newNode, ic);
tmpIdNodes.Insert(~index, newNode);
}
return roots;
}
}
Try following solution using recursive code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
public static List<IDbEntityNode> flatDataStructure = null;
public static Dictionary<int?, List<IDbEntityNode>> dict = null;
static void Main(string[] args)
{
flatDataStructure = new List<IDbEntityNode>
{
new ExceptionCategory("System Exception",1,0),
new ExceptionCategory("Index out of range",2,1),
new ExceptionCategory("Null Reference",3,1),
new ExceptionCategory("Invalid Cast",4,1),
new ExceptionCategory("OOM",5,1),
new ExceptionCategory("Argument Exception",6,1),
new ExceptionCategory("Argument Out Of Range",7,6),
new ExceptionCategory("Argument Null",8,6),
new ExceptionCategory("External Exception",9,1),
new ExceptionCategory("Com",10,9),
new ExceptionCategory("SEH",11,9),
new ExceptionCategory("Arithmatic Exception",12,1),
new ExceptionCategory("DivideBy0",13,12),
new ExceptionCategory("Overflow",14,12),
};
dict = flatDataStructure.GroupBy(x => x.ParentId, y => y)
.ToDictionary(x => x.Key, y => y.ToList());
GenericNode<IDbEntityNode> root = new GenericNode<IDbEntityNode>();
root.Parent = null;
int rootId = 0;
root.NodeInformation.Id = rootId;
root.NodeInformation.name = "root";
root.NodeInformation.ParentId = null;
CreateGenericTree(root);
}
public static void CreateGenericTree<T>(GenericNode<T> parent) where T : IDbEntityNode, new()
{
if (dict.ContainsKey(parent.NodeInformation.Id))
{
List<IDbEntityNode> children = dict[parent.NodeInformation.Id];
foreach (IDbEntityNode child in children)
{
GenericNode<T> newChild = new GenericNode<T>();
if (parent.Children == null) parent.Children = new List<GenericNode<T>>();
parent.Children.Add(newChild);
newChild.NodeInformation.Id = child.Id;
newChild.NodeInformation.ParentId = parent.NodeInformation.Id;
newChild.NodeInformation.name = child.name;
newChild.Parent = parent;
CreateGenericTree(newChild);
}
}
}
}
public class GenericNode<T> where T : new()
{
public T NodeInformation = new T();
public GenericNode<T> Parent { get; set; }
public List<GenericNode<T>> Children { get; set; }
}
public class IDbEntityNode
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string name { get; set; }
}
public class ExceptionCategory : IDbEntityNode
{
public string Data { get; set; }
public ExceptionCategory(string data, int id, int parentId)
{
Id = id;
ParentId = parentId;
Data = data;
}
}
}
I would like to make a method to print a LINQ (table) with all its properties and values to the console.
I'm currently trying to do this via the System.Reflection.GetType().GetProperties()
What I think is going wrong is the type of parameter I try to send to the method. If possible this should be a var so I can use this method with any class list. (not sure if this is possible)
The issue is with the printtabel() method.
I started from:
Print a table with LINQ
namespace LINQ
{
class Program
{
public class Bier
{
public int BierNr { get; set; }
public string Biernaam { get; set; }
public float Alcohol { get; set; }
public Brouwer Brouwer { get; set; } //associatie met een brouwer
public override string ToString() { return Biernaam + ": " + Alcohol + "% alcohol"; }
}
public class Brouwer
{
public int BrouwerNr { get; set; }
public string Brouwernaam { get; set; }
public bool Belgisch { get; set; }
public List<Bier> Bieren { get; set; }
public override string ToString() { return "Brouwerij " + Brouwernaam + " (" + (Belgisch ? "Belgisch" : "Niet Belgisch") + ")"; }
}
public class Brouwers
{
public List<Brouwer> GetBrouwers()
{
List<Brouwer> lijst = new List<Brouwer>();
Brouwer palm = new Brouwer { BrouwerNr = 1, Brouwernaam = "Palm", Belgisch = true };
palm.Bieren = new List<Bier> {
new Bier {BierNr=1,Biernaam="Palm Dobbel", Alcohol=6.2F, Brouwer=palm},
new Bier {BierNr=2, Biernaam="Palm Green", Alcohol=0.1F, Brouwer=palm},
new Bier {BierNr=3, Biernaam="Palm Royale", Alcohol=7.5F, Brouwer=palm}
};
lijst.Add(palm);
Brouwer hertogJan = new Brouwer { BrouwerNr = 2, Brouwernaam = "Hertog Jan", Belgisch = false };
hertogJan.Bieren = new List<Bier> {
new Bier{ BierNr=4, Biernaam="Hertog Jan Dubbel", Alcohol=7.0F, Brouwer=hertogJan},
new Bier{ BierNr=5, Biernaam="Hertog Jan Grand Prestige", Alcohol=10.0F, Brouwer=hertogJan} };
lijst.Add(hertogJan);
Brouwer inBev = new Brouwer { BrouwerNr = 3, Brouwernaam = "InBev", Belgisch = true };
inBev.Bieren = new List<Bier> {
new Bier { BierNr=6, Biernaam="Belle-vue kriek L.A", Alcohol=1.2F, Brouwer=inBev},
new Bier { BierNr=7, Biernaam="Belle-vue kriek", Alcohol=5.2F, Brouwer=inBev},
new Bier { BierNr=8, Biernaam="Leffe Radieuse", Alcohol=8.2F,Brouwer=inBev},
new Bier { BierNr=9, Biernaam="Leffe Triple", Alcohol=8.5F,Brouwer=inBev} };
lijst.Add(inBev);
//return new List<Brouwer> { palm, hertogJan, inBev };
return lijst;
}
}
static void Main(string[] args)
{
var brouwers = new Brouwers().GetBrouwers();
var belgischeBrouwerijenMet3Bieren =
from brouwer in brouwers
where brouwer.Belgisch && brouwer.Bieren.Count == 3
select brouwer;
foreach (var brouwer in belgischeBrouwerijenMet3Bieren)
Console.WriteLine(brouwer.Brouwernaam);
var bieren = from brouwer in brouwers
from bier in brouwer.Bieren
select bier;
string vorigeBrouwer = "";
foreach (var bier in bieren)
{
if (bier.Brouwer.ToString() != vorigeBrouwer)
{
Console.WriteLine(bier.Brouwer);
vorigeBrouwer = bier.Brouwer.ToString();
}
Console.WriteLine($"\t {bier.ToString()}");
}
Console.WriteLine(printtabel(belgischeBrouwerijenMet3Bieren));
Console.ReadLine();
}
public string printtabel(IEnumerable<Brouwer> response)
{
StringBuilder sb = new StringBuilder();
foreach (PropertyInfo prop in response.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
object value = prop.GetValue(response, new object[] { });
sb.AppendLine($"{prop.Name} = {value}");
}
return sb.ToString();
}
}
}
Error CS0120 An object reference is required for the non-static field, method, or property 'Program.printtabel(IEnumerable)' LINQ 204 Active
You can fix it by writing:
public static string printtabel(IEnumerable<Brouwer> response)
You are calling a non static method from a static method. Set printtabel static and this error should disappear.
I have the domain classes separated from the ones I use in the views, so when retrieving data I have to map the domain classes to the view ones.
Until now this have been straight forward, but now I have a case in which I need to map parent-child classes from the domain to parent-child classes on the view.
Using foreach structures works fine, but I have quite a few linq methods that do the mapping between domain and view classes, that need to be refactored to accomodated to the new requirements and would be faster if I knew how to do it with linq. Thanks in advance.
As an example of what I'm trying to accomplish see code below:
In the repository I have the classes:
public class Parent
{
public int ParentId { get; set; }
public string ParentName { get; set; }
};
public class ChildA : Parent
{
public string ChildPropertyA { get; set; }
};
public class ChildB : Parent
{
public string ChildPropertyB { get; set; }
};
Then in the UI I have the classes:
public class ParentVM
{
public int ParentIdVM { get; set; }
public string ParentNameVM { get; set; }
};
public class ChildAVM : ParentVM
{
public string ChildPropertyAVM { get; set; }
};
public class ChildBVM : ParentVM
{
public string ChildPropertyBVM { get; set; }
};
Now I will have a service class in which the methods will look like the one below:
public GetParentVMs()
{
var parents = initializeRepositoryClass();
var parentsVM = MapRepositoryToViewClasses(parents);
ShowResult(parentsVM);
}
Where:
public List<Parent> initializeRepositoryClass()
{
var parents = new List<Parent>(){
new ChildA(){ParentId=1, ParentName="Parent 1", ChildPropertyA="A"},
new Parent(){ParentId=2, ParentName="Parent 2"},
new ChildB(){ParentId=3, ParentName="Parent 3", ChildPropertyB="B"},
};
return parents;
}
private List<ParentVM> MapRepositoryToViewClasses(List<Parent> parents)
{
var parentsVM = new List<ParentVM>();
foreach (var item in parents)
{
if (item is ChildA)
{
var itemVM = item as ChildA;
parentsVM.Add(
new ChildAVM() { ParentIdVM = itemVM.ParentId, ParentNameVM = itemVM.ParentName, ChildPropertyAVM = itemVM.ChildPropertyA }
);
}
else if (item is ChildB)
{
var itemVM = item as ChildB;
parentsVM.Add(
new ChildBVM() { ParentIdVM = itemVM.ParentId, ParentNameVM = itemVM.ParentName, ChildPropertyBVM = itemVM.ChildPropertyB }
);
}
else
{
var itemVM = item as Parent;
parentsVM.Add(
new ParentVM() { ParentIdVM = itemVM.ParentId, ParentNameVM = itemVM.ParentName }
);
}
}
return parentsVM;
}
private void ShowResult(List<ParentVM> parentsVM)
{
foreach (var item in parentsVM)
{
if (item is ChildAVM)
{
var ca = (ChildAVM)item;
Console.WriteLine("Child A " + ca.ChildPropertyAVM);
}
else if (item is ChildBVM)
{
var cb = (ChildBVM)item;
Console.WriteLine("Child B " + cb.ChildPropertyBVM);
}
else
{
Console.WriteLine("Parent ");
}
}
}
The code above will work, but I like to change the method MapRepositoryToViewClasses to another that uses linq, and looks a like the one below:
private List<ParentVM> MapRepositoryToViewClassesLinq(List<Parent> parents)
{
var parentsVM =
from p in parents
case
p is ChildA then select new ChildAVM() {ChildPropertyAVM = p.ChildPropertyA, ...};
else
p is ChildB then select new ChildBVM() {ChildPropertyBVM = p.ChildPropertyB, ...};
else
select new ParentVM() {ParentIdVM = p.ParentId};
return parentsVM.ToList();
}
Any ideas? Thanks.
You need some changes in your code to make it better
1) You have to introduce a factory to create VM's instances.
class VMFactory
{
public ParentVM Create(Parent obj)
{
var childA = obj as ChildA;
if (childA != null)
{
return new ChildAVM() { ParentIdVM = childA.ParentId, ParentNameVM = childA.ParentName, ChildPropertyAVM = childA .ChildPropertyA };
}
var childB = obj as ChildB;
if(childB != null)
{
return new ChildBVM() { ParentIdVM = childB.ParentId, ParentNameVM = childB.ParentName, ChildPropertyBVM = childB.ChildPropertyB };
}
return new ParentVM() { ParentIdVM = obj.ParentId, ParentNameVM = obj.ParentName };
}
}
2) Now you can simplify your code at MapRepositoryToViewClasses method
private List<ParentVM> MapRepositoryToViewClasses(List<Parent> parents)
{
// Factory instance can be provided by the outer scope
var factory = new VMFactory();
var parentsVM = new List<ParentVM>();
foreach (var item in parents)
{
parentsVM.Add(factory.Create(item));
}
return parentsVM;
}
3) Final step, let's use Linq to map
private List<ParentVM> MapRepositoryToViewClasses(List<Parent> parents)
{
// Factory instance can be provided by the outer scope
var factory = new VMFactory();
return parents.Select(factory.Create).ToList();
}
It's done
Yet another attempt to solve it
1) Create the extensions to solve common tasks.
static class Ext
{
public static ParentVM Map<TIn>(this TIn obj, Func<TIn, ParentVM> func)
where TIn : Parent
{
var source = obj as TIn;
return source != null
? func(obj)
: null;
}
}
2) Use the extension method to get VMs
private List<ParentVM> MapRepositoryToViewClassesLinq(List<Parent> parents)
{
var tmp = from p in parents
select
p.Map<ChildA>(c => new ChildAVM() { ParentIdVM = c.ParentId, ParentNameVM = c.ParentName, ChildPropertyAVM = c.ChildPropertyA }) ??
p.Map<ChildB>(c => new ChildBVM() { ParentIdVM = c.ParentId, ParentNameVM = c.ParentName, ChildPropertyBVM = c.ChildPropertyB }) ??
new ParentVM() { ParentIdVM = obj.ParentId, ParentNameVM = obj.ParentName };
return tmp.ToList();
}
If you setup mapping extensions for each type, then the mapping process becomes trivial.
SQL Fiddle: https://dotnetfiddle.net/a4eQ6S
How to map (GetParentsVM())
var parents = initializeRepositoryClass();
var parentsVM = parents.Map();
Mapping Extensions
public static class ParentMappings
{
public static ChildAVM Map(this ChildA model)
{
return new ChildAVM()
{
ParentIdVM = model.ParentId,
ParentNameVM = model.ParentName,
ChildPropertyAVM = model.ChildPropertyA,
};
}
public static ChildBVM Map(this ChildB model)
{
return new ChildBVM()
{
ParentIdVM = model.ParentId,
ParentNameVM = model.ParentName,
ChildPropertyBVM = model.ChildPropertyB,
};
}
public static ParentVM Map(this Parent model)
{
if (model is ChildA)
return ((ChildA)model).Map();
else if (model is ChildB)
return ((ChildB)model).Map();
else
return new ParentVM()
{
ParentIdVM = model.ParentId,
ParentNameVM = model.ParentName,
};
}
public static List<ParentVM> Map(this List<Parent> parents)
{
return parents.Select(p => p.Map()).ToList();
}
}
I need to pass complex or List<> class object to a web API in C#, without AJAX or jQuery. This is my code I used for the API and controller.
Web API:
[AcceptVerbs("GET", "POST")]
[HttpGet]
public void WriteBusinessObjectApiFromObj(int Pa1, string Pa2, object item)
{
// To Do In Function
}
Controller:
public void WriteBusinessObjectApi(object obj)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:8080/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var apiUrl = "api/WriteBusinessObjectApiFromObj?Pa1=1&Pa2=2";
var response = client.PostAsJsonAsync(apiUrl, obj).Result;
client.Dispose();
if (response.IsSuccessStatusCode)
{
}
}
}
I try to call the API but I can't send objects to it.
This object I try to send like:
Returned list of object from this function:
public List<Product> GetProductsObj()
{
var products = new List<Product>
{
new Product()
{
Id = 4,
Name = "product 4",
SupProducts = new List<SupProduct>
{
new SupProduct()
{
Id = 41,
Name = "Sup 41"
},
new SupProduct()
{
Id = 42,
Name = "Sup 42"
},
new SupProduct()
{
Id = 43,
Name = "Sup 43"
}
}
},
new Product()
{
Id = 5,
Name = "product 5",
SupProducts = new List<SupProduct>
{
new SupProduct()
{
Id = 51,
Name = "Sup 51"
},
new SupProduct()
{
Id = 52,
Name = "Sup 52"
},
new SupProduct()
{
Id = 53,
Name = "Sup 53"
}
}
},
new Product()
{
Id = 6,
Name = "product 6",
SupProducts = new List<SupProduct>
{
new SupProduct()
{
Id = 71,
Name = "Sup 71"
},
new SupProduct()
{
Id = 72,
Name = "Sup 72"
},
new SupProduct()
{
Id = 73,
Name = "Sup 73"
}
}
}
};
return products;
}
It's possible that the binder is getting confused and trying to incorrectly mix FromBody and FromURI so try wrapping all of the parameters in an object instead. This is a better pattern anyway because you're explicitly stating what it is that makes a "request". Note also that in the below I specify the object type rather than just saying "object". Better to be explicit, you know the Type on both sides anyway!
public class WriteBusinessObjectApiFromObjRequest
{
public int Pa1 { get; set; }
public string Pa2 { get; set; }
public List<Product> Item { get; set; } // change to your Type
}
[AcceptVerbs("GET", "POST")]
[HttpGet]
public void WriteBusinessObjectApiFromObj(WriteBusinessObjectApiFromObjRequest request)
{
// To Do In Function
}
var apiUrl = "api/WriteBusinessObjectApiFromObj";
var response = client.PostAsJsonAsync(
apiUrl,
new WriteBusinessObjectApiFromObj { Pa1 = 1, Pa2 = "2", Item = obj })
.Result;
Here is a cool overview of how to use parameter binding that doesn't go into any technical detail. Alternatively, here is a much more in depth exploration of Web API parameter binding
Model:
public class Employee
{
[Required]
public string EmployeeId { get; set; }
public string EmployeeName { get; set; }
public int EmployeeRollNum { get; set; }
public EmployeeAddress EmployeeAddr { get; set; }
public List<EmployeeAddress> AllEmployeeAddr { get; set; }
}
public class EmployeeAddress
{
//[Required]
public string EmployeeAddressId { get; set; }
public string EmployeeAddressName { get; set; }
public List<int> AllNum { get; set; }
}
In Web API Server:
[HttpGet]
public object Get([FromUri]Employee employee)
{
if (employee != null && ModelState.IsValid)
{
// Do something with the product (not shown).
return employee;
}
return employee;
}
In Web Api Client:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace WebApiConsoleApplication1
{
public static class UrlHelpers
{
/// <summary>
/// To the query string. http://ole.michelsen.dk/blog/serialize-object-into-a-query-string-with-reflection.html
/// </summary>
/// <param name="request"> The request. </param>
/// <param name="separator"> The separator. </param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException"> request </exception>
public static string ToQueryString(this object request, string innerPropertyName = null, string separator = ",")
{
if (request == null)
{
throw new ArgumentNullException("request");
}
StringBuilder propertyQuery = new StringBuilder();
// Get all primitive properties on the object
var properties = request.GetType().GetProperties()
.Where(x => x.CanRead)
.Where(x => x.GetValue(request, null) != null)
.Where(x => !x.PropertyType.IsClass || (x.PropertyType.IsClass && x.PropertyType.FullName == "System.String"))
.ToDictionary(x => x.Name, x => x.GetValue(request, null));
foreach (KeyValuePair<string, object> kvp in properties)
{
if (string.IsNullOrEmpty(innerPropertyName))
{
propertyQuery.AppendFormat("{0}={1}", Uri.EscapeDataString(kvp.Key), Uri.EscapeDataString(kvp.Value.ToString()));
}
else
{
propertyQuery.AppendFormat("{0}.{1}={2}", Uri.EscapeDataString(innerPropertyName), Uri.EscapeDataString(kvp.Key), Uri.EscapeDataString(kvp.Value.ToString()));
}
propertyQuery.AppendFormat("&");
}
var innerClass = request.GetType().GetProperties()
.Where(x => x.CanRead)
.Where(x => x.GetValue(request, null) != null && x.PropertyType.IsClass && x.PropertyType.FullName != "System.String" && !(x.GetValue(request, null) is IEnumerable))
.ToDictionary(x => x.Name, x => x.GetValue(request, null));
// Get names for all IEnumerable properties (excl. string)
var propertyCollectionNames = request.GetType().GetProperties()
.Where(x => x.CanRead)
.Where(x => x.GetValue(request, null) != null)
.ToDictionary(x => x.Name, x => x.GetValue(request, null))
.Where(x => !(x.Value is string) && x.Value is IEnumerable)
.ToDictionary(x => x.Key, x => x.Value);
// Concat all IEnumerable properties into a comma separated string
foreach (var kvp in propertyCollectionNames)
{
var valueType = kvp.Value.GetType();
var valueElemType = valueType.IsGenericType
? valueType.GetGenericArguments()[0]
: valueType.GetElementType();
if (valueElemType.IsPrimitive || valueElemType == typeof(string)) // List of primitive value type or string
{
var enumerable = kvp.Value as IEnumerable;
int count = 0;
foreach (object obj in enumerable)
{
if (string.IsNullOrEmpty(innerPropertyName))
{
propertyQuery.AppendFormat("{0}[{1}]={2}", Uri.EscapeDataString(kvp.Key), count, Uri.EscapeDataString(obj.ToString()));
}
else
{
propertyQuery.AppendFormat("{0}.{1}[{2}]={3}", Uri.EscapeDataString(innerPropertyName), Uri.EscapeDataString(kvp.Key), count, Uri.EscapeDataString(obj.ToString()));
}
count++;
propertyQuery.AppendFormat("&");
}
}
else if (valueElemType.IsClass) // list of class Objects
{
int count = 0;
foreach (var className in kvp.Value as IEnumerable)
{
string queryKey = string.Format("{0}[{1}]", kvp.Key, count);
propertyQuery.AppendFormat(ToQueryString(className, queryKey));
count++;
}
}
}
foreach (var className in innerClass)
{
propertyQuery.AppendFormat(ToQueryString(className.Value, className.Key));
}
return propertyQuery.ToString();
}
}
public class Employee
{
public string EmployeeId { get; set; }
public string EmployeeName { get; set; }
public int EmployeeRollNum { get; set; }
public EmployeeAddress EmployeeAddr { get; set; }
public List<EmployeeAddress> AllEmployeeAddr { get; set; }
}
public class EmployeeAddress
{
//[Required]
public string EmployeeAddressId { get; set; }
public string EmployeeAddressName { get; set; }
public List<int> AllNum { get; set; }
}
internal class Program
{
private static void Main()
{
RunAsync().Wait();
Console.WriteLine("Completed");
Console.ReadLine();
}
private static async Task RunAsync()
{
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings.Get("HostURL"));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(ConfigurationManager.AppSettings.Get("AcceptType")));
HttpResponseMessage response = await client.GetAsync("api/Values/1");
if (response.IsSuccessStatusCode)
{
string val = await response.Content.ReadAsAsync<string>();
Console.WriteLine("{0}\t", val);
}
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(ConfigurationManager.AppSettings.Get("AcceptType")));
//client.DefaultRequestHeaders.Add()
// HTTP GET
Employee emp = new Employee();
emp.EmployeeId = "sri1";
emp.AllEmployeeAddr = new List<EmployeeAddress>();
EmployeeAddress lstemployeeAddr = new EmployeeAddress();
lstemployeeAddr.EmployeeAddressId = "Address1";
lstemployeeAddr.AllNum = new List<int>();
lstemployeeAddr.AllNum.Add(1);
lstemployeeAddr.AllNum.Add(2);
lstemployeeAddr.AllNum.Add(3);
emp.AllEmployeeAddr.Add(lstemployeeAddr);
lstemployeeAddr = new EmployeeAddress();
lstemployeeAddr.EmployeeAddressId = "Address2";
lstemployeeAddr.AllNum = new List<int>();
lstemployeeAddr.AllNum.Add(24);
lstemployeeAddr.AllNum.Add(56);
emp.AllEmployeeAddr.Add(lstemployeeAddr);
EmployeeAddress innerEmployeeAddr = new EmployeeAddress();
innerEmployeeAddr.EmployeeAddressId = "Addr3";
innerEmployeeAddr.AllNum = new List<int>();
innerEmployeeAddr.AllNum.Add(5);
innerEmployeeAddr.AllNum.Add(6);
emp.EmployeeAddr = innerEmployeeAddr;
string query = emp.ToQueryString();
response = await client.GetAsync("api/Values?" + query);
if (response.IsSuccessStatusCode)
{
Employee product = await response.Content.ReadAsAsync<Employee>();
Console.WriteLine("{0}\t{1}\t", product.EmployeeId, product.EmployeeName);
}
}
}
catch (Exception ex)
{
}
}
}
}
here is my model code
public class Question
{
public int ID { set; get; }
public string QuestionText { set; get; }
public List<Answer> Answers { set; get; }
[Required]
public string SelectedAnswer { set; get; }
public Question()
{
Answers = new List<Answer>();
}
}
public class Answer
{
public int ID { set; get; }
public string AnswerText { set; get; }
public string IsSelected { set; get; }
}
public class Evaluation
{
public List<Question> Questions { set; get; }
public Evaluation()
{
Questions = new List<Question>();
}
}
this way i am updating my model
public void Edit(Evaluation model)
{
var evalVM = new Evaluation();
var q1 = new Question { ID = 1, QuestionText = "What is your favourite language" };
q1.Answers.Add(new Answer { ID = 12, AnswerText = "PHP", IsSelected = "" });
q1.Answers.Add(new Answer { ID = 13, AnswerText = "ASP.NET", IsSelected = "" });
q1.Answers.Add(new Answer { ID = 14, AnswerText = "Java", IsSelected = "" });
evalVM.Questions.Add(q1);
var q2 = new Question { ID = 2, QuestionText = "What is your favourite DB" };
q2.Answers.Add(new Answer { ID = 16, AnswerText = "SQL Server", IsSelected = "" });
q2.Answers.Add(new Answer { ID = 17, AnswerText = "MySQL", IsSelected = "" });
q2.Answers.Add(new Answer { ID = 18, AnswerText = "Oracle", IsSelected = "" });
evalVM.Questions.Add(q2);
foreach (var a in model.Questions)
{
var selectedVal = a.SelectedAnswer;
foreach (var x in evalVM.Questions)
{
var Answer = x.Answers;
foreach (var y in Answer)
{
if (y.ID.ToString() == selectedVal)
{
y.IsSelected = "checked";
}
}
}
}
}
just see this line here i am iterate in foreach loop and update my model in loop
foreach (var a in model.Questions)
{
var selectedVal = a.SelectedAnswer;
foreach (var x in evalVM.Questions)
{
var Answer = x.Answers;
foreach (var y in Answer)
{
if (y.ID.ToString() == selectedVal)
{
y.IsSelected = "checked";
}
}
}
}
I don't want to iterate in loop to update my model rather I want to do it by LINQ. Please guide me what I need to write.
foreach (var selectedVal in model
.Questions
.Select(q => q.SelectedAnswer))
foreach (var x in evalVM
.Questions
.SelectMany(q => q.Answers)
.Where(answer => answer.ID.ToString() == selectedVal))
x.IsSelected = "checked";
or
var selectedValues = model
.Questions
.Select(q => q.SelectedAnswer);
foreach (var x in evalVM
.Questions
.SelectMany(q => q.Answers)
.Where(answer => selectedValues.Contains(answer.ID.ToString())))
x.IsSelected = "checked";