C# - JsonSerializer - DataContract runtime error - c#

I call for to consume json rest web service.
My classes are:
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace WFAEsura
{
[DataContract]
class JsonResponse
{
[DataMember]
public string status { get; set; }
[DataMember]
public Result result { get; set; }
}
class Result
{
public string studentStatus { get; set; }
public List<Results> results { get; set; }
}
class Results
{
public string code { get; set; }
public string description { get; set; }
public double creditAmount { get; set; }
public int timeUnit { get; set; }
public string mark { get; set; }
public bool passed { get; set; }
public string staffMemberName { get; set; }
public List<Results> subResults { get; set; }
}
}
For to create these classes I've used
http://json2csharp.com/
My main class is
var syncClient = new WebClient();
string content = syncClient.DownloadString(baseUrl);
// Create the Json serializer and parse the response
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(JsonResponse));
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(content)))
{
// deserialize the JSON object
var jsonResponse = (JsonResponse)serializer.ReadObject(ms);
}
But in line jsonResponse = (JsonResponse)serializer.ReadObject(ms)
i've invalidDataContractException WFEsura.Result cann't be seralized.
Description is:
An unhandled exception of type 'System.Runtime.Serialization.InvalidDataContractException' occurred in System.Runtime.Serialization.dll
Additional information: Type 'WFAEsura.Result' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
In App.config i've
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
What am I doing wrong?

You must mark all classes and properties:
[DataContract]
class JsonResponse
{
[DataMember]
public string status { get; set; }
[DataMember]
public Result result { get; set; }
}
[DtaContract]
class Result
{
[DataMember]
public string studentStatus { get; set; }
[DataMember]
public List<Results> results { get; set; }
}
[DtaContract]
class Results
{
[DataMember]
public string code { get; set; }
[DataMember]
public string description { get; set; }
[DataMember]
public double creditAmount { get; set; }
[DataMember]
public int timeUnit { get; set; }
[DataMember]
public string mark { get; set; }
[DataMember]
public bool passed { get; set; }
[DataMember]
public string staffMemberName { get; set; }
[DataMember]
public List<Results> subResults { get; set; }
}

Related

AutoMapper - object to object different namespaces

I have a scenario where we have two services that reference an object definition dll which is called SLInterface.dll. This is just a compilation of our object model. This object is huge so I'll tone it down and give a snippet of the code:
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ComponentModel;
namespace SLInterface
{
[DataContract(Namespace = Utilities.strNamespace)]
public class EntityShipment
{
public EntityShipment()
{
lstEntityResponseStatus = new List<EntityResponseStatus>();
}
[DataMember]
public EntityAddress objShipTo
{
get;
set;
}
[DataMember]
public EntityToolKit ToolKit { get; set; }
[DataMember]
public List<EntityResponseStatus> lstEntityResponseStatus
{
get;
set;
}
}
}
namespace SLInterface
{
public class EntityAddress
{
[DataMember]
public String strCustomerID
{
get;
set;
}
[DataMember]
public String strCompanyName
{
get;
set;
}
[DataMember]
public String strContactName
{
get;
set;
}
[DataMember]
public String strAddressLine1
{
get;
set;
}
[DataMember]
public String strAddressLine2
{
get;
set;
}
[DataMember]
public String strAddressLine3
{
get;
set;
}
[DataMember]
public String strCity
{
get;
set;
}
[DataMember]
public String strState
{
get;
set;
}
[DataMember]
public String strPostalCode
{
get;
set;
}
[DataMember]
public String strCountryCode
{
get;
set;
}
[DataMember]
public String strCountryName
{
get;
set;
}
[DataMember]
public String strPhoneNumber
{
get;
set;
}
[DataMember]
public String strFaxNumber
{
get;
set;
}
[DataMember]
public Boolean blnRBDICheck
{
get;
set;
}
[DataMember]
public Boolean blnIsRBDI
{
get;
set;
}
[DataMember]
public String strPlantID
{
get;
set;
}
[DataMember]
public String strAccountNumber
{
get;
set;
}
[DataMember]
public String strEmailAddress
{
get;
set;
}
[DataMember]
public Boolean blnBlindShip
{
get;
set;
}
}
}
And Then there is another definition for toolkit and for EntityResponseStatus which I can post if it is needed.
We have a scenario where from ServiceA, we need to pass this object to ServiceB. We can't just pass this object that is filled during ServiceA as it is a different namespace. So we're trying to use AutoMapper so we don't have to map each property and it values individually.
Here is our AutoMapperCode:
public class ES
{
public ServiceA.SLInterface.EntityResponseStatus CallES(string strPrinterPath, string strShipmentNumber, string strCompanyCode)
{
Mapper.CreateMap<ServiceA.SLInterface.EntityShipment, ServiceB.SLInterface.EntityShipment>();
ServiceA.SLInterface.EntityResponseStatus objERS = new ServiceA.SLInterface.EntityResponseStatus();
objERS.StatusType = ServiceA.SLInterface.ResponseStatusType.SUCCESS;
ServiceA.SLInterface.EntityShipment objES = new ServiceA.SLInterface.EntityShipment();
objES = FillES(objES, strShipmentNumber, strCompanyCode);
Sage300 obj300 = new Sage300();
objES = obj300.Pull(objES);
ServiceB.SLInterface.EntityShipment objESES = new ServiceB.SLInterface.EntityShipment();
try
{
objESES = Mapper.Map<ServiceB.SLInterface.EntityShipment>(objES); //This is the line that we blow up on. The error message is "Missing type map configuration or unsupported mapping."
}
catch(AutoMapperConfigurationException amce)
{
ServiceA.SLInterface.EntityResponseStatus objERS1 = new ServiceA.SLInterface.EntityResponseStatus();
objERS1.Message = amce.Message;
}
catch (AutoMapperMappingException amme)
{
ServiceA.SLInterface.EntityResponseStatus objERS1 = new ServiceA.SLInterface.EntityResponseStatus();
objERS1.Message = amme.Message;
}
objESES = ServiceB.CallESShip(objESES,strPrinterPath);
return objERS;
}
In the try catch is where we get the error message
objESES = Mapper.Map<ServiceB.SLInterface.EntityShipment>(objES); //This is the line that we blow up on. The error message is "Missing type map configuration or unsupported mapping."
Both object models are exactly the same. Do we have to do a mapping for each object in the main object. Right now, we are thinking with the code that we have that it would be mapping everything from the root down exactly the same and then transferring over the data. Any help would be appreciated.
Thanks!

How can I de-serialize this json with C#?

With C#, I try without success to de-serialize this json content :
{
"code":200,
"message":"OK",
"name":"The name",
"description":"The description",
"tags":{
"0.1.3":{
"date":"2015-03-11",
"author":"SOMEONE",
},
"0.1.2":{
"date":"2015-03-11",
"author":"SOMEONE",
}
}
}
You have noticed, there's a list of "tag" objects, but I have not a table.
Beginning of the target classes :
[DataContract]
public class Project
{
[DataMember]
public int code { get; set; }
[DataMember]
public string message { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string description { get; set; }
[DataMember]
**How can I handle tags entries ?**
}
[DataContract]
public class Tag
{
[DataMember]
public string date { get; set; }
[DataMember]
public string author { get; set; }
}
If you're using JSON.NET, then you can have the following:
[DataContract]
public class Project
{
[DataMember]
public int code { get; set; }
[DataMember]
public string message { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string description { get; set; }
[DataMember]
public Dictionary<string, Tag> tags { get; set; }
}
[DataContract]
public class Tag
{
[DataMember]
public string date { get; set; }
[DataMember]
public string author { get; set; }
}
Which then you would use the following way (assuming responseString contains your JSON):
Project project = JsonConvert.DeserializeObject<Project>(responseString);
foreach (KeyValuePair<string, Tag> tag in project.tags)
{
Debug.WriteLine("Version: {0}", tag.Key);
Debug.WriteLine("Date: {0}", tag.Value.date);
Debug.WriteLine("Author: {0}", tag.Value.author);
}
The JSON input is valid according to RFC 4627 (JSON specfication).
http://www.freeformatter.com/json-validator.html
JSON sturcture is based on Key Value pair. Correct JSON format is like:
{
"object":{
"DataMember1":"String content",
"DataMember2":"String content",
"DataMember3":"String content"
},
"object2":{
"DataMember1":"String content",
"DataMember2":"String content"
}
}
Goto basics
To check your json structure you can validate from click here
Hmm, I was able to deserialize:
Newtonsoft.Json.JsonConvert.DeserializeObject<Project>(json);
However, here is my class definition:
public class Project
{
public string code { get; set; }
public string message { get; set; }
public string name { get; set; }
public string description { get; set; }
public Dictionary<string,Tag> tags { get; set; }
}
public class Tag
{
public string date { get; set; }
public string author { get; set; }
}
Thanks to Arturo Torres Sánchez. To get the "tag" entries, the declaration must be :
[DataContract]
public class Project
{
[DataMember]
public int code { get; set; }
[DataMember]
public string message { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string description { get; set; }
[DataMember]
public Dictionary<string, Tag> tags { get; set; }
}
And the most important, I must modify the default settings and use the new settings when I create the instance of DataContractJsonSerializer.
DataContractJsonSerializerSettings settings =
new DataContractJsonSerializerSettings();
settings.UseSimpleDictionaryFormat = true;
DataContractJsonSerializer serializer =
new DataContractJsonSerializer(typeof(Project), settings);
Project results = (Project)serializer.ReadObject(ms);
Without the settings.UseSimpleDictionaryFormat = true; tag's object count is 0.

C# JSON Object wont deserialize

So I have been able to get JSON objects for a few things, however this object is quite a bit more complex.
I'm trying to get comments from Reddit.
Here is the method I use:
public async Task<List<string>> GetComments(string currentSubreddit, string topicID)
{
string commentUrl = "http://www.reddit.com/r/" + currentSubreddit + "/comments/" + topicID + "/.json";
List<Comments> commentList = new List<Comments>();
string jsonText = await wc.GetJsonText(commentUrl);
Comments.RootObject deserializeObject = Newtonsoft.Json.JsonConvert.DeserializeObject<Comments.RootObject>(jsonText);
List<string> commentListTest = new List<string>();
//List<string> commentListTest = deserializeObject.data.children[0].data.children;
return commentListTest;
}
This is the GetJsonText method:
public async Task<string> GetJsonText(string url)
{
var request = WebRequest.Create(url);
string text;
request.ContentType = "application/json; charset=utf-8";
var response = (HttpWebResponse)await request.GetResponseAsync();
using (var sr = new StreamReader(response.GetResponseStream()))
{
text = sr.ReadToEnd();
}
return text;
}
And here is a link to the Object: http://pastebin.com/WQ8XXGNA
And a link to the jsonText: http://pastebin.com/7Kh6cA9a
The error returned says this:
An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in mscorlib.dll but was not handled in user code
Additional information: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'JuicyReddit.Comments+RootObject' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
I'd appreciate if anybody could help me with figuring out whats wrong with this.
Thanks
There are a few problems with your code actually
public async Task<List<string>> GetComments(string currentSubreddit, string topicID)
You don't need to return a list of string here, u need to return a full object
First rename RootObject in the model to an appropriate name such as "CommentsObject"
So set up your class like so and name it CommentsObject.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YOURNAMESPACE.Comments
{
public class MediaEmbed
{
}
public class SecureMediaEmbed
{
}
public class Data4
{
public int count { get; set; }
public string parent_id { get; set; }
public List<string> children { get; set; }
public string name { get; set; }
public string id { get; set; }
public string subreddit_id { get; set; }
public object banned_by { get; set; }
public string subreddit { get; set; }
public object likes { get; set; }
public object replies { get; set; }
public bool? saved { get; set; }
public int? gilded { get; set; }
public string author { get; set; }
public object approved_by { get; set; }
public string body { get; set; }
public object edited { get; set; }
public object author_flair_css_class { get; set; }
public int? downs { get; set; }
public string body_html { get; set; }
public string link_id { get; set; }
public bool? score_hidden { get; set; }
public double? created { get; set; }
public object author_flair_text { get; set; }
public double? created_utc { get; set; }
public object distinguished { get; set; }
public object num_reports { get; set; }
public int? ups { get; set; }
}
public class Child2
{
public string kind { get; set; }
public Data4 data { get; set; }
}
public class Data3
{
public string modhash { get; set; }
public List<Child2> children { get; set; }
public object after { get; set; }
public object before { get; set; }
}
public class Replies
{
public string kind { get; set; }
public Data3 data { get; set; }
}
public class Data2
{
public string domain { get; set; }
public object banned_by { get; set; }
public MediaEmbed media_embed { get; set; }
public string subreddit { get; set; }
public object selftext_html { get; set; }
public string selftext { get; set; }
public object likes { get; set; }
public object secure_media { get; set; }
public object link_flair_text { get; set; }
public string id { get; set; }
public SecureMediaEmbed secure_media_embed { get; set; }
public bool clicked { get; set; }
public bool stickied { get; set; }
public string author { get; set; }
public object media { get; set; }
public int score { get; set; }
public object approved_by { get; set; }
public bool over_18 { get; set; }
public bool hidden { get; set; }
public string thumbnail { get; set; }
public string subreddit_id { get; set; }
public object edited { get; set; }
public object link_flair_css_class { get; set; }
public object author_flair_css_class { get; set; }
public int downs { get; set; }
public bool saved { get; set; }
public bool is_self { get; set; }
public string permalink { get; set; }
public string name { get; set; }
public double created { get; set; }
public string url { get; set; }
public object author_flair_text { get; set; }
public string title { get; set; }
public double created_utc { get; set; }
public int ups { get; set; }
public int num_comments { get; set; }
public bool visited { get; set; }
public object num_reports { get; set; }
public object distinguished { get; set; }
public Replies replies { get; set; }
public int? gilded { get; set; }
public string parent_id { get; set; }
public string body { get; set; }
public string body_html { get; set; }
public string link_id { get; set; }
public bool? score_hidden { get; set; }
public int? count { get; set; }
public List<string> children { get; set; }
}
public class Child
{
public string kind { get; set; }
public Data2 data { get; set; }
}
public class Data
{
public string modhash { get; set; }
public List<Child> children { get; set; }
public object after { get; set; }
public object before { get; set; }
}
public class CommentsObject
{
public string kind { get; set; }
public Data data { get; set; }
}
}
Make your namespace correct!
Then handle the request and deserialise into a list of commentobjects: (u can use the webclient instead of httpclient if you want, this is just an example)
private HttpClient client;
public async Task<List<CommentsObject>> GetComments()
{
client = new HttpClient();
var response = await client.GetAsync("http://www.reddit.com/r/AskReddit/comments/1ut6xc.json");
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
List<CommentsObject> comments = await JsonConvert.DeserializeObjectAsync<List<CommentsObject>>(json);
return comments;
}
else
{
throw new Exception("Errorhandling message");
}
}
It's not ideal (and not completely an answer but more of a work around) but I created models that mock the reddit response json to make deserialization super easy. I use JsonProperty attributes on my model properties to pretty up the models a bit.
Here are the models
And since my models directly mock the json I can just use json.net's generic deserialize method.

JSONConvert.DeserializeObject not handling child array with unnamed array items

I have the following JSON object coming to me from a web service
{
"room":{
"name":"Thunderdome",
"created_at":"2012/04/15 00:36:27 +0000",
"id":xxxxxxx,
"users":[
{
"type":"Member",
"avatar_url":"url",
"created_at":"2012/02/27 14:11:57 +0000",
"id":1139474,
"email_address":"xxx#xxxxxxx.com",
"admin":false,
"name":"xxxx xxxxx"
},
{
"type":"Member",
etc
I'm using the following line to deserialize:
var room = JsonConvert.DeserializeObject<SingleRoom>(text);
And the following mapping classes
public class SingleRoom
{
public Room Room { get; set; }
}
[DataContract]
public class Room
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
public string Image {
get { return "Assets/campfire.png"; }
}
[DataMember]
public string Topic { get; set; }
[DataMember(Name ="membership_limit")]
public int MembershipLimit { get; set; }
[DataMember]
public bool Full { get; set; }
[DataMember]
public bool Locked { get; set; }
[DataMember(Name = "open_to_guests")]
public bool OpenToGuests { get; set; }
[DataMember(Name = "updated_at")]
public DateTime UpdatedAt { get; set; }
[DataMember(Name = "created_at")]
public DateTime CreatedAt { get; set; }
[DataMember(Name = "active_token_value")]
public string ActiveTokenValue { get; set; }
[DataMember(Name = "Users")]
public List<User> Users { get; set; }
}
[DataContract]
public class User
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember(Name = "email_address")]
public string EmailAddress { get; set; }
[DataMember]
public bool Admin { get; set; }
[DataMember]
public DateTime CreatedAt { get; set; }
[DataMember]
public string Type { get; set; }
[DataMember(Name = "avatar_url")]
public string AvatarUrl { get; set; }
}
The 'Room' object deserializes correctly but the Users property on the Room is always null. I know that a null result is the result of a JSON.NET serialization that couldn't find the matching property. However, I think I have it right? List should match to user. I know the array object users in the JSON doesn't have named children, is that the issue? If so, how do I solve it?
Thanks!
This works.... You can rename them (or use JsonProperty attribute) to use c# style property names
(BTW: Json.Net doesn't require DataMember, DataContract attributes)
var obj = JsonConvert.DeserializeObject<SingleRoom>(json)
public class User
{
public string type { get; set; }
public string avatar_url { get; set; }
public string email_address { get; set; }
public bool admin { get; set; }
public string name { get; set; }
public string created_at { get; set; }
public int id { get; set; }
}
public class Room
{
public string topic { get; set; }
public int membership_limit { get; set; }
public bool locked { get; set; }
public string name { get; set; }
public List<User> users { get; set; }
public bool full { get; set; }
public bool open_to_guests { get; set; }
public string updated_at { get; set; }
public string created_at { get; set; }
public int id { get; set; }
}
public class SingleRoom
{
public Room room { get; set; }
}
PS: You may find that site useful http://json2csharp.com/ .
In my case, I had missing to add the "public" key for the child property.

Error when attempting to deserialze JSON using DataContractJsonSerializer

This one really has me stumped. I'm trying to deserialize the following JSON string which I get from a ASP.NET Web Service:
"{\"d\":{\"__type\":\"KPCServer.LogonResult\",\"User\":{\"UserId\":\"affaa328-5b53-430e-991a-22674ede6faf\",\"Email\":\"test#test.com\",\"Alias\":\"Mike\",\"FullName\":\"Mike Christensen\",\"Password\":\"secret\",\"Location\":\"Redmond, WA\",\"ImageUrl\":null,\"DateOfBirth\":\"\\/Date(-62135568000000)\\/\",\"LastLogon\":\"\\/Date(1350450228000)\\/\",\"UserSince\":\"\\/Date(1197980020000)\\/\",\"MailingList\":true,\"Bio\":\"Test\"},\"NewUser\":false,\"Ticket\":\"FJEjfje87fjef88fe8FAF8fA88fAjk+AFJ9fja9Fa9Ff99aJF9aFjfA99fjaBFJ7zqmlcHn9Dfw=\"}}"
I have the following types:
public class User
{
public Guid UserId { get; set; }
public string Email { get; set; }
public string Alias { get; set; }
public string FullName { get; set; }
public string Password { get; set; }
public string Location { get; set; }
public string ImageUrl { get; set; }
public DateTime DateOfBirth { get; set; }
public DateTime LastLogon { get; set; }
public DateTime UserSince { get; set; }
public bool MailingList { get; set; }
public string Bio { get; set; }
}
[DataContract(Name="KPCServer.LogonResult")]
public class LogonResult
{
[DataMember] public User User { get; set; }
[DataMember] public bool NewUser { get; set; }
[DataMember] public string Ticket { get; set; }
}
[DataContract]
[KnownType(typeof(LogonResult))]
public class Result<T>
{
[DataMember]
public T d { get; set; }
}
I then try to deserialize the string using:
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Result<T>));
Result<T> result = serializer.ReadObject(stream) as Result<T>;
return result.d;
}
Note: In the above method, T is of type LogonResult.
However, I get the following exception on ReadObject:
System.Runtime.Serialization.SerializationException was unhandled by user code
HResult=-2146233076
Message=JSON contains a '__type' member specifying the data contract name ':KPCServer.LogonResult'. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to 'KPCServer.LogonResult' 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. You can also often eliminate this error by avoiding the use of derived types where the JSON is produced.
Source=System.ServiceModel.Web
InnerException:
If I run:
json = json.Replace("_type", "_blah");
Then everything works fine. This is using Silverlight on Windows Phone 8.
This is due to the fact that:
"\"__type\":\"KPCServer.LogonResult\""
doesn't contain a data contract namespace. This is fixed by modifying the DataContractAttribute on LogonResult:
[DataContract(Name = "KPCServer.LogonResult", Namespace="")]
public class LogonResult
{
[DataMember]
public User User { get; set; }
[DataMember]
public bool NewUser { get; set; }
[DataMember]
public string Ticket { get; set; }
}

Categories