I noticed that using RestSharp :Execute<T>() , when T as below
public class Result
{
public List<DBData> Data { get; set; }
public int Total { get; set; }
public bool Success { get; set; }
}
It deserialized the JSON from Execute<Result>() correctly into Result object,
However when the class has IEnumerable property like below
public class Result
{
public IEnumerable<DBData> Data { get; set; }
public int Total { get; set; }
public bool Success { get; set; }
}
Execute<Result>() does not fill(deserialize) into the object Result.
I am suspecting it is because of IEnumerable<T> being read only and Restsharp is unable to deserialize data because of that ? Is it the case ?
Because RestSharp can not infer the type of the property from the IEnumerable. Extend the existing SimpleJson serializer to use more robust serializer like Json.Net
Related
There's a lot of Qs on this, but I need a solution without JSON.Net, etc. - I must use the canned stuff in Asp.Net MVC.
How can I serialize a POCO with a dynamic property - and get all the static properties, too? What I found was the dynamic only, or the static type which is easy.
e.g.
public class ReturnThisClassAsJSON {
public int Id {get; set; }
public string Name { get; set; }
public ContainedClass ContainedContents { get; set; }
}
public class ContainedClass {
public int Order { get; set; }
public string Label { get; set; }
public dynamic DynamicInfo { get; set; }
public List<dynamic> DynamicList { get; set }
}
My own answer:
I replaced the dynamic from the DynamicInfo and DynamicList from the ContainedClass with static types.
With the dynamic, I had 1 of 2 choices. Either serialize the dynamic to a string in its own serialization call using above SO question 5156664. (Which left me with the rest of the class I also wanted serialized and merged with it, thus this question). Or, incur this error:
"A circular reference was detected while serializing an object of type 'System.Reflection .RuntimeModule' ".
when attempting a single serialization call on the ContainedClass.
So, I transferred the dynamics into static-typed classes:
public class ColumnValue
{
public string Name { get; set; }
public string Value { get; set; }
}
public class DynamicRow
{
public List<ColumnValue> ColumnValue { get; set; }
}
and, change ContainedClass to this:
public class ContainedClass
{
public List<ColumnValue> DynamicInfo { get; set; }
public List<DynamicRow> Data { get; set; }
}
And, it serializes using out-of-the-box Asp.Net MVC:
return Json(ReturnThisClassAsJSON, JsonRequestBehaviour.AllowGet);
I have the following Object that matches the pattern of a JSON object i get from one REST request I send:
public class MyObject
{
public List<string> columns { get; set; }
public List<List<string>> rows { get; set; }
public DisplayValue displayValue { get; set; }
public string currency { get; set; }
public object alert { get; set; }
}
public class DisplayValue
{
public Id DisplayId { get; set; }
}
public class Id
{
public List<string> IdToName { get; set; }
}
this object match to the response I get and the next code is working with the upper implementation of MyObject (I'm using C#'s RestSharp):
var response = client.Execute(request);
result = JsonConvert.DeserializeObject<MyObject>(response.Content);
Now I would like to implement the Iterator design pattern on MyObject since MyObject.rows is the only field I actually use.
So I've changed MyObject class to the following
public class MyObject : IEnumerable<List<string>
{
public List<string> columns { get; set; }
public List<List<string>> rows { get; set; }
public DisplayValue displayValue { get; set; }
public string currency { get; set; }
public object alert { get; set; }
}
public IEnumerator<List<string>> GetEnumerator()
{
foreach (List<string> row in rows)
{
yield return row;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class DisplayValue
{
public Id DisplayId { get; set; }
}
public class Id
{
public List<string> IdToName { get; set; }
}
But when I try to JSONConvert I get the following exception:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'MyObject' because
the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly. To fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be deserialized from a JSON
object. JsonObjectAttribute can also be added to the type to force it
to deserialize from a JSON object.
Any idea to why is this happening?
The problem is that Json.NET will try to serialize any POCO that implements IEnumerable<T> for some T as a JSON array rather than a JSON object, as is documented here. Since your JSON is presumably not an array, you receive the exception you are seeing.
Since you don't want your MyObject serialized as an array, you can force Json.NET to (de)serialize it as an object instead by marking it with [JsonObject]:
[JsonObject]
public class MyObject : IEnumerable<List<string>>
{
public List<string> columns { get; set; }
public List<List<string>> rows { get; set; }
public DisplayValue displayValue { get; set; }
public string currency { get; set; }
public object alert { get; set; }
// Implementation of IEnumerable<List<string>>...
}
See JsonObjectAttribute force object serialization.
I have this class that defines the json format:
public class ResultType
{
public bool status { get; set; }
public string message { get; set; }
}
The actual json looks like this:
{"result":{"status":true,"message":"Success"}}
How can I override the root attribute when de-serializing the json to "result"
JObject jsonResponse = JObject.Parse(jsonString);
ResultType _Data = Newtonsoft.Json.JsonConvert.DeserializeObject<ResultType>(jsonResponse["result"].ToString());
Console.WriteLine(_Data.status);
Fiddle: https://dotnetfiddle.net/gjYS2p
I have a central deserialization method, so I'm trying to avoid type specific code as much as possible.
I used the following to resolve the problem, maybe not as sexy as I was hoping for but it works.
public class ResultType
{
public ResultDetailType result { get; set; }
}
public class ResultDetailType
{
public bool status { get; set; }
public string message { get; set; }
}
passing a Json value like this one(this will be the var jsonValue in code):
"{\"Something\":0,\"Something2\":10,\"Something3\":{\"Something4\":17,\"Something5\":38042,\"Something6\":38043,\"Id\":215},\"Something7\":215,\"SomethingId\":42,\"Something8\":\"AString, Gläser\",\"Something8\":\"44-55-18\",\"Status\":{\"Caption\":\"Fixed\",\"Value\":7},\"Type\":\"Article\",\"Id\":97,\"#Delete\":true,\"Something9\":\"8\"}"
to the following code:
var deserializer = new JsonSerializer();
const string regex = #"/Date\((.*?)\+(.*?)\)/";
var reader = new JsonTextReader(new StringReader(jsonValue));
returnValue = deserializer.Deserialize(reader, type);
type is the typeof https://dotnetfiddle.net/LMPEl0 (thank you Craig) (sorry for the weird names, can't disclose the actual ones...)
The jsonvalue is generated by input in an editable cell of a DataTable and apparently places previously null values in the end of the json string.
I get a null value in the "Something9" property in the returnValue, instead of 8(Something9 was null before and set to 8 through an editable Cell of a DataTable)
Is there some problem with the Json value that I can't see?
Or do I need some setting in the Deserializer?
Thanks
You don't show what your type is so I generated one using http://json2csharp.com.
public class Something3
{
public int Something4 { get; set; }
public int Something5 { get; set; }
public int Something6 { get; set; }
public int Id { get; set; }
}
public class Status
{
public string Caption { get; set; }
public int Value { get; set; }
}
public class RootObject
{
public int Something { get; set; }
public int Something2 { get; set; }
public Something3 Something3 { get; set; }
public int Something7 { get; set; }
public int SomethingId { get; set; }
public string Something8 { get; set; }
public Status Status { get; set; }
public string Type { get; set; }
public int Id { get; set; }
[JsonProperty("#Delete")]
public bool Delete { get; set; }
public string Something9 { get; set; }
}
Because one of your properties has a name that is not valid as a .NET property I added the [JsonProperty] attribute to that one. After that it worked perfectly. Perhaps the problem is with how you declared the #Delete JSON property in your .NET type. Given that Something9 comes after that property it would be my guess that that's part of the problem.
Here's the fiddle.
https://dotnetfiddle.net/McZF9Q
While Craig's answer helped a lot and finally led to a solution the exact answer to the problem was the following:
The Status object is an Enum and was not Deserialized correctly.
Due to that, anything that followed in the Json string was also not deserialized.
Implementing a custom Enum Deserializer was the solution. There are other Questions in stackoverflow that helped with this, particularly this one here:
How can I ignore unknown enum values during json deserialization?
Thank you everyone :)
I have code structured like below.
public class Stats
{
public string URL { get; set; }
public string Status { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int Length { get; set; }
}
and
public class UrlStats
{
public string URL { get; set; }
public int TotalPagesFound { get; set; }
public List<Stats> TotalPages { get; set; }
public int TotalTitleTags { get; set; }
public List<Stats> TotalTitles { get; set; }
public int NoDuplicateTitleTags { get; set; }
public List<Stats> DuplicateTitles { get; set; }
public int NoOverlengthTitleTags { get; set; }
public List<Stats> OverlengthTitles { get; set; }
}
Basically i am scanning a website for statistics like title tags, duplicate titles, etc.
I am using JQuery and making AJAX calls to webservice and retrieving url stats while the process is running to show user url stats by far collected since it takes quite a time to scan a big website. So after every 5 seconds i retrieve stats from server. Now the problem is all the List variable data i need to send at the end when scanning processing is complete, not during updates. What's happening right now the List<Stats> variable data is also sent during updates which is big chunk of data and i want to send only int type variables which are required to show process updates.
From searching on internet i couldn't find anything useful solving my problem and i found that Json.NET is very good library but i really don't know how to properly use it to get what i want.
Basically i am looking for serializing properties depending on their datatype at runtime, if its possible.
There are two different approaches for your problem.
You should choose the first one if you are going to change your classes more often because the first approach prevents that you forget to serialize a newly added property. Furthermore it is much more reusable if you want to add another classes you want to be serialized the same way.
If you have only these two classes and it's most likely that they're not going to change you can choose the second approach to keep your solution simple.
1. Use a custom converter to select all int properties
The first approach is to use a custom JsonConverter which serializes a class or struct by only including properties which have type int. The code might look like this:
class IntPropertyConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
// this converter can be applied to any type
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// we currently support only writing of JSON
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
serializer.Serialize(writer, null);
return;
}
// find all properties with type 'int'
var properties = value.GetType().GetProperties().Where(p => p.PropertyType == typeof(int));
writer.WriteStartObject();
foreach (var property in properties)
{
// write property name
writer.WritePropertyName(property.Name);
// let the serializer serialize the value itself
// (so this converter will work with any other type, not just int)
serializer.Serialize(writer, property.GetValue(value, null));
}
writer.WriteEndObject();
}
}
Then you have to decorate your class with a JsonConverterAttribute:
[JsonConverter(typeof(IntPropertyConverter))]
public class UrlStats
{
// ...
}
Disclaimer: This code has been tested only very roughly.
2. Choose properties individually
The second solution looks a bit simpler: You can use the JsonIgnoreAttribute to decorate the attributes you want to exclude for serialization. Alternatively you can switch from "blacklisting" to "whitelisting" by explicitly including the attributes you want to serialize. Here is a bit of sample code:
Blacklisting: (I've reordered the properties for a better overview)
[JsonObject(MemberSerialization.OptOut)] // this is default and can be omitted
public class UrlStats
{
[JsonIgnore] public string URL { get; set; }
[JsonIgnore] public List<Stats> TotalPages { get; set; }
[JsonIgnore] public List<Stats> TotalTitles { get; set; }
[JsonIgnore] public List<Stats> DuplicateTitles { get; set; }
[JsonIgnore] public List<Stats> OverlengthTitles { get; set; }
public int TotalPagesFound { get; set; }
public int TotalTitleTags { get; set; }
public int NoDuplicateTitleTags { get; set; }
public int NoOverlengthTitleTags { get; set; }
}
Whitelisting: (also reordered)
[JsonObject(MemberSerialization.OptIn)] // this is important!
public class UrlStats
{
public string URL { get; set; }
public List<Stats> TotalPages { get; set; }
public List<Stats> TotalTitles { get; set; }
public List<Stats> DuplicateTitles { get; set; }
public List<Stats> OverlengthTitles { get; set; }
[JsonProperty] public int TotalPagesFound { get; set; }
[JsonProperty] public int TotalTitleTags { get; set; }
[JsonProperty] public int NoDuplicateTitleTags { get; set; }
[JsonProperty] public int NoOverlengthTitleTags { get; set; }
}
Oh got it, re-reading your question I think you can serialize a projection of your data.
You can try the following:
var json = JsonConvert.SerializeObject(new { u.TotalPagesFound, u.TotalTitleTags, u.NoDuplicateTitleTags, u.NoOverlengthTitleTags } );
This will convert to JSON only the int properties of your class. This is the easiest way, and it is tied to the structure of your class. If you want something more general, you will need to implement a custom converter.
Original answer:
I see no problem with your classes, you don't have anything weird like loop references, so Json.NET should have no problem serializing your class. So go grab Json.NET and then you can attempt the following
// create new instance of your url stat class
var u = new UrlStats() { URL = "a.com", TotalPages = new List<Stats>() { new Stats() { URL = "b.com", Status = "xxxx" } } };
// seralize!
var json = JsonConvert.SerializeObject(u);
Console.Write(json);
What I get with this method is something like this:
{"URL":"a.com","TotalPagesFound":0,"TotalPages":[{"URL":"b.com","Status":"xxxx","Title":null,"Description":null,"Length":0}],"TotalTitleTags":0,"TotalTitles":null,"NoDuplicateTitleTags":0,"DuplicateTitles":null,"NoOverlengthTitleTags":0,"OverlengthTitles":null}
And that looks like good json to me.