I am getting tdata from a certain endpoint and the problem id on serialization to my classes. I want to cast the bellow data to my class but cant get how the class should be structured. Check out the data .....
{
"-LYG_AI_oGYjNBrzMlKF": {
"chatDispayText": "",
"chatId": "-LYG_AI_oGYjNBrzMlKF",
"chatName": "",
"chattype": "single",
"imageUrl": "https://wallpaper.wiki/wp-content/uploads/2017/04/wallpaper.wiki-Amazing-celebrities-hd-wallpaper-PIC-WPD004734.jpg",
"lastMessageSent": "aiye",
"lastMessageSentTime": 1549704416263,
"synched": false,
"users": {
"-LYG_AIZ5MvTbjR7DACe": "Uicpm3L15TX0c15pKCI6KUEARyB3",
"-LYG_AI_oGYjNBrzMlKE": "Xsr0z9lsqNOEytX61lJvaGz1A8F2"
}
}
}
If the data you get out the endpoint has a dynamic structure, you can make use of a key-vale pair collection or a dictionary. For instance:
JObject jObject = JObject.Parse(Data); // This would already give you a key-value pair collection
Dictionary<String,Object> collection = new Dictionary<String, Object>();
foreach(var obj in jObject){
collection.Add(obj.Key, obj.Value);
}
However, this isn't a strongly typed approach which means that it is not effective in the majority of scenarios. A better solution when dealing with endpoints would be to define a class with fixed schema, actually something you need in your code, and then map the class to the object yielded by the endpoint using a metadata struct. For example:
public class ChatInfoModel
{
[JsonProperty(Metadata.ChatId)]
public long ChatId { get; set; }
[JsonProperty(Metadata.ChatId, Required = Required.AllowNull)]
public String Message { get; set; }
}
public struct Metadata
{
public const String ChatId = "userChatId";
public const String Message = "messageTxt";
}
And then
var deserializedObject = JsonConvert.DeserializeObject<ChatInfoModel>(data);
However, if your class has the exact same naming convention (but should not necessarily follow the camelCase naming convention) for its properties as in the serialized data, the JsonProperty attribute would not be needed.
You can also deserialize the object without using JsonProperty attribute manually using the first approach, and it is actually advantageous in certain scenarios where your schema comes from a configuration file rather than a struct.
Take inspiration from the Structure below:
public class Rootobject
{
public LYG_AI_Ogyjnbrzmlkf LYG_AI_oGYjNBrzMlKF { get; set; }
}
public class LYG_AI_Ogyjnbrzmlkf
{
public string chatDispayText { get; set; }
public string chatId { get; set; }
public string chatName { get; set; }
public string chattype { get; set; }
public string imageUrl { get; set; }
public string lastMessageSent { get; set; }
public long lastMessageSentTime { get; set; }
public bool synched { get; set; }
public Users users { get; set; }
}
public class Users
{
public string LYG_AIZ5MvTbjR7DACe { get; set; }
public string LYG_AI_oGYjNBrzMlKE { get; set; }
}
I'm 'conjoining' Umbraco with another web application and using Elasticsearch to store data from both applications in one index. So far, I've been only searching through Umbraco content, getting its ID and then using UmbracoHelper to retrieve the proper IPublishedContent item, which then I mapped to a strong-typed object [Class1], which inherits from PublishedContentModel abstract class, using Ditto.
Currently in the Umbraco application, the Class1 object is being serialized with JSON.Net and output and I can't change the structure of it. With addition of the items coming from another, non-Umbraco application I wanted to completely omit the step of retrieving the content from Umbraco and instead hold all of the relevant data directly in the index. That way I could just create strong typed objects based on the content of the index. However, after remapping the item to it's DTO [Class1DTO], I found myself unable to map those onto the Class1.
Obviously, I cannot use Ditto anymore, as it only works when mapping from IPublishedContent and it's derivatives. I was thinking about using AutoMapper, but the problem is, I cannot instantiate my Class1, without passing IPublishedContent object (because of the need to implement the PublishedContentModel constructor).
I know I could duplicate all of my strong-typed objects without the PublishedContentModel inheritance, but it feels really wrong doing that. Is there a way to somehow fake the IPublishedContent object, so that I could use AutoMapper? Or is there any other way of achieving the same output?
Example classes below:
[JsonObject(MemberSerialization.OptIn)]
public class Class1 : PublishedContentModel
{
public Class1(IPublishedContent content)
: base(content)
{
}
[JsonProperty]
public string type { get; set; }
[JsonProperty]
public override int Id { get { return base.Id; } }
[JsonProperty]
public override string SomeData { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public class Class1DTO
{
[JsonProperty]
public string type { get; set; }
[JsonProperty]
public int Id { get; set; }
[JsonProperty]
public string SomeData { get; set; }
[JsonProperty]
public SomeFilter FilterForSearch { get; set; }
}
Couldn't you create your own version of the PublishedContentModel that doesn't have a reliance on IPublishedContent? Something like this:
public abstract class Base
{
public Int32 Id { get; set; }
public String Name { get; set; }
public String Path { get; set; }
public IList<Int32> PathIds
{
get
{
return !String.IsNullOrEmpty(Path) ? Path.Split(',').Select(x => Convert.ToInt32(x)).ToList() : null;
}
}
public Int32 ParentId
{
get
{
if (PathIds.HasItemsAndNotNull() && PathIds.Count >= 2)
return PathIds[PathIds.Count - 2];
return -1;
}
}
public Int32 Level { get; set; }
public DateTime CreateDate { get; set; }
public DateTime UpdateDate { get; set; }
public String WriterName { get; set; }
public String DocumentTypeAlias { get; set; }
}
Unless you have a need of very specific fields that are on PublishedContentModel.
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 the following json string:
{"Visits":[true,"DockedOnly","leftZone","0","500",0,0,0],
"Weather":[true,"DockedOnly","leftZone","0","0",0,0,1],
"ContactUs":[true,"DockedOnly","leftZone","0","317",0,0,2],
"Birthdays":[true,"DockedOnly","middleZone","0","0",0,0,0],
"Reminders":[true,"DockedOnly","middleZone","0","145",0,0,1],
"Messages":[true,"DockedOnly","middleZone","0","0",0,0,2],
"Availability":[true,"DockedOnly","middleZone","0","0",0,0,3],
"Settings":[false,"DockedOnly","leftzone","0","155",0,0,0]}
Is there anyway to deserialize to something like the following?
[Serializable]
public class WidgetProps
{
public bool Visible { get; set; }
public string DockState { get; set; }
public string Zone { get; set; }
public string Top { get; set; }
public string Left { get; set; }
public int UnusedA { get; set; }
public int UnusedB { get; set; }
public int Position { get; set; }
}
[Serializable]
public class WidgetLayout
{
public WidgetProps Visits { get; set; }
public WidgetProps Weather { get; set; }
public WidgetProps ContactUs { get; set; }
public WidgetProps Birthdays { get; set; }
public WidgetProps Reminders { get; set; }
public WidgetProps Messages { get; set; }
public WidgetProps Availability { get; set; }
public WidgetProps Settings { get; set; }
}
or
public class Widget
{
public string WidgetName { get; set; }
public WidgetProps props { get; set; }
}
List<Widget> MyWidgets;
I am given the json string so I can't change how it is given to me but maybe I could tinker with it after I get it so it will work.
I tried:
string s = "{\"Visits\":[true,\"DockedOnly\",\"leftZone\",\"0\",\"500\",0,0,0],\"Weather\":[true,\"DockedOnly\",\"leftZone\",\"0\",\"0\",0,0,1],\"ContactUs\":[true,\"DockedOnly\",\"leftZone\",\"0\",\"317\",0,0,2],\"Birthdays\":[true,\"DockedOnly\",\"middleZone\",\"0\",\"0\",0,0,0],\"Reminders\":[true,\"DockedOnly\",\"middleZone\",\"0\",\"145\",0,0,1],\"Messages\":[true,\"DockedOnly\",\"middleZone\",\"0\",\"0\",0,0,2],\"Availability\":[true,\"DockedOnly\",\"middleZone\",\"0\",\"0\",0,0,3],\"Settings\":[false,\"DockedOnly\",\"leftzone\",\"0\",\"155\",0,0,0]}}";
var sd = new JavaScriptSerializer().Deserialize < List<Widget>>(s);
and
var sd = new JavaScriptSerializer().Deserialize < WidgetLayout >(s);
This isn't working because you're trying to deserialize an array into an object. The json.NET deserializer will not be able make that conversion.
Because your json arrays have multiple types in them you'll have to deserialize into the smallest common denominator, in this case, object. From there I would recommend writing a method to assign each index to it's corresponding property in WidgetProps.
So basically, define this constructor;
public WidgetProps(object[] props)
{
Visible = (bool)props[0];
DockState = (string)props[1];
// ext
}
I would have something like a WidgetDirty class that I do the initial deserilization into. From there you can create a new instance of WidgetLayout by instantiating each of it's properties like myWidgetLayoutInstance.Visits = new WidgetProp(myWidgetDirtyInstance.Visits); I'd probably hide this mess in a WidgetLayout constructor that takes a WidgetDirty as it's only arg.
yes it's disgusting... but I don't know of any real alternatives because that json's design just isn't very compatible with the C# language. If you're strongly apposed to this I might look at the dynamic type. I haven't used it in C# and probably never will, but I know that deserializing that in a dynamic language like PHP would be no trouble at all.
This doesn't work, because array is normally not deserialized as an object. If possible, I think you should fix the JSON. If you can't do that, and you're using JSON.NET, you can create JsonConverter for WidgetProps that manually converts the array to the object:
class WidgetPropsConverter : JsonConverter
{
public override void WriteJson(
JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException();
}
public override object ReadJson(
JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
var array = serializer.Deserialize<object[]>(reader);
return new WidgetProps
{
Visible = (bool)array[0],
DockState = (string)array[1],
Zone = (string)array[2],
Top = (string)array[3],
Left = (string)array[4],
Position = (int)(long)array[7]
};
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(WidgetProps);
}
}
You would then use it like this:
var result = JsonConvert.DeserializeObject<WidgetLayout>(
jsonString, new WidgetPropsConverter());
This is a continuation of a previous question of mine. The solution worked for what I was trying to do at the time but broke a whole lot of my code. I know it was bad practice not to make sure beforehand but yeah... you live and learn.
Anyhoo, here's the Q: an easy way to serialise c# objects
What I want to know is: is there any way to get the NewtonSoft Library to handle this stuff? If yes, how? If no, suggestions?
What i'm doing is chatting to a RoR3 app using json, now I cant deserialise the response. here's a little code:
The response i'm getting from RoR looks like:
[{"directory":{"created_at":"2011-07-20T22:29:38Z","drive_info":1,"id":15,"name":"New Drive","parent":0,"size":0,"updated_at":"2011-07-20T22:29:39Z","user":1}}]
I'm trying to deserialise it into a list of Directory objects using:
public static CompositeCollection deserialise<T>(string json)
{
CompositeCollection result = new CompositeCollection();
JArray arr = JArray.Parse(json);
foreach (JObject obj in arr)
{
result.Add(JsonConvert.DeserializeObject<T>(obj.First.First.ToString()));
}
return result;
}
and the relevant part of the directory class looks like:
// [Serializable]
// [DataContract]
public class Directory
{
// [DataMember]
public int id { get; set; }
// [DataMember]
public string name { get; set; }
// [DataMember]
public int parent { get; set; }
// [DataMember]
public int drive_info { get; set; }
// [DataMember]
public int size { get; set; }
// [DataMember]
public int user { get; set; }
// [DataMember]
public string state
{
get
{
/* if (parent == 0)
return _state.identify();
Directory parental;
return parental.state;*/
if (parental != null)
return parental.state;
return _state.identify();
}
set
{
_state = StateFactory.getState(value);
}
}
//[JsonIgnore]
blah...
I can deserialise most of the time by uncommenting [Serializable] (sometimes i get the following error: Object of type 'System.Int32' cannot be converted to type 'OffloadUI.Directory'. still investigating), and I can serialise by uncomenting [DataContract] and all instances of [DataMember]. What i need is something that will work in both directions.
Thanks to Zootius I found a useful guide. Here's what i did, works like a bought one:
[JsonObject(MemberSerialization.OptIn)]
public class Directory
{
[JsonProperty]
public int id { get; set; }
[JsonProperty]
public string name { get; set; }
[JsonProperty]
public int parent { get; set; }