.net property won't deserialize from json to .net object [duplicate] - c#

I searched through similar questions and couldn't find anything that quite matched what i was looking for.
New to C# so bear with me please.
I have some json files that i am deserializing. I want the files to deserialize to objects of the correct type, without having to define the type before hand. Here's my code:
public class loadJson
{
//path of the file location
public void readJson(string path)
{
//array of files at the path location. right now just reading one file
FileInfo[] files = new DirectoryInfo(path).GetFiles("seleniumExample.json").ToArray();
foreach (FileInfo fi in files)
{
dynamic b1 = null;
using (StreamReader file = new StreamReader(fi.FullName))
{
string fileText = file.ReadToEnd();
//Console.WriteLine(fileText);
try
{
b1 = Newtonsoft.Json.JsonConvert.DeserializeObject(fileText);
}
catch(Exception e)
{
Console.WriteLine("ERROR!!!! " + e.ToString());
}
file.Close();
}
}
}
}
I have a bunch of object types that I will be feeding into my program through json files.
I don't want to have to explicitly call b1 a Bid, or a Client, or any other specific predefined class. If I do explicitly call b1 a Bid, it loads all the info just fine and fills out the correct instance variables.
But when I use "dynamic", or general "object", it can't figure it out and just initializes to an "object".
Is there a way to perform generic deserialization and have it create an object of the correct class based on the fields defined in the json file?
Thanks in advance for the help, and i apologize if my question is incredibly unclear. If so, please just let me know how I can help clear up any ambiguity. Thanks again.

Json.NET has the ability to record the .Net object type of polymorphic types during serialization, by using the setting TypeNameHandling = TypeNameHandling.Auto. When the setting is enabled the .Net type of polymorphic objects will appear as a synthetic property called "$type", for instance:
"$type": "Newtonsoft.Json.Samples.Stockholder, Newtonsoft.Json.Tests"
However, the "$type" property is never emitted for the root object if you call the conventional methods JsonConvert.SerializeObject(Object) or JsonSerializer.Serialize(TextWriter, Object). Instead, you must use one of the serialization methods that accepts an "expected" root type, for instance SerializeObject(Object, Type, JsonSerializerSettings) or JsonSerializer.Serialize(TextWriter, Object, Type). Passing typeof(object) as the expected type guarantees the type property will appear:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
var json = JsonConvert.SerializeObject(rootObject, typeof(object), settings);
If you create your JSON files using this setting, the JSON itself will remember the type of object serialized. This type will be used by Json.NET during deserialization, as long as you use set TypeNameHandling to something other than TypeNameHandling.None. e.g.:
var settings = new Newtonsoft.Json.JsonSerializerSettings { TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto };
b1 = Newtonsoft.Json.JsonConvert.DeserializeObject(fileText, settings);
Working sample .Net fiddle here.
Caveats: this way of storing .Net types in JSON is nonstandard. Other serializers such as DataContractJsonSerializer do not process type information in this format.
Note also this caution from the Newtonsoft docs:
TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than None.
For a discussion of why this may be necessary, see TypeNameHandling caution in Newtonsoft Json, How to configure Json.NET to create a vulnerable web API, and Alvaro Muñoz & Oleksandr Mirosh's blackhat paper https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf.

Deserialize your JSON into the most basic form:
Dictionary<string, object> theData= new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(jsonString);
string baseItemName = (string)theData["baseItem"];
Dictionary<string, object> someNode= (Dictionary<string, object>)theData["something"];
string anything = (string)someNode["anything"];
string nothing = (string)someNode["nothing"];
The call to Deserialize() creates a tree of Dictionary<string, object> that you can traverse at will.

Related

How to serialize Dynamics CRM metadata

I am trying to serialize a complete set of Dynamics CRM metdata, using roughly the following code:
RetrieveAllEntitiesRequest metaDataRequest = new RetrieveAllEntitiesRequest()
{
EntityFilters = EntityFilters.All
};
// Execute the request
RetrieveAllEntitiesResponse metaDataResponse = (RetrieveAllEntitiesResponse)service.Execute(metaDataRequest);
entitiesMetadata = metaDataResponse.EntityMetadata;
// Store Metadata for faster usage in the future
Serialize<EntityMetadata[]>(entitiesMetadata, "foobar_metadata.xml");
public static void Serialize<T>(T value, string filePath)
{
if (value == null)
{
return;
}
try
{
var xmlserializer = new XmlSerializer(typeof(T));
var stringWriter = new StringWriter();
using (var writer = new XmlTextWriter(stringWriter) { Formatting = System.Xml.Formatting.Indented })
{
xmlserializer.Serialize(writer, value);
File.WriteAllText(filePath, stringWriter.ToString());
}
}
catch (Exception ex)
{
throw new Exception("An error occurred", ex);
}
}
Yet, some of the metadata classes do not have parameterless constructors. So I get the following exception:
[...] cannot be serialized because it does not have a parameterless constructor
I know that the common advice is to extend the affected classes and give them a parameterless constructor. Yet, this could mean many iterations of trial and error as many classes are involved in the Dynamics CRM metadata.
Is there any other way of serializing/deserializing, which doesn't need a parameterless constructor for each class?
Did somebody go through the effort of extending classes for Dynamics CRM metadata and can share the code?
Is there a possibility to automatically omit any non-serializable classes and only serialize the rest?
I have never manually serialized an entity's metadata. Fortunately, exporting a solution that contains an entity serializes the metadata.
While adding the constructors might allow you to get over the hump with "manual" serializing, you could programmatically create a solution, add all the entities to it, and export it as an unmanaged solution.
The exported solution will be a zip file. All of the entities' metadata will be the cutomizations.xml file. You could then parse that XML and split each entity out to its own file.
Out of curiosity, what is driving the requirement to serialize the metadata? Is it for documentation purposes?

How to deserialize JSON to objects of the correct type, without having to define the type before hand?

I searched through similar questions and couldn't find anything that quite matched what i was looking for.
New to C# so bear with me please.
I have some json files that i am deserializing. I want the files to deserialize to objects of the correct type, without having to define the type before hand. Here's my code:
public class loadJson
{
//path of the file location
public void readJson(string path)
{
//array of files at the path location. right now just reading one file
FileInfo[] files = new DirectoryInfo(path).GetFiles("seleniumExample.json").ToArray();
foreach (FileInfo fi in files)
{
dynamic b1 = null;
using (StreamReader file = new StreamReader(fi.FullName))
{
string fileText = file.ReadToEnd();
//Console.WriteLine(fileText);
try
{
b1 = Newtonsoft.Json.JsonConvert.DeserializeObject(fileText);
}
catch(Exception e)
{
Console.WriteLine("ERROR!!!! " + e.ToString());
}
file.Close();
}
}
}
}
I have a bunch of object types that I will be feeding into my program through json files.
I don't want to have to explicitly call b1 a Bid, or a Client, or any other specific predefined class. If I do explicitly call b1 a Bid, it loads all the info just fine and fills out the correct instance variables.
But when I use "dynamic", or general "object", it can't figure it out and just initializes to an "object".
Is there a way to perform generic deserialization and have it create an object of the correct class based on the fields defined in the json file?
Thanks in advance for the help, and i apologize if my question is incredibly unclear. If so, please just let me know how I can help clear up any ambiguity. Thanks again.
Json.NET has the ability to record the .Net object type of polymorphic types during serialization, by using the setting TypeNameHandling = TypeNameHandling.Auto. When the setting is enabled the .Net type of polymorphic objects will appear as a synthetic property called "$type", for instance:
"$type": "Newtonsoft.Json.Samples.Stockholder, Newtonsoft.Json.Tests"
However, the "$type" property is never emitted for the root object if you call the conventional methods JsonConvert.SerializeObject(Object) or JsonSerializer.Serialize(TextWriter, Object). Instead, you must use one of the serialization methods that accepts an "expected" root type, for instance SerializeObject(Object, Type, JsonSerializerSettings) or JsonSerializer.Serialize(TextWriter, Object, Type). Passing typeof(object) as the expected type guarantees the type property will appear:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
var json = JsonConvert.SerializeObject(rootObject, typeof(object), settings);
If you create your JSON files using this setting, the JSON itself will remember the type of object serialized. This type will be used by Json.NET during deserialization, as long as you use set TypeNameHandling to something other than TypeNameHandling.None. e.g.:
var settings = new Newtonsoft.Json.JsonSerializerSettings { TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto };
b1 = Newtonsoft.Json.JsonConvert.DeserializeObject(fileText, settings);
Working sample .Net fiddle here.
Caveats: this way of storing .Net types in JSON is nonstandard. Other serializers such as DataContractJsonSerializer do not process type information in this format.
Note also this caution from the Newtonsoft docs:
TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than None.
For a discussion of why this may be necessary, see TypeNameHandling caution in Newtonsoft Json, How to configure Json.NET to create a vulnerable web API, and Alvaro Muñoz & Oleksandr Mirosh's blackhat paper https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf.
Deserialize your JSON into the most basic form:
Dictionary<string, object> theData= new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(jsonString);
string baseItemName = (string)theData["baseItem"];
Dictionary<string, object> someNode= (Dictionary<string, object>)theData["something"];
string anything = (string)someNode["anything"];
string nothing = (string)someNode["nothing"];
The call to Deserialize() creates a tree of Dictionary<string, object> that you can traverse at will.

how to use the return data in json format in c#?

I'm using HttpWebRequest method to "GET" data from a specific url that the returned data supposed to be in json format. My code are something like
WebRequest request = WebRequest.Create("https://xxx.xxxxxxxx.com/xxxxxxx");
request.Method = "GET";
request.ContentType = "application/json";
var response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
}
The responseText value as I observed are
[
{
"webinarKey":5303085652037254656,
"subject":"Test+Webinar+One",
"description":"Test+Webinar+One+Description",
"organizerKey":73563532324,
"times":[{"startTime":"2011-04-26T17:00:00Z","endTime":"2011-04-26T18:00:00Z"}]
},
{
"webinarKey":9068582024170238208,
"name":"Test+Webinar+Two",
"description":"Test Webinar Two Description",
"organizerKey":73563532324,
"times":[{"startTime":"2011-04-26T17:00:00Z","endTime":"2011-04-26T18:00:00Z"}]
}
]
As you can see it is in json format, but I don't know how to set it as a json object, so I can get it's field value as something like
string webinarKey=responseText[0].webinarKey;
Am I right?
JavaScriptSerializer ser = new JavaScriptSerializer();
MyClass package = null;
package = ser.Deserialize<MyClass>(item);
Where item is your response text, and MyClass is the .net class you are returning. then you can access the properties of your object.
You have to parse the response (that is a textstring with JSON) with a JSON parser/deserializer. For example: Json.net
http://msdn.microsoft.com/en-us/library/bb412179.aspx
WCF has a DataContractJSONDeserializer.
You would need to define your types as .net objects that had properties that "look" like the json data coming back. I don't get the impression that you are actually using WCF in your application but you may still be able to use the DataContractJSONDeserializer anyway. You just need to instruct it the type you want it to deserialze as and the type needs to be marked with a DataContract attribute.
Heres plenty more info
http://msdn.microsoft.com/en-us/library/bb412170.aspx
You can almost always get away with using the JavaScriptSerializer class. There will be numerous variations on this, and I can see suggestions in other answers already, though this might well suffice. Namely, you'll want to look into the Deserialize<T> method, with a signature of:
public T Deserialize<T>(
string input
)
One advantage, if this suits, is that it is a readily available class in System.Web.Extension and removes the requirement for 'third party components'.
One possibility for this is to use a JObject instance. YOu can pass it a string and then extract the values easily:
JObject jobj = JObject.Parse(resultString);
someValue = jobj[0]["webinarKey"];

Control XML element name dynamically during serialization

here's my problem to be solved: I've a plugin-structure for multimedia shows that allows to implement media types in external assemblies by subclassing from a base class in my framework. A show holds a list of media types. Shows are loaded and saved in XML using the XmlSerializer. This all works, even with programatic type mapping for plugin MediaTypes.
However, I want to be able to load XML files that contain MediaTypes that are not known, because the plugin isn't available.
For illustration, here is such an XML file:
<MultiMediaShow>
<MediaTypes>
<SomeType />
<SomeType />
<AnotherType />
<UnknownTypeFromPluginNotLoaded />
</MediaTypes>
</MultiMediaShow>
In the above example, I assume 2 "known" MediaTypes SomeType and AnotherType, comming from 2 plugin assemblies. The third type (UnknownTypeFromPluginNotLoaded) is unknown.
I'm already able to deserialize such unknown objects, but struggle with the serialization. In my aplication, I've the following code so far:
// To be implemented / subclassed by plugin assembly types
public abstract class MediaType
{
}
public class UnknownMediaType : MediaType
{
[XmlAnyElement]
public XmlElement[] UnknownChildElements;
[XmlAnyAttribute]
public XmlAttibute[] UnknownAttributes;
[XmlIgnore]
public string XmlTagName; // stores the xml element tag name in the original document
}
[XmlRoot("MultimediaShow")]
public class MultimediaShow
{
public List<MediaType> MediaTypes = new List<MediaType>();
}
When deserializing this with XmlSerializer, I use the event UnknownElement and manually insert an UnknownMediaType element into show.MediaTypes:
void HandleUnknownElements(Show show, List<XmlElementEventArgs> unknownElementEvents, XmlAttributeOverrides overrides)
{
// add a root attribute to UnknownMediaType
XmlAttributes attrs = new XmlAttributes();
XmlRootAttribute xmlRoot = new XmlRootAttribute(e.Element.Name);
attrs.XmlRoot = xmlRoot;
XmlAttributeOverrides o = new XmlAttributeOverrides();
o.Add(typeof(UnknownMediaObject), attrs);
// use a new XmlSerializer and a memory stream for deserializting the object as UnknownMediaType.
XmlSerializer xmlSerializer = new XmlSerializer(typeof(UnknownMediaType), o);
using (MemoryStream memoryStream = new MemoryStream())
{
XmlDocument doc = new XmlDocument();
doc.AppendChild(doc.ImportNode(e.Element, true));
doc.Save(memoryStream);
memoryStream.Position = 0;
try
{
// deserialize the object, store the XML element name and insert it into the chapter
UnknownMediaType t = xmlSerializer.Deserialize(memoryStream) as UnknownMediaObject;
t.XmlTagName = e.Element.Name;
show.MediaTypes.Add(t);
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine(exc.ToString());
//return objectType.IsByRef ? null : Activator.CreateInstance(objectType);
}
}
}
The BIG BIG problem is that such an event doesn't seem to be available when serializing an object. What I get as output (not very surpising) is:
<MultiMediaShow>
<MediaTypes>
<SomeType />
<SomeType />
<AnotherType />
<UnknownMediaType /> // !!!! was 'UnknownTypeFromPluginNotLoaded' !!!!
</MediaTypes>
</MultiMediaShow>
However, this is obviously not the same as what I've deserialized. So the question is, how would I best solve this problem?!?!
All help highly appreciated!!
Cheers,
Felix
UPDATE
I was wondering if it is possible to generate classes programmatically that derive from UnknownMediaType and have the class name taken from the UnknownMediaType.XmlTagName. Or, alternativly, to have an attribute for specifying the XML tag name of a class??
Cheers,
Felix
In fact, I implemented some working solution based on building types dynamically. So far, it's doing what I want. The only downside I see at the moment is that I create them into the current app domain, so I can't unload them (e.g. if a new show is loaded or if the plugins would be made available at runtime).
Here's my code:
void HandleUnknownElements(Show show, List<XmlElementEventArgs> unknownElementEvents, XmlAttributeOverrides overrides)
{
foreach (XmlElementEventArgs e in unknownElementEvents)
{
// (1) Dynamically create a type that simply inherits from UnknownMediaType
AssemblyName assName = new AssemblyName("Show Dynamic Type " + e.Element.Name + " Assembly");
AssemblyBuilder assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);
ModuleBuilder modBuilder = assBuilder.DefineDynamicModule(assBuilder.GetName().Name);
TypeBuilder typeBuilder = modBuilder.DefineType(e.Element.Name, TypeAttributes.Class | TypeAttributes.Public, typeof(UnknownMediaType));
Type objectType = typeBuilder.CreateType();
// (2) Add a root attribute to the type as override
XmlAttributes attrs = new XmlAttributes();
XmlRootAttribute xmlRoot = new XmlRootAttribute(e.Element.Name);
attrs.XmlRoot = xmlRoot;
XmlAttributeOverrides o = new XmlAttributeOverrides();
o.Add(objectType, attrs);
// (3) Use a memory stream for creating a temporary XML document that will be deserialized
using (MemoryStream memoryStream = new MemoryStream())
{
XmlDocument doc = new XmlDocument();
doc.AppendChild(doc.ImportNode(e.Element, true));
doc.Save(memoryStream);
memoryStream.Position = 0;
// (4) Deserialize the object using an XmlSerializer and add it
try
{
XmlSerializer xmlSerializer = new XmlSerializer(objectType, o);
UnknownMediaType t = xmlSerializer.Deserialize(memoryStream) as UnknownMediaType;
show.MediaTypes.Add(t);
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine(exc.ToString());
}
}
}
}
Would be glad if you'd post any issues with this and your concerns...
Cheers,
Felix
See whether you can implement the IXmlSerializable interface for your root class.
From MSDN:
There are two reasons to implement
this interface. The first is to
control how your object is serialized
or deserialized by the XmlSerializer.
For example, you can chunk data into
bytes instead of buffering large data
sets, and also avoid the inflation
that occurs when the data is encoded
using Base64 encoding. To control the
serialization, implement the ReadXml
and WriteXml methods to control the
XmlReader and XmlWriter classes used
to read and write the XML. For an
example of this, see How To: Chunk
Serialized Data.
The second reason is to be able to
control the schema. To enable this,
you must apply the
XmlSchemaProviderAttribute to the
serializable type, and specify the
name of the static member that returns
the schema. See the
XmlSchemaProviderAttribute for an
example.
A class that implements the interface
must have a parameterless constructor.
This is a requirement of the
XmlSerializer class
You can implement a customer serializer. It is more work than using the xmlserializer, but gives you full control. See: http://msdn.microsoft.com/en-us/library/ty01x675(v=vs.80).aspx

How do I serialize a C# anonymous type to a JSON string?

I'm attempting to use the following code to serialize an anonymous type to JSON:
var serializer = new DataContractJsonSerializer(thing.GetType());
var ms = new MemoryStream();
serializer.WriteObject(ms, thing);
var json = Encoding.Default.GetString(ms.ToArray());
However, I get the following exception when this is executed:
Type
'<>f__AnonymousType1`3[System.Int32,System.Int32,System.Object[]]'
cannot be serialized. Consider marking
it with the DataContractAttribute
attribute, and marking all of its
members you want serialized with the
DataMemberAttribute attribute. See
the Microsoft .NET Framework
documentation for other supported
types.
I can't apply attributes to an anonymous type (as far as I know). Is there another way to do this serialization or am I missing something?
Try the JavaScriptSerializer instead of the DataContractJsonSerializer
JavaScriptSerializer serializer = new JavaScriptSerializer();
var output = serializer.Serialize(your_anon_object);
As others have mentioned, Newtonsoft JSON.NET is a good option. Here is a specific example for simple JSON serialization:
return JsonConvert.SerializeObject(
new
{
DataElement1,
SomethingElse
});
I have found it to be a very flexible, versatile library.
You can try my ServiceStack JsonSerializer it's the fastest .NET JSON serializer at the moment. It supports serializing DataContract's, Any POCO Type, Interfaces, Late-bound objects including anonymous types, etc.
Basic Example
var customer = new Customer { Name="Joe Bloggs", Age=31 };
var json = customer.ToJson();
var fromJson = json.FromJson<Customer>();
Note: Only use Microsofts JavaScriptSerializer if performance is not important to you as I've had to leave it out of my benchmarks since its up to 40x-100x slower than the other JSON serializers.
For those checking this around the year 2020:
Microsoft's System.Text.Json namespace is the new king in town. In terms of performance, it is the best as far as I can tell:
var model = new Model
{
Name = "Test Name",
Age = 5
};
string json = JsonSerializer.Serialize(model);
As some others have mentioned, NewtonSoft.Json is a very nice library as well.
The fastest way I found was this:
var obj = new {Id = thing.Id, Name = thing.Name, Age = 30};
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(obj);
Namespace: System.Web.Script.Serialization.JavaScriptSerializer
Please note this is from 2008. Today I would argue that the serializer should be built in and that you can probably use swagger + attributes to inform consumers about your endpoint and return data.
Iwould argue that you shouldn't be serializing an anonymous type. I know the temptation here; you want to quickly generate some throw-away types that are just going to be used in a loosely type environment aka Javascript in the browser. Still, I would create an actual type and decorate it as Serializable. Then you can strongly type your web methods. While this doesn't matter one iota for Javascript, it does add some self-documentation to the method. Any reasonably experienced programmer will be able to look at the function signature and say, "Oh, this is type Foo! I know how that should look in JSON."
Having said that, you might try JSON.Net to do the serialization. I have no idea if it will work
You could use Newtonsoft.Json.
var warningJSON = JsonConvert.SerializeObject(new {
warningMessage = "You have been warned..."
});
A faster alternative with Microsofts' new library on System.Text.Json
var warningJSON = JsonSerializer.Serialize(new {
warningMessage = "You have been warned..."
});
Assuming you are using this for a web service, you can just apply the following attribute to the class:
[System.Web.Script.Services.ScriptService]
Then the following attribute to each method that should return Json:
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
And set the return type for the methods to be "object"
public static class JsonSerializer
{
public static string Serialize<T>(this T data)
{
try
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
var stream = new MemoryStream();
serializer.WriteObject(stream, data);
string jsonData = Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length);
stream.Close();
return jsonData;
}
catch
{
return "";
}
}
public static T Deserialize<T>(this string jsonData)
{
try
{
DataContractJsonSerializer slzr = new DataContractJsonSerializer(typeof(T));
var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonData));
T data = (T)slzr.ReadObject(stream);
stream.Close();
return data;
}
catch
{
return default(T);
}
}
}

Categories