RestSharp/Json.NET Serialize Array as JSON Object - c#

I have a slight situation. I'm interacting with a web service using RestSharp, where the service is requiring me to send the following as part of the request:
{
"a":"a value",
"b":"b value"
}
Which is all fine and dandy, because you could simply use a class such as this:
public class MyClass
{
public string A { get; set; }
public string B { get; set; }
}
However, I do not know know the property names at runtime. Therefore, I attempted to use an ExpandoObject, but of course, this simply serialized as a JSON array:
[
"a":"a value",
"b":"b value"
]
So, it would seem that I need to be able to serialize (and deserialize) a Dictionary (or IEnumerable<KeyValuePair<string, string>>) as a JSON object (in other words, use curly braces instead of a brackets).
Does anyone know how I might do this, preferably by using a Json.NET attribute, such that the functionality may be reused elsewhere?

how about using a JObject?
var obj = new JObject();
obj["One"] = "Value One";
obj["Two"] = "Value Two";
obj["Three"] = "Value Three";
var serialized = obj.ToString(Formatting.None);
gives you
{"One":"Value One","Two":"Value Two","Three":"Value Three"}

Use JavascripSerializer object from .net class libs. It supports reflection on the object it is serializing
see msdn docs

Related

C# Deserializing JSON to class dependent on a type property

Let's say I have this little json snippet:
{
"Type": "Bar",
"BarOnly": "This is a string readable when deserialized to the Bar class only, as declared in my type key"
}
I also have these three classes:
public class Base
{
public enum SampleEnum
{
Bar,
Baz,
}
public SampleEnum Type
{
get;
set;
}
}
public class Bar : Base
{
public string BarOnly
{
get;
set;
}
}
public class Baz : Base
{
public string BazOnly
{
get;
set;
}
}
Based on the Type property in the json snippet, I'd like to have it deserialize to either Bar or Baz.
My first idea was to first deserialize it to the Base class, and then use its type and a switch statement to deserialize the JSON again to its respective class. (Using Newtonsoft.Json)
var type = JsonConvert.DeserializeObject<Base>(json).Type;
string message = "";
switch (type)
{
case (Base.SampleEnum.Bar):
message = JsonConvert.DeserializeObject<Bar>(json).BarOnly;
break;
case (Base.SampleEnum.Baz):
message = JsonConvert.DeserializeObject<Baz>(json).BazOnly;
break;
}
Console.WriteLine(message);
Needless to say that this process is extremely redundant, tedious and, since the switch statement is hard-coded, not very "dynamic" at all.
Another idea was to use a generic class as the base class instead and passing in the type of the actual class it should deserialize to, but then I end up with the same switch statement to figure out what that class should be.
Since you can't map enums to class types, I also thought about using a Dictionary to map the possible enum values to their class counterparts; this still makes the mapping process hard-coded though.
Is there any way I can dynamically get the corresponding class to deserialize to based on the type property of the json object?
EDIT: There seems to be some confusion about how this is supposed to be used and how the data is fetched; let me provide some background information.
I'm iterating through a directory with a lot of different spreadsheet files, mostly CSVs and XML files. Each of these feeds have a "meta file", describing how to process their content. This includes checksums, delimiters and other information. They also declare of what type their parent file is (CSV, XML etc). Hence, they share a lot of common properties (like the Base class in my example), but also have their own set of properties. They derive from an abstract class that requires them to implement a function that returns an instance of the corresponding feed processing class, initialized with values directly from within the meta class. I hope this makes sense.
#OguzOzgul commenting is correct. I've done this countless of times for objects that are composed with interfaces that need to be serialized and deserialized.
See TypeNameHandling for Newtonsoft:
https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm
Your json file will look ever so slightly different:
{
"$type": "SomeNamespace.Bar",
"BarOnly": "This is a string readable when deserialized to the Bar class only, as declared in my type key"
}
If you use
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
}
During serialization, it will add the full type name of all objects to make sure newtonsoft knows what their type is during deserialization (given you use the same settings then). That way you do not have to write your own custom code for type detection.

C# Dynamic Type Initialization From JSON

I am trying to dynamically instantiate a class from my visual studio solution based on a JSON string.
Before I describe my exact issue I want to give an example of what I want to achieve.
Say I have the following JSON :
{
"Type": "AutoIncrementTag,
"StartFrom": 0,
"Skip": 10,
"LeadingZero": false
}
So from that Json, I want to find the class called "AutoIncrementTag" and instantiate it, setting its "StartFrom", "Skip" and "LeadingZero" parameters to the correspoding values.
Note 1: I have a couple of theese "Tag" classes and I want to instantiate a different on the "Type" attribute in my Json string.
Note 2: My Json string will contain more than 1 of these class "descriptions" (I believe they are called JSON Objects but I'm not too familliar with the JSON format just yet)
Note 3: I am using Newtonsoft.Json for all the Json parsing/converting.
So, now for my issue.
I managed to get the Type property using
JObject.Parse(myJsonString).GetValue("Type").ToString();
However, how would I go about getting all the other values, since they will be different depending on what Type I have? (I need a way to dynamically iterate and get the values of the other properties.)
And second, how do I then map these properties to a C# object.
I thought about using
Activator.CreateInstance(Type type, object[] args)
But how can I (dynamically) get an object[] from the properties described in my json format.
JSON.Net (i.e. Newtonsoft.Json) does this for you already. For example, lets start off with a basic class:
public class Thing
{
public int SomeValue { get; set; }
public string AnotherValue { get; set; }
}
And an instance of it:
var thing = new Thing { SomeValue = 5, AnotherValue = "blah" };
We can deserialise with a custom settings object, specifically setting the TypeNameHandling property
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
};
var json = JsonConvert.SerializeObject(thing, settings);
Which will give output something like this:
{
"$type":"Thing, Namespace",
"SomeValue": 5,
"AnotherValue": "blah"
}
And to get it back into the right kind of object, just use the same settings:
var anotherThing = JsonConvert.DeserializeObject(json, settings);

Accessing properties with a dot in their name

I am trying to deserialize JSON. My root object has a single property "en.pickthall". I am using dynamic type for reading my JSON. I thought I could just do away with "." in the property since its a local JSON file but then there must be some way to access such a property
var result = App_Code.FileIOHelper.ReadFromDefaultFile("ms-appx:///Assets/en.pickthall.json");
dynamic stuff = JsonConvert.DeserializeObject(result);
foreach(var x in stuff.(en.pickthall)) //Tried this intellisense didn't like it
{
}
You could create a root class to deserialize into and use JsonProperty
public class Root
{
// Use the proper type instead of object
[JsonProperty(PropertyName = "en.pickthall")]
public IEnumerable<object> EnPickthall { get; set; }
public Root() { }
}
Used as follows
Root stuff = JsonConvert.DeserializeObject<Root>(result);
foreach(var x in stuff.EnPickthall)
{
}
You could serialize not to dynamic but to JObject and then access your property via
JObject stuff = JsonConvert.DeserializeObject<JObject>(Jsonstring);
var x = stuff.Value<String>("my.property")
C# doesn't have any way of quoting identifiers. If it's not a valid identifier, your only option is reflection.
However, it's possible the object returned by your JSON deserializer changed the identifiers to make them useable in C# - you might want to enumerate all the properties to check if that is the case. A dynamic object with indexers might also be a solution (allowing e.g. stuff["en.pickthall"]).
Another alternative is to change the way the serializer maps properties. For example, Newtonsoft.Jsoft allows you to customize this using a IContractResolver. It's quite easy to replace the . for something more C#-sane in this way.
I know you said you were using a dynamic type for your JSON deserialization, but I just wanted to point out that there is a .NET RESTful client out there that supports this with static model definitions too. For you or for anyone else who happens upon this response when searching for an answer to their problems with dots in property names in C# REST calls.
As of the newly released RestSharp 106.1.0 (and I do mean this version because this support was just added), it can handle renaming properties with a dot in their name via the DeserializeAs attribute. An example being when I call the ElasticSearch API for a _cat call with the following model:
public class CatResponse
{
public string index { get; set; }
...
[DeserializeAs(Name = "docs.count")]
public string docscount { get; set; }
}
And actually get back the docs.count property deserialized into docscount now:
var resource = $"_cat/indices/{indexPattern}?format=json&pretty=true";
var request = new RestRequest(resource, Method.GET);
var response = client.Execute<List<CatResponse>>(request);
This support is out of the box and doesn't need to use the Newtonsoft.Json.JsonSerializer which I have also heard is a possible solution to this problem but which I couldn't get to work.
With a dynamic object and NewtonSoft.Json:
dynamic json = JValue.Parse(result);
int Opens = Convert.ToInt32(json.opens);
int Clicks = Convert.ToInt32(json.clicks);
string State = json.state;

type xxxx not expected use xmlinclude or soapinclude

I have a curious case of this serialization issue - which has been asked many times on this site and I have gone through a few of these questions and tried the usual items to no avail:
Add [XmlInclude] to the class throwing the error
Remove namespaces
Add a different namespace to each class
To explain further, I have provided a simplified version of my code below. Essentially I am using a WebServiceHost object to run a RESTful service and one of my endpoints returns an object serialized as XML (I have annotated the object with [DataContract] and [DataMember] attributes). This object contains a SerializableDictionary<string, object> (here) where the value has been typed as object. I believe this is why it is failing:
Works fine when the value is assigned a primitive
When I assign a custom object to the KV pair V, I get the unexpected type exception probably because the Serializer does not know how to serilaize the object / some sort of namespacing issue
Obviously, I am unable to annotate Object.cs with [XmlInclude] and because it is a service and I am not myself serializing I cannot using something like
new Serializer(typeof(...), new Type[] { ... }}
Any idea's of what I can do? I thought about not typing the dict value as object and rtaher comething more concrete but the problem is that this value can take primitives or cusotm types. Some code to explain the above:
Edit: Updated the code below to make it more clear
[DataContract]
public class ResponseObject
{
[DataMember(Name = "data")]
public SerializableDictionary<string, object> Data { get;set; }
public ResponseObject()
{
Data = new SerializableDictionary<string, object>();
}
}
...
var d1 = new ResponseObject();
d1.Data.Add("some key", "some value"); //WORKS AND SERIALIZES PERFECLTY
var d2 = new ResponseObject();
d2.Data.Add("some other key", new SomeOtherObjecT());
var d3 = new ResponseObject();
d3.Data.Add("another key", d2); //THIS THROWS THE UNEXPECTED TYPE ERROR WHEN SEIRLAIZING SomeOtherObject
Edit: The error is thrown in SerializableDictionary where it is attempting to serialize an object of type ResponseObject. The two are in seperate projects - if that is significant?
Normally, you should add an [XmlInclude] to the ResponseObject class. In this case, it doesn't work because of the SerializableDictionary that you're using. That class creates another XmlSerializer in its implementation, and therefore it doesn't care about your [XmlInclude]'s. Basically it just cannot handle your use case. You should switch from the XmlSerializer to the DataContractSerializer which handles the Dictionary class and supports the [KnownType] attribute to register additional types: http://pastebin.com/vGLSaxHF . Also note that it's pointless to add [DataContract] and [DataMember] attributes in your current case because the XmlSerializer ignores those attributes, they are used by the DataContractSerializer only. Or if you're not sure how to change your serializer (I know I'm not) then you should either not be using a Dictionary or change the SerializableDictionary implementation to handle the dynamic object types that you want to use (find every line where it creates a new XmlSerializer). Or, as an alternative, define a base class for all your objects that you will ever put into the dictionary and do it like this:
[XmlInclude(typeof(Class1), XmlInclude(typeof(Class2)), etc]
public class AbstractBase { }
public class Class1 : AbstractBase { ... }
public class Class2 : AbstractBase { ... }
public class BigClass {
public SerializableDictionary<string, AbstractBase> Dictionary { get; set; }
}
This way, when the SerializableDictionary creates its own XmlSerializer, it will recognize the AbstractBase and from there, all of its descendants.

Deserialization of JSON object by using DataContractJsonSerializer in C#

I'm sure this question has been asked over and over again, but for some reason, I still can't manage to get this to work.
I want to deserialize a JSON object that contains a single member; a string array:
[{"idTercero":"cod_Tercero"}]
This is the class that I'm trying to deserialize into:
[DataContract]
public class rptaOk
{
[DataMember]
public string idTercero { get; set; }
public rptaOk() { }
public rptaOk(string idTercero)
{
this.idTercero = idTercero;
}
}
This is the method that I try to deserialize:
public T Deserialise<T>(string json)
{
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
T result = (T)deserializer.ReadObject(stream);
return result;
}
}
And so I try to fill the object:
rptaOk deserializedRpta = deserializarOk(rpta);
But for some reason, this returns ""
MessageBox.Show(deserializedRpta.idTercero);
Without any dependencies outside of the .net framework, you could do it this way
[DataContract(Name="rptaOk")]
public class RptaOk
{
[DataMember(Name="idTercero")]
public string IdTercero { get; set; }
}
[CollectionDataContract(Name="rptaOkList")]
public class RptaOkList : List<RptaOk>{}
var stream = new StreamReader(yourJsonObjectInStreamFormat);
var serializer = new DataContractSerializer(typeof(RptaOkList));
var result = (RptOkList) serializer.ReadObject(stream);
I don't know if your're wiling to change the library that you're using, but I use library "Newtonsoft.Json" to desserialize JSON objects, it's pretty easy to use
[HttpPost]
public void AddSell(string sellList)
{
var sellList = JsonConvert.DeserializeObject<List<Sell>>(sellListJson);
BD.SaveSellList(sellList);
}
As you can see you can deserialize a whole json object list to a List<> fo the type "Sell", an object that i've created... And, of course, you can do that to an array too. I don't know the correct syntax for this, but you can convert this list to an array afterwards
Hope this helps
I think you're making this a lot more difficult than it needs to be. Firstly, your sample json and the class you're trying to deserialize into do not have an array of strings. They have a single property of type string. Secondly, why are you using this class DataContractJsonSerializer? You're not doing anything with it that you can't get from a simple call to json.NET's generic deserialization method. I would remove all of your code except the class definition and replace it with this simple one liner;
rptaOk[] myInstances = JsonConvert.DeserializeObject<rptaOk>(jsonString);
Also, no matter what the structure of your json is, if you have a class to correctly model it that method will correctly deserialize it. If you want to enforce some kind of contract I recommend using json schemas which json.NET also supports. If you use a schema it enforces a rigid contract, if you attempt to deserialize into an object there is something of an implicit contract. I don't know every scenario which will cause it to throw, but if your json is too far from the class definition it will. If your class has properties that don't appear in the json I believe they will just get initialized with the default values for that type.
EDIT: I just noticed your json is actually an array of objects. So you simply need to make the lhs of that assignment an array or rptaOk objects, rather than a singleton.

Categories