I've created a dll that perform some request on my API. Now the request send me back a json response, what I want to do (from the dll), is return an array of object to be used in the program that implements the DLL. Now I've this class:
public class Details
{
public string name { get; set; }
public string age { get; set; }
}
public class Info
{
public List<object> info { get; set; }
}
public class User
{
public Details details { get; set; }
public Info info { get; set; }
}
public class RootObject
{
public User user { get; set; }
}
I deserialize the request like this:
var obj = JsonConvert.DeserializeObject<List<RootObject>>("json returned");
Now the json contains the details of the user, and in some case also the info, so I iterate through of it in this way:
foreach(var user in obj)
{
item.user.details.name;
//take some info (could not contain nothing)
foreach(var info in user.info.info)
{
info; //<- contains all the information
}
}
What I want to know is: How can I create a list of object? In particular I want send back the user object that have as property details and info. The result should be an array of object 'cause who reiceve the object need to iterate through of it and read each object property as:
user[0].details.name: //where 0 is the index of the user (php syntax)
I don't know if is possible in c#, someone could help me to achieve this target?
Your json converter returns List<RootObject>, and each RootObject contains only one property: user. A simple Linq query would change the List<RootObject> into a List<User> object:
var users = obj.Select(o => o.user).ToList();
Each element in users then is a User, with both the Details and Info property.
As an example on how to use this, consider you have a method that does the conversion from json and you want that method to return the list of users. That method would look something like this:
public List<User> GetUsersFromJson()
{
var obj = JsonConvert.DeserializeObject<List<RootObject>>("json returned");
var users = obj.Select(o => o.user).ToList();
return users;
}
You can iterate through the users object like this:
foreach (var user in users)
{
var detail = user.details;
var info = user.info;
}
You should consider changing your public properties to camel-case as is common practice in C#.
JsonConvert.DeserializeObject> returns the list of RootObject. You can use method ToArray() to change the list to array.
In this case:
var obj = JsonConvert.DeserializeObject<List<RootObject>>("json returned");
RootObject[] array = obj.ToArray();
string s = array[0].user.details.name;
object[] infos = array[0].user.info.info.ToArray();
and in this code:
foreach(var user in obj)
{
item.user.details.name;
//take some info (could not contain nothing)
foreach(var info in user.info.info)
{
info; //<- contains all the information
}
}
don't have sens, it should be like this:
foreach (RootObject elem in obj)
{
foreach (Info info in elem.user.info.info)
{
object[] localInfo = info.info.ToArray(); //<- contains all the information
}
}
Related
I have to store complex object into hash of redis cash.I am using stackexchange.redis to do this.My Class is like below.
public class Company
{
public string CompanyName { get; set; }
public List<User> UserList { get; set; }
}
public class User
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Twitter { get; set; }
public string Blog { get; set; }
}
My code snippet to store data in redis is:
db.HashSet("Red:10000",comapny.ToHashEntries());
//Serialize in Redis format:
public static HashEntry[] ToHashEntries(this object obj)
{
PropertyInfo[] properties = obj.GetType().GetProperties();
return properties
.Where(x => x.GetValue(obj) != null) // <-- PREVENT NullReferenceException
.Select(property => new HashEntry(property.Name, property.GetValue(obj)
.ToString())).ToArray();
}
I could store the data in redis but not as i want.I am geting result as shown in below image.
I want UserList value in json format.So,how can i do this.
Probably the easiest path is checking if each property value is a collection (see the comments in my modified version of your method):
public static HashEntry[] ToHashEntries(this object obj)
{
PropertyInfo[] properties = obj.GetType().GetProperties();
return properties
.Where(x => x.GetValue(obj) != null) // <-- PREVENT NullReferenceException
.Select
(
property =>
{
object propertyValue = property.GetValue(obj);
string hashValue;
// This will detect if given property value is
// enumerable, which is a good reason to serialize it
// as JSON!
if(propertyValue is IEnumerable<object>)
{
// So you use JSON.NET to serialize the property
// value as JSON
hashValue = JsonConvert.SerializeObject(propertyValue);
}
else
{
hashValue = propertyValue.ToString();
}
return new HashEntry(property.Name, hashValue);
}
)
.ToArray();
}
It seems that there is something wrong with serializing. The best way of converting between JSON and .NET object is using the JsonSerializer:
JsonConvert.SerializeObject(fooObject);
You can see more details from Serializing and Deserializing JSON.
Also there is another good way,you can try to use IRedisTypedClient which is a part of ServiceStack.Redis.
IRedisTypedClient - A high-level 'strongly-typed' API available
on Service Stack's C# Redis Client to make all Redis Value operations
to apply against any c# type. Where all complex types are
transparently serialized to JSON using ServiceStack JsonSerializer -
The fastest JSON Serializer for .NET.
Hope this helps.
I have this IDictionary declaration: IDictionary<string, string> trace;
Inside of it I want save a list of element returned by a json deserialization, actually I do this like:
var obj = JsonConvert.DeserializeObject<List<RootObject>>(responseText);
foreach (var item in obj)
{
trace["date"] = item.trace.details.date;
trace["type"] = item.trace.details.type;
foreach (var trace in item.trace.context.context)
{
trace["context"] = JsonConvert.SerializeObject(trace);
}
}
Now this code working good but save only the last item of the iteration, this 'cause when I iterate over the item the date, type etc... are replaced, but I want store the item not replace it in each new iteration.
How can do this with IDictionary?
Note that: trace.x is the name of the class that deserialize the json.
Further question: Maybe the use of IDictionary is not a good idea for achieve this?
Looks like you'd be better off using a dedicated class, something like this:
public class TraceInfo
{
public string Date { get; set; }
public string Type { get; set; }
public List<string> ContextItems { get; set; }
}
Then for every value in obj, create a TraceInfo object using new TraceInfo() and set its properties.
You can then store them in a List<TraceInfo> or in a Dictionary<string, TraceInfo>, the choice is yours.
I made a class for deserialize a JSON (I'm using JSON.net), this is the structure:
public class User
{
public string Name { get; set; }
public string Surname { get; set;}
}
public class RootObject
{
public List<User> Users { get; set; }
}
I deserialize the JSON like this:
var obj = JsonConvert.DeserializeObject<RootObject>(responseText);
Now If I want return all the JSON I simply do: return obj.Users; but how can I return a specific property of the class User? In particular the Name property. I tried this:
return obj.Users.name // user list does not contain any name property
Also I tried with LINQ:
obj.Select(c => c.Name).Single();
But I can't use Select because I need to declare obj as:
var obj = JsonConvert.DeserializeObject<List<RootObject>>(responseText);
If instead I return obj.user; I can use LINQ and access to the name. But how can do this in the method that return the response?
Add a reference to class
using System.Linq;
since user is of type List you can apply lambda expression in it. Do not use Single it will fail if user will have more than one record in it, use FirstOrDefault instead. It will work for zero or more number of elements
var obj = JsonConvert.DeserializeObject<RootObject>(responseText);
string name = obj.user.Select(p=> p.name).FirstOrDefault();
string surname = obj.user.Select(p=> p.surname).FirstOrDefault();
You have to use one user instead of the whole list as RootObject.user is a List<User> and not an instance of User:
var name = obj[0].Name;
Or whatever element within your list you want to use.
Alternativly use LINQ:
var user = obj.FirstOrDefault();
if (user != null) name = user.name;
I have such a class:
public class item
{
public string Name { get; set; }
public string City { get; set; }
public string Pw { get; set; }
}
from which I create several objects I store in the DB. Then I want to update one of them with data coming from client in the form of a json like this:
{
"Name":"John",
"City":"NYC"
}
the idea would be to use:
item myitem = JsonConvert.DeserializeObject<item>(jsoncomingfromclient);
but doing so Pw is overwritten with null (while obviously I want to keep the original value)
NullValueHandling looks like a good candidate but it works if the value is null, in my case it is completely missing from the json.
Any idea how to deserialize a json keeping the old value in the destination object if the value is missing in the json?
Use JsonConvert.PopulateObject. It's designed for this purpose:
var item = new item { Name = "my name", City = "my city", Pw = "my pw" };
var json = #"
{
""Name"":""John"",
""City"":""NYC""
}";
JsonConvert.PopulateObject(json, item);
Debug.Assert(item.Pw == "my pw"); // no assert
Debug.Assert(item.Name == "John"); // no assert
Debug.Assert(item.City == "NYC"); // no assert
This part of code JsonConvert.DeserializeObject<item>(jsoncomingfromclient); will create new instance of type item based on parameter jsoncomingfromclient and return it.
This part item myitem = ... declares a variable myitem of type item and gives it a concrete instance. So there is no way to merge anything like this.
You just have to write some merge method manually and define what and how is merged between two objects.
Something like that
item dbitem = ...
item myitem = JsonConvert.DeserializeObject<item>(jsoncomingfromclient);
item mergedItem = myitem.merge(dbitem)
I have a JSON "multi-level" response that I need to deserialize and from the deserialized classes structure I need to extract all the objects of a certain class.
Below the code I'm using, at the end I find that my result is empty, not populated.
// given these two classes:
[DataContract]
public class ThingsList
{
[DataMember(Name = "status")]
public string Status { get; set; }
[DataMember(Name = "since")]
public double Since { get; set; }
[DataMember(Name = "list")]
public Dictionary<string, ThingsListItem> Items { get; set; }
public DateTime SinceDate { get { return UnixTime.ToDateTime(Since); } }
}
[DataContract]
public class ThingsListItem
{
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "title")]
public string Title { get; set; }
}
// I can deserialize my json to this structure with:
ThingsList results = JsonConvert.DeserializeObject<ThingsList>(e.Result);
// now I need to "extract" only the ThingsListItem objects, and I'm trying this:
var theList = from item in results.Items.OfType<ThingsListItem>()
select new
{
Title = item.Title,
Url = item.Url
};
// but "theList" is not populated.
The points here are (I believe):
- I try to use results.Items.OfType() in order to extract only the ThingsListItem objects, that in the "upper" class are declared in the
public Dictionary Items { get; set; }
row.
Any idea? Tell if it's not clear...
Thanks
Andrea
EDIT: updated my response for clarity.
Since your Dictionary values are of type ThingsListItem you can access them directly by using the Dictionary's Values property. There is no need to use OfType to check their type and extract them. Simply use:
var items = results.Items.Values;
The Values property would return an ICollection<ThingsListItem>. You can then iterate over the results with a foreach. LINQ does not have to be used.
While the Values property described above should be sufficient, I will point out a few issues with your original LINQ query attempt.
1) The following query is probably what you were after. Again, the Dictionary's Values property is key (no pun intended) to accessing the items:
var theList = from item in results.Items.Values
select new
{
Title = item.Title,
Url = item.Url
};
2) Why are you using new? That will return an IEnumerable of anonymous types. You already have a defined class, so why project into a new anonymous type? You should retain the underlying ThingsListItem items by selecting the item directly to get an IEnumerable<ThingsListItem>:
var theList = from item in results.Items.Values
select item;
foreach (var item in theList)
{
Console.WriteLine("Title: {0}, Url: {1}", item.Title, item.Url);
}
You would usually project into a new anonymous type to define a type with data properties you are interested in. Generally you would use them immediately after the query, whereas a selection into an existing class could be used immediately or passed around to other methods that are expecting that type.
Hopefully this has cleared up some questions for you and you have a better idea of using LINQ and when to use the new keyword. To reiterate, for your purposes it seems the Values property should suffice. Using LINQ to select the item is redundant when there are other immediate means to do so.