I'm having trouble deserializing a JSON string in C# to an object whose property names slightly differ from those in the JSON string. Here is my code:
using System.Collections.Generic;
using Newtonsoft.Json;
[JsonObject(MemberSerialization.OptIn)]
public class AuctionFilesList
{
[JsonProperty("files")]
public List<AuctionFile> Files { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public class AuctionFile
{
#region Properties
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("lastModified")]
public long LastModified { get; set; }
#endregion
}
string jsonResponse = "{\"files\":[{\"url\":\"http://auction-
api.com/auctions.json\",\"lastModified\":1495397839000}]}"
AuctionFilesList auctionFiles = JsonConvert.DeserializeObject<AuctionFilesList>(jsonResponse);
I get no errors, it just fails to deserialize into the object. I have tried adding serializer settings as follows but it still fails:
JsonSerializerSettings jss = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
AuctionFilesList auctionFiles = JsonConvert.DeserializeObject<AuctionFilesList>(jsonResponse, jss);
My class structures agree with what json2csharp returns and it works when I match the property names of the object to the JSON, so either I am misunderstanding what JsonProperty does or it is being ignored somehow.
Any help is appreciated.
Related
Is it possible to convert json produced by JSON.NET with type name handling set on into regular json?
My application cannot assume anything about the types it is receiving as it will be 1 of many 1000s of classes. I just need to remove the type information from the json.
For example I receive this json string in my application:
{
"$type": "MyAssembly.MyType, MyAssembly",
"$id": 1,
"MyValue": 5
}
Can I convert it into this json:
{
"MyValue": 5
}
I've tried loading the original json into JObject and then removing all members starting with $ but then found this fails when working with arrays, as they can look like this:
{
"MyArray": {
"$type": "System.Collections.List, System",
"$values": [
{
"$type": "MyAssembly.MyType, MyAssembly",
"MyValue": 5
}
]
}
}
Is there anything built into JSON.NET that allows such a conversion to take place?
Here is an example to show what I mean
class Program
{
static void Main(string[] args)
{
JsonSerializerSettings withNamehandling = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
PreserveReferencesHandling = PreserveReferencesHandling.All,
Formatting = Formatting.Indented
};
var obj = new MyObj();
//This is the json which my application will be receiving. My application does not know about MyObj or MyType.
var json = JsonConvert.SerializeObject(obj, withNamehandling);
Console.WriteLine(json);
//Deserialize the object without namehandling enabled
var deserializeObject = JsonConvert.DeserializeObject(json);
//Serialize again without namehandling enabled
var json2 = JsonConvert.SerializeObject(deserializeObject, Formatting.Indented);
//Metadata removed from root node but not children.
Console.WriteLine(json2);
Console.ReadLine();
}
}
class MyObj
{
public List<MyType> Types { get; set; } = new List<MyType>()
{
new MyType()
{
Value = 5
}
};
}
class MyType
{
public int Value { get; set; }
}
If I use http://json2csharp.com/, below structure I get
public class RootObject
{
public string __invalid_name__$type { get; set; }
public int __invalid_name__$id { get; set; }
public int MyValue { get; set; }
}
With that what if you create your model as
public class MyType
{
public int MyValue { get; set; }
}
And then deserialize it to that type MyType
You can as well use JsonProperty annotation and make the specific property not required like
public class RootObject
{
[JsonProperty(Required = Required.Default)]
public string __invalid_name__$type { get; set; }
[JsonProperty(Required = Required.Default)]
public int __invalid_name__$id { get; set; }
public int MyValue { get; set; }
}
Yes, you can deserialize the data and then reserialize it. By default JSON .NET will not include the type names, so that must be set by the serialization side with a purpose, to use the same assembly to serialize/deserialize the data, so be careful when manipulating that data without the real source assembly.
Anyway, to deserialize the data first create a model which fits with the real data:
public class RootObject
{
public List<MyObject> MyArray { get; set; }
}
public class MyObject
{
public MyType MyValue { get; set; }
}
//I assume this because there's not info about "MyType"
public class MyType : String { }
Now you create a JsonSerializerSettings and set the TypeNameHandling to None:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None };
And deserialize the data to your struct:
var deser = JsonConvert.DeserializeObject<RootObject>(seria, settings);
Now you have the data reconstructed and you can reserialize it with no type handling and it will remove all the namespaces and class types:
var cleanJson = JsonConvert.SerializeObject(deser, settings);
EDIT:
IF you don't need to reconstruct the structure just use the settings as posted and de/serialize to JObject:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None };
var deser = JsonConvert.DeserializeObject(SourceData, settings);
var clean = JsonConvert.SerializeObject(deser, settings);
Utilizing C# Newtownsoft JSON libraries... I have run into this issue.
To set the stage...
I have this JSON from a RESTful Web Service:
[
{
"CorporateArea": "Brampton",
"ServiceAddress": "321 Heart Lake Road",
"VendorName": "Enbridge Gas Distribution Inc",
"MeterNumber": "502105",
"RateClass": "NG-R6",
"Department": "22603",
"Account": "12008",
"VendorID": "0000001195",
"MeterLevelID": 2882,
"SiteAddressID": 468,
"MappingLocation": "Beckett Sproule",
"ElectricalBilling": "",
"EnergyLine": "",
"CorporateGroup": "Public Works"
}
]
I also have these C# classes:
public class AccountInfo
{
[JsonProperty("Account")]
public string Account { get; set; }
[JsonProperty("CorporateArea")]
public string CorporateArea { get; set; }
[JsonProperty("CorporateGroup")]
public string CorporateGroup { get; set; }
[JsonProperty("Department")]
public string Department { get; set; }
[JsonProperty("ElectricalBilling")]
public string ElectricalBilling { get; set; }
[JsonProperty("EnergyLine")]
public string EnergyLine { get; set; }
[JsonProperty("MappingLocation")]
public string MappingLocation { get; set; }
[JsonProperty("MeterLevelID")]
public string MeterLevelID { get; set; }
[JsonProperty("MeterNumber")]
public string MeterNumber { get; set; }
[JsonProperty("RateClass")]
public string RateClass { get; set; }
[JsonProperty("ServiceAddress")]
public string ServiceAddress { get; set; }
[JsonProperty("SiteAddressID")]
public string SiteAddressID { get; set; }
[JsonProperty("VendorID")]
public string VendorID { get; set; }
[JsonProperty("VendorName")]
public string VendorName { get; set; }
}
public class JSONArray {
public IList<AccountInfo> AccountsInfo { get; set; }
}
From these, I call this Newtownsoft Method:
JSONArray Accounts = JsonConvert.DeserializeObject<JSONArray> (responseBody,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
But everytime I do so, I get the exception Newtonsoft.Json.JsonSerializationException
with the error message:
Error converting value "[{"CorporateArea":"Brampton","ServiceAddress":"321 Heart Lake Road","VendorName":"Enbridge Gas Distribution Inc","MeterNumber":"502105","RateClass":"NG-R6","Department":"22603","Account":"12008","VendorID":"0000001195","MeterLevelID":2882,"SiteAddressID":468,"MappingLocation":"Beckett Sproule","ElectricalBilling":"","EnergyLine":"","CorporateGroup":"Public Works"}]" to type 'TestWebService_Consume.JSONArray'. Path '', line 1, position 421.
I've tried messing with the JSON string so it's not an array, and casting it into a simple AccountsInfo object, it returns the same error.
I must be doing something wrong, but it's been some time since I've worked with the Newtonsoft JSON libraries, so I'm at a loss of what could possible be the issue here.
The Deserialization output for the JSON is when trying with
JSONArray Accounts = JsonConvert.DeserializeObject<JSONArray>(json, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
is
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'JustSO.JSONArray' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
But if you try like this
List<AccountInfo> lc = JsonConvert.DeserializeObject<List<AccountInfo>>(json, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
or
List<AccountInfo> lc = JsonConvert.DeserializeObject<List<AccountInfo>>(json);
will give you the resultant json into Object.
Your JSOn is not an object, but an array of objects, so you don't need a class to wrap the array, you should deserialize directly to array:
var Accounts = JsonConvert.DeserializeObject<List<AccountInfo>>(responseBody,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
If you really want to have JSONArray object, you could create it and serialize to it's property. Just to mention: your AccountInfo property is private, you should change it to public to deserialize to it.
JSONArray Accounts = new JSONArray
{
AccountsInfo = JsonConvert.DeserializeObject<List<AccountInfo>>(responseBody,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
})
};
I use Newtonsoft.Json in generic read and write methods for Excel spreadsheets. Had this exception start throwing, and turned out to be a change made to the excel spreadsheet. In general column types, the first cell is used to set the data table type, generally with a header column this ends up being a string. The excel I was trying to load had a new row added at the top for zero indexing, so all columns were being set as system.double.
Just thought I'd throw that here, since it took a while to track down why this error started happening after years of working perfectly.
Im trying simply to deserialize a JSON payload using the JavaScriptSerializer class and running into an issue of the class property im setting this supposed deserialized data too being 'null'.
JSON:
{
"XmlPayload": "<PaperLessTimeSheetActivation xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://host.adp.com\"><iSIClientID>99783971</iSIClientID><organizationId>FDGFGD</organizationId><statusDescription>Success</statusDescription></PaperLessTimeSheetActivation>"
}
Here my code:
var jsObject = new JavaScriptSerializer();
string holdData = xmlPayload.ToString();
//*****issue: JSON XmlPayLoadConvert property is 'null'.
JSONConverted objectToConvert = jsObject.Deserialize<JSONConverted>(holdData);
string stringXDoc = ConvertToXDoc(objectToConvert.XmlPayloadToConvert);
Here the class the deserialized data should map too:
public class JSONConverted
{
public string XmlPayloadToConvert
{
get;
set;
}
}
Can anyone tell me where I'm going wrong?
With the edit the error becomes obvious: XmlPayload is not the same as XmlPayloadToConvert.
Change your type to:
public class JSONConverted
{
public string XmlPayload {get;set;}
}
and it'll work fine. With some serializers (Json.NET, for example) you can also tell it how to map the names:
[DataContract]
public class JSONConverted
{
[DataMember(Name = "XmlPayload") ]
public string XmlPayloadToConvert {get;set;}
}
I am getting this error when using my class.
Error
Expecting element 'root' from namespace ''.. Encountered 'None' with
name '', namespace
My Class
[DataContract]
public class EntryData
{
[DataMember]
public string EntryId { get; set; }
[DataMember]
public string EmailAddress { get; set; }
[DataMember]
public string StatusCode { get; set; }
[DataMember]
public string TotalVoteCount { get; set; }
public static T Deserialise<T>(string json)
{
var obj = Activator.CreateInstance<T>();
using (var memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
memoryStream.Position = 0;
var serializer = new DataContractJsonSerializer(obj.GetType());
obj = (T)serializer.ReadObject(memoryStream); // getting exception here
return obj;
}
}
}
USAGE
string responseJson = new StreamReader(HttpContext.Current.Request.InputStream).ReadToEnd();
var results = EntryData.Deserialise<EntryData>(response)
I have seen online that it has to do with the memoryStream position BUT as you can see i am setting it to the beginning.
Please help.
Json going to handler
I don't set StatusCode or TotalVoteCount when passing JSON in. I don't think this is the problem though.
{
"EntryId":"43",
"EmailAddress":"test#email.com"
}
ANSWER
Instead of using Deserialize method in my class I am using now this.
//commented out this code.
string responseJson = new StreamReader(HttpContext.Current.Request.InputStream).ReadToEnd();
var results = EntryData.Deserialise<EntryData>(response)
// this is the way to go using JavaScriptSerializer
var serializer = new JavaScriptSerializer();
var results = serializer.Deserialize<EntryData>(response);
Could it be caused by your JSON names not matching your property names in C#?
My understanding is that
{
"FirstName" : "Mark"
}
Would be able to deserialize into:
[DataContract]
public class Person
{
[DataMember]
public string FirstName {get; set;}
}
but this wouldn't be able to serialize
{
"Name" : "Mark"
}
unless you changed your C# class to have an explicit name for the DataMember
[DataContract]
public class Person
{
[DataMember(Name="Name")]
public string FirstName {get; set;}
}
I'm not sure which error this would cause though. I Don't have enough first hand experience.
Do you think it could be an encoding problem? Have you tried using Encoding.UTF8 instead of Unicode?
All the examples I have seen using DataContractSerializer have used a UTF-8 encoding.
Encoding.Unicode is a UTF-16 encoding.
I can't find any documentation explicitly stating which encodings DataContractSerializer supports. I assume it would be smart enough to detect the proper encoding, but I don't know a whole whole lot about encodings. Maybe that isn't really possible in this instance.
Does the Json.Encode() Helper use the JavaScriptSerializer class to encode a string to json?
I am getting a circular reference exception when using Json.Encode(Model) even though my class properties that are being serialized have the [ScriptIgnore] attribute.
My only guess is that maybe the Json.Encode() helper doesn't use the JavaScriptSerializer to serialize to json but I can't find the documentation anywhere on msdn.
#Html.Raw(Json.Encode(Model))
Here's an example of one of the models that has a property that should not be serialized...
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Web.Script.Serialization;
namespace RobotDog.Entities {
public class Character {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[MaxLength(200)]
public string Name { get; set; }
public virtual Person Person { get; set; }
[ScriptIgnore]
public virtual Movie Movie { get; set; }
}
}
Does the Json.Encode() Helper use the JavaScriptSerializer class to encode a string to json?
Yes.
From the source code:
private static readonly JavaScriptSerializer _serializer = Json.CreateSerializer();
public static string Encode(object value)
{
DynamicJsonArray dynamicJsonArray = value as DynamicJsonArray;
if (dynamicJsonArray != null)
return Json._serializer.Serialize((object) (object[]) dynamicJsonArray);
else
return Json._serializer.Serialize(value);
}
where JavaScriptSerializer is System.Web.Script.Serialization.JavaScriptSerializer
also to assist your issue see this thread
http://msdn.microsoft.com/en-us/library/system.web.helpers.json.encode(v=vs.111).aspx
according to the above link Json.Encode uses system.web.helpers.
What does your Model contain?
Also, are you sure that [ScriptIgnore] will ignore what you have it assigned to?