I am working on a c#.dotNet project which invokes a 3rd party REST service.
Sample Class Structure :
[Serializable]
[DataContract(Name = "MainClass")]
[KnownType(typeof(Class1))]
[KnownType(typeof(Class2))]
public class MainClass : IMainInterface
{
public MainClass()
{
Value2 = new List<IClass2>();
}
[DataMember(Name = "class")]
public IClass1 Value1 { get; set; }
[DataMember(Name = "classes")]
public List<IClass2> Value2 { get; set; }
}
[Serializable]
[Export(typeof(IClass1))]
[ExportMetadata("IClass1", "Class1")]
[DataContract(Name = "class1")]
public class Class1 : IClass1
{
[ImportingConstructor]
public Class1()
{
}
[DataMember(Name = "prop1")]
public string Prop1 { get; set; }
[DataMember(Name = "prop2")]
public string Prop2 { get; set; }
[DataMember(Name = "prop3")]
public string Prop3 { get; set; }
}
[Serializable]
[Export(typeof(IClass2))]
[ExportMetadata("IClass2", "Class2")]
[DataContract]
public class Class2 : IClass2
{
[ImportingConstructor]
public Class2()
{ }
[DataMember(Name = "propA")]
public string PropA { get; set; }
[DataMember(Name = "propB")]
public string PropB { get; set; }
[DataMember(Name = "propC")]
public string PropC { get; set; }
}
public interface IMainInterface
{
IClass1 Value1 { get; set; }
List<IClass2> Value2 { get; set; }
}
public interface IClass1
{
string Prop1 { get; set; }
string Prop2 { get; set; }
string Prop3 { get; set; }
}
public interface IClass2
{
string PropA { get; set; }
string PropB { get; set; }
string PropC { get; set; }
}
Json_String1: (with type hint)
{
"class":
{"__type":"class1:#WpfApplication1","prop1":"TestVal0","prop2":"TestVal2","prop3":"TestVal3"},
"classes":
[
{"__type":"Class2:#WpfApplication1","propA":"A","propB":"B","propC":"C"},
{"__type":"Class2:#WpfApplication1","propA":"X","propB":"Y","propC":"Z"},
{"__type":"Class2:#WpfApplication1","propA":"1","propB":"2","propC":"3"}
]
}
Json_String2: (without type hint)
{
"class":
{"prop1":"TestVal0","prop2":"TestVal2","prop3":"TestVal3"},
"classes":
[
{"propA":"A","propB":"B","propC":"C"},
{"propA":"X","propB":"Y","propC":"Z"},
{"propA":"1","propB":"2","propC":"3"}
]
}
So, for given class structure if I generate json (of object of MainClass
) using DataContractJsonSerializer
, I am getting Json_String1 and if i directly deserialize, it works fine.
Whereas as while GETting data, response is Json_String2 ( w/o type hint). Hence, while deserializing I get following error.
InvalidCastException was unhandled. Unable to cast object of type 'System.Object' to type 'WpfApplication1.IClass2'.
Now, I manually have to modify above json (string manipulation) by adding type hint, to deserialize it successfully.
Question 1) how can I avoid this Json String Manipulation for deserializing ?
Question 2) how can I create json without type hint ?
edit : 1. Added IMainInterface which is implemented by MainClass. 2. dotNet Framework 4
Since none of your classes are actually polymorphic, there are a couple solutions available that use .Net built-in class libraries:
Solution 1:
JavaScriptSerializer
SolutionJavaScriptSerializer
makes it easy to remap interfaces to classes during deserialization by using aJavaScriptConverter
. However, it does not allow field and property names to be remapped, thus your property names must match the names in the JSON you wish to process. The following converter does the trick:And use it like:
Solution 2:
DataContractJsonSerializer
SolutionWCF and its
DataContractSerializer
s work only with concrete types and do not serialize interfaces. Thus, if you wish to use these serializers you must use concrete classes internally and present them to the outside world as interfaces, for instance:Note that if a caller attempts to set an
IClass1
orIClass2
which is not an actualClass1
orClass2
, anInvalidCastException
will be thrown. Thus this gives the appearance of hiding interface implementations without truly keeping the implementations private.The issue is because you're trying to deserialize to a class that only has interfaces. It obviously works when the JSON specifies the __type. But when it doesn't (like in your second JSON example), ReadObject isn't able to automatically resolve the interfaces to their implementation.
Try using the concrete classes
Class1
,Class2
inMainClass
instead of their interfaces (IClass1, IClass2). The rest of the code can remain as-is. Both your Json examples should work fine with this.