I am using Newtonsoft JSON serializer, and the serialized string is missing the properties from the derived class if the class is derived from a list. Here is my example code.
Classes:
[DataContract]
public class TestItem
{
[DataMember]
public int itemInt;
[DataMember]
public string itemString;
public TestItem() {}
public TestItem(int _intVal, string _stringVal)
{
itemInt = _intVal;
itemString = _stringVal;
}
}
[DataContract]
public class TestMain : List<TestItem>
{
[DataMember]
public int mainInt;
[DataMember]
public string mainString;
}
Serializing code:
string test;
// Test classes
TestMain main = new TestMain();
main.mainInt = 123;
main.mainString = "Hello";
main.Add(new TestItem(1, "First"));
test = Newtonsoft.Json.JsonConvert.SerializeObject(main);
After serialization, the value of test is:
[{\"itemInt\":1,\"itemString\":\"First\"}]
The values for mainInt and mainString are missing altogether.
The behaviour is not changed by the [DataContract] and [DataMember] tags, but I have them in there, to pre-empt the answer that they are missing.
How do I get JSON to recognize and serialize the mainInt and mainString properties of the derived class?
Is this what you want?
[DataContract]
public class TestItem
{
[DataMember]
public int itemInt { get; set; }
[DataMember]
public string itemString { get; set; }
public TestItem() { }
public TestItem(int _intVal, string _stringVal)
{
itemInt = _intVal;
itemString = _stringVal;
}
}
[DataContract]
public class TestMain
{
[DataMember]
public int mainInt { get; set; }
[DataMember]
public string mainString { get; set; }
[DataMember]
public List<TestItem> TestItem = new List<TestItem>();
}
class Program
{
static void Main(string[] args)
{
string test;
// Test classes
TestMain main = new TestMain();
main.mainInt = 123;
main.mainString = "Hello";
main.TestItem.Add(new TestItem(1, "First"));
test = Newtonsoft.Json.JsonConvert.SerializeObject(main);
Console.WriteLine(test);
}
}
Take a look at putting json attribs on your properties. Here is a sample: Json.NET serialize object with root name. The only thing I would hesitate to do is having the main derive from list like that. Its not a recommended pattern and practice.
add list as another child property rather then deriving from list, json serialize is getting confused as to your intentions.
adding this attrib works for me:
using System.ComponentModel.DataAnnotations;
[Newtonsoft.Json.JsonObject(Title = "root")]
public class Testmain : List
Related
I’ve got a base class (which is used a base for a User class):
public abstract class UserB2C
{
…
public List<SignInName> SignInNames { get; set; }
…
}
public class SignInName
{
string Type { get; set; }
string Value { get; set; }
}
And some JSON which includes:
\"signInNames\":[{\"type\":\"emailAddress\",\"value\":\"user#yahoo.co.uk\"}],
which is passed to:
JsonConvert.DeserializeObject<User>(json);
But the object created (deserialised) has:
"signInNames": [
{}
],
Any ideas why the field doesn’t get populated?
There is no error generated.
All other (simple) values get populated ok.
I've tried changing the case of Type and Value to match the JSON string,
and also tried explicitly creating the List<SignInName> when the object is created, but to no avail.
Properties of SignInName class should be declared as public in order to be deserialized with values.
public class SignInName
{
public string Type { get; set; }
public string Value { get; set; }
}
UPDATE
Here is a Minimal, Complete, and Verifiable example:
using Newtonsoft.Json;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
var json =
"{\"signInNames\":[{\"type\":\"emailAddress\",\"value\":\"user#example.com\"}]}";
var user = JsonConvert.DeserializeObject<User>(json);
System.Console.WriteLine(JsonConvert.SerializeObject(user));
}
}
public abstract class UserB2C
{
public List<SignInName> SignInNames { get; set; }
}
public class User : UserB2C { }
public class SignInName
{
string Type { get; set; }
string Value { get; set; }
}
Output is {"SignInNames":[{}]}
If we make SignInName class properies public the output will be:
{"SignInNames":[{"Type":"emailAddress","Value":"user#example.com"}]}
Using .net XmlSerializer and the following structure:
public class SomeClass {
[XmlElement("some-string")]
public string SomeString { get; set; }
}
I need the above to produce :
<someclass>
<some-string alt-name="someotherstring">
StringValue
</some-string>
</someclass>
But i dont want to have to define types for somestring, some int, somebool, yetanotherstring etc every time i want to add a standard type as a porperty to my classes.
Any way I can override xlement to handle this maybe?
Produce wrappers for base types and conversion operators to alleviate object construction:
[Serializable()]
public partial class StringWrapper
{
[XmlAttribute("alt-name")]
public string altname { get; set; }
[XmlText()]
public string Value { get; set; }
public static implicit operator string (StringWrapper sw) { return sw.Value; }
public static implicit operator StringWrapper (string s) {
return new StringWrapper() { altname = "someotherstring", Value = s };
}
}
Use wrappers instead of base types where needed:
[Serializable()]
[XmlRoot(Namespace = "someclass", IsNullable = false)]
public class someclass
{
[XmlElement("some-string")]
public StringWrapper somestring { get; set; }
}
Use it like:
var srlz = new XmlSerializer(typeof(someclass));
srlz.Serialize(Console.Out, new someclass() { somestring = "StringValue" });
The only way to do that via XmlSerializer is:
[XmlRoot("someclass")]
public class SomeClass {
[XmlElement("some-string")]
public SomeOtherClass Foo {get;set;}
}
public class SomeOtherClass {
[XmlText]
public string Text {get;set;}
[XmlAttribute("alt-name")]
public string Bar {get;set;}
}
Alternatively: use XmlDocument / XDocument instead of XmlSerializer.
I am having a difficult time parsing a json response with C# asp.net. mostly with the array within array structure of this response. I have edited the post to reflect the json object. I think we can omit the deserialzation code.
{"Level1":
[
{
A:"some",
B:"more",
C:"stuff"
}
],"DataLevel":
[[
{ "AnotherLevel":
{
"File":"data"
},
"More":"stuff"
}
]]}
// C# code
public class JsonObject
{
public Level1[] level1 {get;set;}
public DataLevel[] datalevel {get;set;}
}
public class Level1
{
public string A {get;set;}
public string B {get;set;}
public string C {get;set;}
}
public class DataLevel
{
// ??
// Seems like this should be public AnotherLevel anotherlevel {get;set;}
public string More {get;set;}
}
Ok so looking at your data I would say your class definitions do not match the json you posted. Look closely at it. You have an object with 2 properties. One is an array of objects, the other is an array of object arrays. Below I have a different set of class definitions that should solve your problems.
public class OuterObject
{
public FirstArrayObject[];
public List<ObjInNestedArray[]>;
}
public class FirstArrayObject
{
public string A;
public string B;
public string C;
}
public class ObjInNestedArray
{
string property1;
AnotherLevel AnotherLevel;
}
public class AnotherLevelObj
{
string prop1;
}
OuterObject response = JsonConvert.DeserializeObject<OuterObject>(responseBodyAsString);
I don't know how good this is and didn't check if it is actually correct but you could try this website http://json2csharp.com/, but it might help you in some way!
This is the result I got when I used the json data you provided:
class Level1
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
public class RootObject
{
public List<Level1> Level1 { get; set; }
public List<List<>> DataLevel { get; set; }
}
I found something that confused me today:
1. If I have this:
public interface INamed
{
[XmlAttribute]
string Name { get; set; }
}
public class Named : INamed
{
public string Name { get; set; }
}
It gives the following output (Name property serialized as element):
<Named>
<Name>Johan</Name>
</Named>
2. If I have this:
public abstract class NamedBase
{
[XmlAttribute]
public abstract string Name { get; set; }
}
public class NamedDerived : NamedBase
{
public override string Name { get; set; }
}
The XmlSerializer throws System.InvalidOperationException
Member 'NamedDerived.Name' hides inherited member 'NamedBase.Name',
but has different custom attributes.
The code I used for serialization:
[TestFixture]
public class XmlAttributeTest
{
[Test]
public void SerializeTest()
{
var named = new NamedDerived {Name = "Johan"};
var xmlSerializer = new XmlSerializer(named.GetType());
var stringBuilder = new StringBuilder();
using (var stringWriter = new StringWriter(stringBuilder))
{
xmlSerializer.Serialize(stringWriter, named);
}
Console.WriteLine(stringBuilder.ToString());
}
}
My question is:
Am I doing it wrong and if so what is the correct way to use xml attributes in interfaces and abstract classes?
Attributes are not inherited on overriden properties. You need to redeclare them.
Also in your first example the behavior is not the "expected" one as you declared XmlAttribute at the interface level and yet the serialized xml contains the value as an element. So the attribute in the interface is ignored and only info taken from the actual class matters.
I think you should xmlignore your abstract class property
public abstract class NamedBase
{
[XmlIgnore]
public abstract string Name { get; set; }
}
public class NamedDerived : NamedBase
{
[XmlAttribute]
public override string Name { get; set; }
}
I have a json comprising list of MyFacebookClass and when i am deserializing the list of MyFacebookClass then i am getting the error that no blank constructor defined for CustomObject though i have already defined constructor as shown below,so please help me out.
public class MyFacebookClass
{
public MyFacebookClass
{
data =new List<CustomObject>();
}
public string Name{get;set;}
public int Id{get;set;}
public List<CustomObject> data {get;set;}
}
public class CustomObject
{
public CustomObject()
{
}
public string id {get;set;}
public string name {get;set;}
}
I am using:
List<MyFacebookClass> routes_list = new List<MyFacebookClass>();
JavaScriptSerializer jSerializer = new JavaScriptSerializer();
routes_list = jSerializer.Deserialize<List<MyFacebookClass>>(json);
you have no constructor for CustomObject in the code that you have posted. basically, a constructor is a method that has no return type and is the same name as the declaring class. You DO have a constructor for your MyFacebookClass here is the MSDN documentation on constructors.
public class CustomObject
{
public CustomObject()
{
/* now you have a constructor */
}
public string id {get;set;}
public string name {get;set;}
}
Working perfectly fine. Only issue I found in your code was, MyFacebookClass class constructor should have brackets
public class MyFacebookClass
{
public MyFacebookClass()
{
data = new List<CustomObject>();
}
public string Name { get; set; }
public int Id { get; set; }
public List<CustomObject> data { get; set; }
}
public class CustomObject
{
public CustomObject()
{
/* now you have a constructor */
}
public string id { get; set; }
public string name { get; set; }
}
public class Main
{
public List<MyFacebookClass> Deserialize(string json)
{
List<MyFacebookClass> routes_list = new List<MyFacebookClass>();
JavaScriptSerializer jSerializer = new JavaScriptSerializer();
return jSerializer.Deserialize<List<MyFacebookClass>>(json);
}
}
[TestMethod()]
public void doSomethingTest()
{
Main target = new Main(); // TODO: Initialize to an appropriate value
Assert.AreEqual(target.Deserialize(""), null);
}