Deserializing JSON from ASP.net web service into C# object - c#

After spending a day reading through posts here I still can't get this to work so hopefully this makes sense to someone here.
The web service returns this simple JSON
{"d":{"__type":"TestWebServices.Person","Name":"Bob","FavoriteColor":"Green","ID":0}}
Then I am using C# code to deserialize
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(Person));
Person someone = (Person)jsonSerializer.ReadObject(responseStream);
When I use this model someone is created but all the properties are null
[DataContract]
public class Person {
[DataMember]
public string Name { get; set; }
[DataMember]
public string FavoriteColor { get; set; }
[DataMember]
public int ID { get; set; }
}
I tried being more literal and used this model
[DataContract]
public class Person {
[DataMember]
public PersonItem d { get; set; }
}
[DataContract]
public class PersonItem {
[DataMember]
public string __Type { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string FavoriteColor { get; set; }
[DataMember]
public int ID { get; set; }
}
And got this error, which I don't even know where to start with
Element ':d' contains data from a type that maps to the name ':GEMiniWebServices.Person'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'TestWebServices.Person' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.
Any thoughts?
Thanks

__Type should never be part of your object. It's a hint to the serializer. Also, the type hint that you have in your JSON object is bad. Stand-Alone JSON Serialization says:
To preserve type identity, when serializing complex types to JSON a
"type hint" can be added, and the deserializer recognizes the hint and
acts appropriately. The "type hint" is a JSON key/value pair with the
key name of "__type" (two underscores followed by the word "type").
The value is a JSON string of the form
"DataContractName:DataContractNamespace" (anything up to the first
colon is the name).
The type hint is very similar to the xsi:type attribute defined by the
XML Schema Instance standard and used when serializing/deserializing
XML.
Data members called "__type" are forbidden due to potential conflict
with the type hint.
It works with the following if you rewrite the __type declaration as Person:#TestWebServices or eliminate it:
namespace TestWebServices
{
[KnownType(typeof(Person))]
[DataContract]
public class PersonWrapper
{
[DataMember]
public Person d { get; set; }
}
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string FavoriteColor { get; set; }
[DataMember]
public int ID { get; set; }
}
}

Try adding (and I'm kind of taking a bit of a stab here so the exact namespace my be incorrect)
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/TestWebServices.Person")]
to your DataContractAttribute on Person.
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/TestWebServices.Person")]
public class Person {
[DataMember]
public PersonItem d { get; set; }
}
[DataContract]
public class PersonItem {
[DataMember]
public string __Type { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string FavoriteColor { get; set; }
[DataMember]
public int ID { get; set; }
}

Related

Dynamic/Expando and JSON

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);

JSON.Net Deserialization of non-generic Root Objects

I'm currently working on a project where I make a request to the Riot Games API, parse the JSON, and do some stuff with it. I have the request working, and I know I'm getting valid JSON. My issue is using JSON.Net to deserialize the JSON.
The JSON is of the following structure:
{
"xarcies": {
"id": 31933985,
"name": "Farces",
"profileIconId": 588,
"revisionDate": 1450249383000,
"summonerLevel": 30
}
}
I want to load this data into the following class
[JsonObject(MemberSerialization.OptIn)]
class Summoner
{
[JsonProperty("id")]
public long id {get;set;}
[JsonProperty("name")]
public string name { get; set; }
[JsonProperty("profileIconId")]
public int profileIconId { get; set; }
[JsonProperty("revisionDate")]
public long revisionDate { get; set; }
[JsonProperty("summonerLevel")]
public long summonerLevel { get; set; }
}
The issue I'm having is that because I'm given a "xarcies" object that contains the information I need, I'm not sure how to go about designing a class that can accept the JSON data. I've seen some examples that use a RootObject class to take the object and that class has a subclass that all the pairs are put into, but I can't seem to get it to work. Every time I run it the attributes for the object end up being NULL.
You can deserialize your JSON as a Dictionary<string, Summoner>:
var root = JsonConvert.DeserializeObject<Dictionary<string, Summoner>>(jsonString);
The dictionary will be keyed by the user name, in this case "xarcies". See Deserialize a Dictionary.
I just used json2csharp to create the following class (its types look a bit different then yours):
public class UserData
{
public int id { get; set; }
public string name { get; set; }
public int profileIconId { get; set; }
public long revisionDate { get; set; }
public int summonerLevel { get; set; }
}
public class RootObject
{
public KeyValuePair<string, UserData> value { get; set; }
}

Json Deserialisation with subarrays doesn't contain values

I am trying to deserialise a json object. The Problem is that the the object also contains subarrays
http://i.imgur.com/WWwEVLR.png
Except for the subarrays everything is working.
I am using Newtonsoft.Json;
Here is my class
public string date_updated { get; set; }
public string date_expires { get; set; }
This is working fine.
For the subarray I did it that way:
public JsonArray contacts { get; set; }
This is my method to deserialise it:
var json = await webClient.GetAsync(new Uri(uri));
var result = await json.Content.ReadAsStringAsync();
Model = JsonConvert.DeserializeObject<Model>(result);
The Array is created well with all fields needed, but the values are not working.
The values are just: Windows.Json.JsonObject as on the picture below.
http://i.imgur.com/Q8bpCoD.png
Why is he not writing the values? How can I get them?
Thank you for your help.
The values are working fine. Using JsonArray tells the deserializer to convert the JSON data to something that is compatible with the type JsonArray. This type is simply a 1:1 representation of the JSON string underneath and is not deserialized into useful data automatically for you.
Also, JsonArray is not even part of the Json.Net library. As the debugger is telling you, it is part of the Windows.Data.Json namespace which is in a different library. You could still access the data directly from each JsonObjects using the various Get methods inside the class ( http://msdn.microsoft.com/en-us/library/windows.data.json.jsonobject.aspx ) but this is probably not the way you want to go.
In your case, you should create a class that represents the data you have inside each of those arrays. If not all entries in the array contains all of the properties of your class, don't worry. Json.Net will simply leave their value empty when deserializing. This will look like:
public class Contact
{
public string type { get; set; }
public string name { get; set; }
public string organization { get; set; }
public string full_address { get; set; }
etc.
}
For good measure, you should also respect the C# naming convention which states that properties should use CamelCase names. To help you with this, you can use the JsonProperty attribute like so:
public class Contact
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("organization")]
public string Organization { get; set; }
[JsonProperty("full_address")]
public string FullAddress { get; set; }
etc.
}
Then, you can replace the type of your contacts property to List<Contact> and the data will be automatically deserialized to a format that you can easily use.
Define new class
class Contact {
public string type { get; set; }
public string name { get; set; }
// etc
}
and modify your ReqInfo_WhoIs_Model class
public string date_updated { get; set; }
public string date_expires { get; set; }
public List<Contact> contacts { get; set; }

Why am I getting the exception "Consider using a DataContractResolver or add any types not known statically to the list of known types"

I'm trying to serialise a object to Xml using the DataContractSerializer. I have the following classes;
[ActiveRecord(Lazy = true)]
[KnownType(typeof(RoomType))]
[DataContract]
public class Room : ActiveRecordBase<Room>
{
[PrimaryKey]
[DataMember]
public virtual Int64 RoomId { get; protected set; }
[BelongsTo("RoomTypeId")]
[DataMember]
public virtual RoomType RoomType { get; set; }
[Property]
[DataMember]
public virtual Int64 HotelId { get; set; }
[Property]
[DataMember]
public virtual string Name { get; set; }
[Property]
[DataMember]
public virtual string Description { get; set; }
public static Room[] FindByHotelId(Int64 HotelId)
{
return (Room[])FindAllByProperty(typeof(Room), "HotelId", HotelId);
}
}
The RoomType class is
[ActiveRecord(Lazy = true)]
[DataContract]
public class RoomType : ActiveRecordBase<RoomType>
{
[PrimaryKey]
[DataMember]
public virtual int RoomTypeId { get; protected set; }
[Property]
[DataMember]
public virtual string Name { get; set; }
}
I use the following method to serialise the object
internal static XElement ObjectToXElement<T>(T source)
{
XDocument oXDocument = new XDocument();
try
{
using (var writer = oXDocument.CreateWriter())
{
// write xml into the writer
var serializer = new DataContractSerializer(source.GetType());
serializer.WriteObject(writer, source);
}
}
catch(Exception e)
{
using (var writer = oXDocument.CreateWriter())
{
// write xml into the writer
var serializer = new DataContractSerializer(oError.GetType());
serializer.WriteObject(writer, oError);
}
}
return oXDocument.Root;
}
The actual object I'm serialising is;
[KnownType(typeof(List<Room>))]
[KnownType(typeof(RoomType))]
[DataContract]
public class RoomTypeResponse
{
[DataMember]
public int Code { get; set; }
[DataMember]
public string Message { get; set; }
[DataMember]
public List<Room> Rooms { get; set; }
public RoomTypeResponse()
{
this.Rooms = new List<Room>();
}
}
But for some reason when I call the method to serialise the object I get the following exception;
Type 'Castle.Proxies.RoomTypeProxy' with data contract name
'RoomTypeProxy:http://schemas.datacontract.org/2004/07/Castle.Proxies'
is not expected. Consider using a DataContractResolver or add any
types not known statically to the list of known types - for example,
by using the KnownTypeAttribute attribute or by adding them to the
list of known types passed to DataContractSerializer.
If I comment out the property in Room class, it works fine
[BelongsTo("RoomTypeId")]
[DataMember]
public virtual RoomType RoomType { get; set; }
I'm not sure why I am getting the exception, because I've added the knowtype attribute for RoomType ? What am I missing, that is causing this problem.
The problem is that one type (Castle.Proxies.RoomTypeProxy) is generated at runtime, so .NET knows nothing about it. This is not an NHibernate-specific problem. If you disable lazy loading and proxy generation, the problem will go away, but I understand it might be difficult.
Other option would be to use another serializer, like BinaryFormatter, but I don't know if that will work for you.

ASP.net Web API: change class name when serializing

I have a Data Transfer Object class for a product
public class ProductDTO
{
public Guid Id { get; set; }
public string Name { get; set; }
// Other properties
}
When the Asp.net serializes the object in JSON (using JSON.NET) or in XML, it generates ProductDTO objects.
However, i want to change the name during serialization, from ProductDTO to Product, using some kind of attributes:
[Name("Product")]
public class ProductDTO
{
[Name("ProductId")]
public Guid Id { get; set; }
public string Name { get; set; }
// Other properties
}
How can i do this?
I can't see why the class name should make it into the JSON-serialized data, but as regards XML you should be able to control the type name via DataContractAttribute, specifically via the Name property:
using System.Runtime.Serialization;
[DataContract(Name = "Product")]
public class ProductDTO
{
[DataMember(Name="ProductId")]
public Guid Id { get; set; }
[DataMember]
public string Name { get; set; }
// Other properties
}
DataContractAttribute is relevant because the default XML serializer with ASP.NET Web API is DataContractSerializer. DataContractSerializer is configured through DataContractAttribute applied to serialized classes and DataMemberAttribute applied to serialized class members.
An option is to use the default .Net Serialization attributes for this:
[DataContract(Name = "Product")]
public class ProductDTO
{
[DataMember(Name = "ProductId")]
public Guid Id { get; set; }
[DataMember]
public string Name { get; set; }
// Other properties
}

Categories