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);
Related
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.
i want to pass following json as an reference in my console application in c#
{"val1":["dfgdsfgdfgsdf"],"val2":258915,"val3":"PPaaaA","val4":null,
"valJSON":"[{\"TypeID\":\"Z_FI_MDG\",\"SeverityCode\":\"3\",\"Note\":\"\\\"zczczca \\\\\\\"leading zero\\\\\\\". \\\\\\\\r\\\\\\\\n•YYY: Institution\"}]"}
I am doing following , but it is not working
JsonSerializer serializer = new JsonSerializer();
dynamic item = serializer.Deserialize<object>("
{"val1":["dfgdsfgdfgsdf"],"val2":258915,"val3":"PPaaaA","val4":null,
"valJSON":"[{\"TypeID\":\"Z_FI_MDG\",\"SeverityCode\":\"3\",\"Note\":\"\\\"zczczca \\\\\\\"leading zero\\\\\\\". \\\\\\\\r\\\\\\\\n•YYY: Institution\"}]"}
");
any other way i can pass this to function ?
to simplyfy
when i try to assign this to string it gives error can anyon hlp me
You should remove object type from function call:
JsonSerializer serializer = new JsonSerializer();
dynamic item = serializer.Deserialize("...");
I would use Newtonsoft's solution, if it's possible, i never regreted.
In your case, i'd use:
string json = #"{
"val1": [
"dfgdsfgdfgsdf"
],
"val2": 258915,
"val3": "PPaaaA",
"val4": null,
"valJSON": "[{\"TypeID\":\"Z_FI_MDG\",\"SeverityCode\":\"3\",\"Note\":\"\\\"zczczca \\\\\\\"leading zero\\\\\\\". \\\\\\\\r\\\\\\\\n•YYY: Institution\"}]"
}"
dynamic rss = JObject.Parse(json);
And then accessing values from it like:
var val2 = rss.val2;
I'm not sure if that's what you was looking for, but i tried...
Read more: http://www.newtonsoft.com/json/help/html/QueryJson.htm
Then, if you want more how to "install" newtonsoft: How to install JSON.NET using NuGet?
If you want to parse Json to the exact class you can try this
RootObject item = JsonConvert.DeserializeObject<RootObject>(File.ReadAllText(#"D:\file.txt"));
public class RootObject
{
public List<string> val1 { get; set; }
public int val2 { get; set; }
public string val3 { get; set; }
public object val4 { get; set; }
public string valJSON { get; set; }
}
I've managed to find a solution without removing the paths from the keys.Thanks for the help guys, and also pointing out problems, I really appreciate it! :)
Loaded the Json to a string, deserialized it into a dynamic, ran a foreach through it, and added to a List with ResFiles in it.
static void loadJson()
{
List<ResFile> fileList = new List<ResFile>();
string jsonString = File.ReadAllText(jsonPath);
dynamic files = JsonConvert.DeserializeObject(jsonString);
foreach (var f in files.objects)
fileList.Add(new ResFile(f.Name, f.Value.hash.ToString(), (int)f.Value.size.Value));
}
I'm trying to deserialize some Json file in C# with Newtonsoft's Json library.
The files are named after it's hash, not the real file name and I want to rename them back to the proper names, so like this:
10a54fc66c8f479bb65c8d39c3b62265ac82e742 >> file_1.ext
The Json file:
{
"files": {
"file_1.ext": {
"hash": "10a54fc66c8f479bb65c8d39c3b62265ac82e742",
"size": 8112
},
"file_2.ext": {
"hash": "14cfb2f24e7d91dbc22a2a0e3b880d9829320243",
"size": 7347
},
"file_3.ext": {
"hash": "bf7fadaf64945f6b31c803d086ac6a652aabef9b",
"size": 3838
},
"file_4.ext": {
"hash": "48f7e1bb098abd36b9760cca27b9d4391a23de26",
"size": 6905
}
}
}
I've tried deserialize with this:
static void loadJson()
{
using (StreamReader reader = new StreamReader(jsonPath))
{
string json = reader.ReadToEnd();
dynamic files = JsonConvert.DeserializeObject(json);
}
}
The deserialization itself working, but I don't know how to loop through them.
I've also tried to do this:
class ResFile
{
public string name;
public string hash;
public int size;
}
And somehow force the deserialization to use this, but it didn't work of course.
According to your sample json, your classes would be:
public class ResFile
{
public string hash { set; get; }
public int size { set; get; }
}
public class ResRoot
{
public Dictionary<string, ResFile> Files { set; get; }
}
You can deserialize as
var res = JsonConvert.DeserializeObject<ResRoot>(File.ReadAllText(filename));
foreach(var f in res.Files)
{
Console.WriteLine("Name={0} Size={1}", f.Key, f.Value.size);
}
Please follow the C# conventions and do not expose member variables as public or start property names with lower case. In order to make your conventional objects deserializable, you could use the System.Runtime.Serialization DataContract and DataMember attributes. DataContract indicates that an object of this type is serializable and DataMember is used to specify a property's serialization name.
class ResFile
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "hash")]
public string Hash { get; set; }
[DataMember(Name = "size")]
public int Size { get; set; }
public ResFile () { }
}
[DataContract]
class ResFileCollection
{
[DataMember(Name ="files")]
public Dictionary<string, ResFile> Files { get; set; }
}
And here is the deserialization:
string json = File.ReadAllText("data.json");
var files = JsonConvert.DeserializeObject<ResFileCollection>(json);
foreach(KeyValuePair<string, ResFile> f in files.Files)
{
Console.WriteLine("{0} {1} {2}", f.Key, f.Value.Name, f.Value.Hash);
}
Serialized property names should also be shorter for better performance. An example:
[DataMember(Name="src")]
public string SourcePath { get; set; }
Below is a section of json I receive from an endpoint.
If you look at the Json below, 'User-Defined-Network-Name' is a custom node and the name will change each time.
How do I define a C# object for this Json?
"addresses": {
"public": [{
"version": 6,
"address": "2005:4600:788e:0910:1a72:81c0:ff03:c7y6"
},
{
"version": 4,
"address": "197.68.xx.xxx"
}],
"private": [{
"version": 4,
"address": "10.xx.xx.xxx"
}],
"User-Defined-Network-Name": [{
"version": 4,
"address": "192.xxx.x.xxx"
}]
}
This is how far I have come -
[Serializable]
public class Addresses
{
public List<Public> #public { get; set; }
public List<Private> #private { get; set; }
}
Im using 'JavascriptSerializer' class to deserialize json.
Thanks,
Ryan
addresses can be deserialized to a type like Dictionary<string,List<YourClass>> where YourClass holds version and addresss.
var obj = new JavaScriptSerializer().Deserialize<Root>(jsonstring);
--
public class Root
{
public Dictionary<string,List<VersionAddress>> addresses;
//Your other fields/properties
}
public class VersionAddress
{
public string version;
public string address;
}
You could take advantage of the dynamic nature of C#:
// this could come from user input:
string userDefinedName = "User-Defined-Network-Name";
string json = "YOUR JSON COMES HERE";
var serializer = new JavaScriptSerializer();
dynamic result = serializer.DeserializeObject(json);
int version = result["addresses"][userDefinedName][0]["version"];
string address = result["addresses"][userDefinedName][0]["address"];
Console.WriteLine(version);
Console.WriteLine(address);
and if you wanted to loop through the results:
foreach (dynamic item in result["addresses"][userDefinedName])
{
int version = item["version"];
string address = item["address"];
Console.WriteLine(version);
Console.WriteLine(address);
}
Why don't you make network names a dictionary, with key of network name ?
Then you can just iterate over it.
I would not recommend using JavaScriptSerializer, as it has been deprecated. If you want a third-party solution, JSON.Net is pretty good from what I hear.
However, I'm one that's weird about dependencies, so I typically roll my own if it doesn't exist already. Fortunately, this one isn't too hard due to DataContractJsonSerializer from the System.Runtime.Serialization namespace.
All you need to do is first define all the objects in a nested fashion:
using System.Reflection;
using System.Runtime.Serialization; // You will have to add a reference
using System.Runtime.Serialization.Json; // to System.Runtime.Serialization.dll
[DataContract]
public class AddressInfo
{
[DataMember(Name = "address")]
public string Address { get; set; }
[DataMember(Name = "version")]
public int Version { get; set; }
}
[DataContract]
public class AddressList
{
[DataMember(Name = "public")]
public IEnumerable<AddressInfo> Public { get; set; }
[DataMember(Name = "private")]
public IEnumerable<AddressInfo> Private { get; set; }
[DataMember(Name = "User-Defined-Network-Name")]
public IEnumerable<AddressInfo> UserDefined { get; set; }
}
Then a couple helper methods to do the deserialization:
// This will change the DataMember.Name at runtime!
// This will only work if you know the node name in advance.
static void SetUserDefinedNodeName(string userDefinedNodeName)
{
var type = typeof(AddressList);
var property = type.GetProperty("UserDefined", BindingFlags.Default);
var attribute = property.GetCustomAttribute<DataMemberAttribute>();
if (attribute != null)
attribute.Name = userDefinedNodeName;
}
static T Deserialize<T>(string jsonText, string userDefinedNodeName)
{
SetUserDefinedNodeName(userDefinedName);
var jsonBytes = Encoding.UTF8.GetBytes(jsonText);
using (var stream = new MemoryStream(jsonBytes))
{
var serializer = new DataContractJsonSerializer(typeof(T));
var obj = serializer.ReadObject(stream) as T;
return obj;
}
}
Then you use it like so:
var jsonText = // get your json text somehow
var addressList = Deserialize<AddressList>(jsonText);
I have wrote a basic web service using .net which I intend to use in a mobile app. It currently outputs Json however the structure it not quite what I need.
The models I've created
[DataContract]
class PoiList
{
[DataMember]
public List<Poi> Pois { get; set; }
}
[DataContract]
class Poi
{
[DataMember]
public string title { get; set; }
[DataMember]
public string latitude { get; set; }
[DataMember]
public string longitude { get; set; }
}
Then i added some test data:
PoiList poiList = new PoiList
{
Pois = new List<Poi>()
};
Poi p = new Poi
{
title = "whatever",
latitude = "-2.45554",
longitude = "52.5454645"
};
poiList.Pois.Add(p);
p = new Poi
{
title = "weeee",
latitude = "-2.45554",
longitude = "52.5454645"
};
poiList.Pois.Add(p);
string ans = JsonConvert.SerializeObject(poiList, Formatting.Indented);
This is what the returned string looks like:
{ "Pois": [ { "title": "shit", "latitude": "-2.45554", "longitude": "52.5454645" }, { "title": "weeee", "latitude": "-2.45554", "longitude": "52.5454645" } ] }
...and this is what I want the outputted Json to look like:
string TempString = #"{ ""pois"":
[{ ""poi"":
{
""title"": ""Test title"",
""latitude"": ""-2.4857856"",
""longitude"": ""54.585656""
}},
{ ""poi"":
{
""title"": ""Halfords"",
""latitude"": ""-2.575656"",
""longitude"": ""53.5867856""
}}]}";
Basically the only difference being the "poi" next to each object in the list. Is there a simple way to include this? I should add I am using the newtonsoft.json package.
I would suggest you go with the JSON that's being generated, as your target JSON contains unnecessary objects, IMO.
Your target JSON has an object with a single field "pois", which contains a list of objects, each with a single field "poi" that contains an object with the fields "title", "latitude", and "longitude".
To access a single title field, you would need to do the following:
poisObj.pois[0].poi.title
If you go with the JSON that's generated by your object structure, you would access a single title field like so:
poisObj.pois[0].title
That having been said, if you absolutely must target that JSON structure, you'll need another DataContract object, as follows:
[DataContract]
class PoiList
{
[DataMember]
public List<PoiPoi> Pois { get; set; }
}
[DataContract]
class PoiPoi
{
[DataMember]
public Poi poi { get; set; }
}
[DataContract]
class Poi
{
[DataMember]
public string title { get; set; }
[DataMember]
public string latitude { get; set; }
[DataMember]
public string longitude { get; set; }
}
No need to declare many tiny classes just to output a json string. You can create an anonymous object to serialize like below:
var obj = new { pois = new List<object>() };
obj.pois.Add(new { poi = new {title = "Test title", latitude = "-2.4857856", longitude = "54.585656" } });
obj.pois.Add(new { poi = new {title = "Halfords" , latitude = "-2.4857856", longitude = "53.5867856" } });
string json = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented);
Console.WriteLine(json);
Go with the default structure the only thing the "poi" gives you is what "type" the object is, which JSON doesn't really have a concept of. If you want to include type information, try :-
var jsonSerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
};
var json = JsonConvert.SerializeObject(o, Formatting.None, jsonSerializerSettings);
this will give you a field _type_ which is useful especially if you have a list of various types of objects. Json.Net then knows how to recreate the objects using this _type_ field.