XML Deserialization doesn't work with abstract class - c#

I'm trying to deserialize from a xml string to an object. But my obect is always null.
I have an abstract class (Response), a class that inherits from "Response" (DirectorSearchResponse), and an object in the class "DirectorSearchResponse" (HeaderResponse). This object is always null after deserialization.
Response.cs
public abstract class Response
{
public HeaderResponse Header { get; set; }
public Response()
{
}
}
DirectorSearchResponse.cs
[XmlRoot("xmlresponse")]
public class DirectorSearchResponse : Response
{
public DirectorSearchResponse() : base()
{
/* DO NOTHING */
}
}
HeaderResponse.cs
[XmlRoot("header")]
public class HeaderResponse
{
[XmlElement("toto")]
public String toto { get; set; }
public HeaderResponse()
{
}
}
My running code :
/* DESERIALIZE */
String toto = "<xmlresponse><header><toto>tutu</toto><reportinformation><time>08/04/2016 13:33:37</time><reporttype> Error</reporttype><country>FR</country><version>1.0</version><provider>www.creditsafe.fr</provider><chargereference></chargereference></reportinformation></header><body><errors><errordetail><code>110</code><desc></desc></errordetail></errors></body></xmlresponse>";
XmlSerializer xsOut = new XmlSerializer(typeof(DirectorSearchResponse));
using (TextReader srr = new StringReader(toto))
{
DirectorSearchResponse titi = (DirectorSearchResponse)xsOut.Deserialize(srr);
}
When I execute my code, the object "titi" is instanciate, but "Header" is always null.
How retrieve the "toto" value from xml ?

XML is case sensitive, so you need to use [XmlElement("header")] to inform the serializer of the correct element name for the Header property:
public abstract class Response
{
[XmlElement("header")]
public HeaderResponse Header { get; set; }
public Response()
{
}
}
The [XmlRoot("header")] you have applied to HeaderResponse only controls its element name when it is the root element of an XML document.

You need to add the link to the abstract class like this :
[XmlRoot(ElementName = "Response")]
public abstract class Response
{
public HeaderResponse Header { get; set; }
public Response()
{
}
}
[XmlRoot(ElementName = "Response")]
public class DirectorSearchResponse : Response
{
public DirectorSearchResponse() : base()
{
/* DO NOTHING */
}
}

Related

C# Generic way to store unknown properties in List

I'd like to store LicenseInformations for multiple domains in my application.
The structure looks the following way:
public class LicenseData
{
// properties...
public List<LicenseDomain> Domains { get; set; }
// other properties...
}
public class LicenseDomain
{
// properties...
public object LicenseConfig { get; set; }
}
We have multiple domains with total different properties, but the license may contain multiple configurations..
For example:
{
"MaxValidUsers": 5
}
{
"Property": "xy"
"SubProperty": { "Foo" : "Bar"
}
}
The generation is no problem in any way..
But if I restore the informations from my signed json file I deserialize to object..
Which pattern / possiblity I have to work with Interfaces / Abstracts / that I can (RE)store generic informations here..
Right now I hack with:
JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(domain.LicenseConfig))
But I can't agree with myself.
So, based on the pieces of context I can grab, I would actually recommend having your LicenseConfig stored as a JSON string, which would give you the ability to do something like this:
public class LicenseDomain
{
// properties...
// Depending on how this is loaded,
// this property (or at least its setter) could be made private/protected/internal
public string LicenseConfigJson { get; set; }
public T LicenseConfig<T>() where T : BaseLicenseConfig
{
if (string.IsNullOrWhiteSpace(LicenseConfigJson))
{
return null;
}
return JsonConvert.DeserializeObject<T>(LicenseConfigJson);
}
public void SaveLicenseConfig<T>(T config) where T : BaseLicenseConfig
{
if (config == null)
{
LicenseConfigJson = null;
}
else
{
LicenseConfigJson = JsonConvert.SerializeObject(config);
}
}
}
Or if each LicenseDomain can only have one type of LicenseConfig, you could make it a generic parameter to the class:
public class LicenseData
{
// properties...
public List<LicenseDomain<BaseLicenseConfig>> Domains { get; set; }
// other properties...
}
public class LicenseDomain<T> where T : BaseLicenseConfig
{
// properties...
// Depending on where this value comes from, you could do this a variety of ways,
//but this is just one
public string LicenseConfigJson { get; set; }
public T LicenseConfig
{
get
{
if (string.IsNullOrWhiteSpace(LicenseConfigJson))
{
return null;
}
return JsonConvert.DeserializeObject<T>(LicenseConfigJson);
}
set
{
if (value == null)
{
LicenseConfigJson = null;
}
else
{
LicenseConfigJson = JsonConvert.SerializeObject(value);
}
}
}
}
public abstract class BaseLicenseConfig
{
}
public class LicConfig1 : BaseLicenseConfig
{
public int MaxValidUsers { get; set;}
}
public class LicConfig2 : BaseLicenseConfig
{
public string Property {get;set;}
public SubProp SubProperty {get;set;}
}
public class SubProp
{
public string Foo {get;set;}
}
In both cases, the BaseLicenseConfig class is strictly to enforce that everything in the domain list can come from a base class of some kind. If that's not important, you don't need the base class and can remove the where T : BaseLicenseConfig from LicenseDomain class.

Override a property to another type on derived class

I'm trying to find out a solution for this, but I'm not sure if it's possible or not.
I have a base class, lets say
public class A
{
[XmlAttribute("Date")]
public DateTime Date {get;set;}
}
and a derived class:
public class B: A
{
[XmlAttribute("Date")]
public new String StringDate {get;set;}
}
I have to serialize a Xml.
The value of "Date" on the Xml, is String and in fact it's not a DateTime format string. But I use "A" for many other stuff so I cannot just change it to String without affecting other parts of the program. Sadly it is not an option.
So my idea is to create a derived class "B" who inherit everything of "A" and overrided the property Date to get it fill from the deserialization and then format it to DateTime.
I read about virtual or abstracts but I'm not acquainted with it and don't have any clue about it, if it is the solution maybe someone can guide me on the first steps.
Anyone can help me?
EDIT
XML:
<Vorgang Vorgang="HQHT8GTQ">
<Vertragsbeginn Vertragsbeginn="20140202" />
</Vorgang>
Class A:
[DataContract(Name = "Vorgang")]
[KnownType(typeof(Vorgang))]
public class Vorgang
{
[IgnoreDataMember]
public DateTime Vertragsbeginn { get; set; }
}
Class B:
public class VorgangOverride : UTILMD.Vorgang
{
private string datestring;
[XmlAttribute("Vertragsbeginn")]
public new String Vertragsbeginn {
get { return datestring; }
set
{
base.Vertragsbeginn = DateUtil.StringToDate(value, EDIEnums.Vertragsbeginn);
datestring = value;
}
}
}
Deserialization method:
private static VorgangOverride Deserialize (XmlNode inVorgang)
{
using (MemoryStream stm = new MemoryStream())
{
using (StreamWriter stw = new StreamWriter(stm))
{
stw.Write(inVorgang.OuterXml);
stw.Flush();
stm.Position = 0;
XmlRootAttribute xRoot = new XmlRootAttribute { ElementName = "Vorgang", IsNullable = true };
var serializer = new XmlSerializer(typeof(VorgangOverride), xRoot);
VorgangOverride podItem = (VorgangOverride) serializer.Deserialize(stm);
return podItem;
}
}
}
EDIT:
Solved using
[XmlRoot("Vorgang")]
public class VorgangOverride
{
public VorgangOverride()
{
}
#region Public Properties
public string datestring;
[XmlElement("Vertragsbeginn")]
public Vertragsbeginn VertragsbeginnAsString { get ; set ;}
#endregion
}
public class Vertragsbeginn
{
[XmlAttribute("Vertragsbeginn")]
public String vertragsbeginn { get; set; }
}
I found the solution:
[DataContract(Name = "Vorgang")]
[KnownType(typeof(Vorgang))]
public class Vorgang
{
[XmlIgnore] // use XmlIgnore instead IgnoreDataMember
public DateTime Vertragsbeginn { get; set; }
}
// this class map all elements from the xml that you show
[XmlRoot("Vorgang")] // to map the Xml Vorgang as a VorgangOverride instance
public class VorgangOverride : Vorgang
{
[XmlAttribute("Vorgang2")] // to map the Vorgang attribute
public string VorgangAttribute { get; set; }
[XmlElement(ElementName = "Vertragsbeginn")] // to map the Vertragsbeginn element
public Vertragsbeginn VertragsbeginnElement
{
get { return _vertragsbeginn; }
set
{
base.Vertragsbeginn = new DateTime(); // here I Assing the correct value to the DateTime property on Vorgan class.
_vertragsbeginn = value;
}
}
private Vertragsbeginn _vertragsbeginn;
}
// this class is used to map the Vertragsbeginn element
public class Vertragsbeginn
{
[XmlAttribute("Vertragsbeginn")] // to map the Vertragsbeginn attriubute on the Vertragsbeginn element
public string VertragsbeginnAttribute { get; set; }
}
later I say:
var string xmlContent =
#"<Vorgang Vorgang2=""HQHT8GTQ"">
<Vertragsbeginn Vertragsbeginn=""20140202"" />
</Vorgang>";
var a = Deserialize<VorgangOverride>(xmlContent);
and this is the method to Deserialize:
// method used to deserialize an xml to object
public static T Deserialize<T>(string xmlContent)
{
T result;
var xmlSerializer = new XmlSerializer(typeof(T));
using (TextReader textReader = new StringReader(xmlContent))
{
result = ((T)xmlSerializer.Deserialize(textReader));
}
return result;
}
You will not be able to override a property with an other class type.
The reason is Polymorphism. (more information: https://msdn.microsoft.com/en-us/library/ms173152.aspx)
You can cast the class B to class A. Which means the class B must have all the properties and methods class A has, too. But in your case class B would have a String rather than a Date called Date. Which is simply not possible.

Json.net and JsonIgnore in Serializing

i have an object which have an attribute of Serializable, this class inherit from abstract class which inherit from other class which also Serializable which inherit from an interface
i have used
string included = JsonConvert.SerializeObject(msg,
Formatting.Indented,
new JsonSerializerSettings { /*ContractResolver = new NotificationPropertyResolver()*/ TypeNameHandling = TypeNameHandling.All});
as msg is the interface
I want to send this object in SignalR and i see that it dont ignore any member,
i have decorated the interface and the classes
is there solution for that?
i have tried also to use resolver with my own attributes - but still same results
the classes are to big but ...
[Serializable]
[WebAPINotification(Type = typeof(CSensor), Group = "Sensor")]
public class SensorsStateModeNotification : SensorNotification, IBPMPackagedNotification
public abstract class SensorNotification : BasicLanNotification, ISensNotification
[Serializable]
public class BasicLanNotification : BasicNotification, ILanNotification
[Serializable]
public abstract class BasicNotification : INotification, ISerializable, IOpSerializable
[JsonIgnore]
public long SentAt
{
get
{
return m_sentAt;
}
set
{
m_sentAt = value;
}
}
/// <summary>
///
/// </summary>
[JsonIgnore]
public ENotificationGateway NotificationGateway
{
get
{
return m_NotifyGateway;
}
set
{
m_NotifyGateway = value;
}
}
Your type implements the ISerializable interface - that takes precedence over attributes. If you don't want to serialize the members of the class, simply don't return them in the ISerializable.GetObjectData implementation. See the SSCCE below (and by the way, in the future if you want better answers, you should provide one as well) for an example.
public class StackOverflow_18127665
{
public class WebAPINotificationAttribute : Attribute
{
public Type Type { get; set; }
public string Group { get; set; }
}
public class CSensor { }
public interface INotification { }
public interface IOpSerializable { }
public interface IBPMPackagedNotification { }
public interface ILanNotification { }
public interface ISensNotification { }
[Serializable]
[WebAPINotification(Type = typeof(CSensor), Group = "Sensor")]
public class SensorsStateModeNotification : SensorNotification, IBPMPackagedNotification { }
public abstract class SensorNotification : BasicLanNotification, ISensNotification { }
[Serializable]
public class BasicLanNotification : BasicNotification, ILanNotification { }
[Serializable]
public abstract class BasicNotification : INotification, ISerializable, IOpSerializable
{
long m_sentAt;
ENotificationGateway m_NotifyGateway;
[JsonIgnore]
public long SentAt
{
get
{
return m_sentAt;
}
set
{
m_sentAt = value;
}
}
/// <summary>
///
/// </summary>
[JsonIgnore]
public ENotificationGateway NotificationGateway
{
get
{
return m_NotifyGateway;
}
set
{
m_NotifyGateway = value;
}
}
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
// Comment the lines below not to have this serialized
info.AddValue("NotificationGateway", this.NotificationGateway);
info.AddValue("SentAt", this.SentAt);
}
#endregion
}
public enum ENotificationGateway { First, Second }
public static void Test()
{
BasicNotification msg = new BasicLanNotification
{
SentAt = 123,
NotificationGateway = ENotificationGateway.First
};
var str = JsonConvert.SerializeObject(
msg,
Newtonsoft.Json.Formatting.Indented,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
Console.WriteLine(str);
}
}
public class NotificationPropertyResolver : DefaultContractResolver
{
public NotificationPropertyResolver()
{
IgnoreSerializableAttribute = true;
IgnoreSerializableInterface = true;
}
}

How to determine if a customAttribute from a class is equals to another?

check that I have a customAttribute called ResponseAttributes. I have declared an interface and several concrete classes { Question 1, Question2, Question3 }
[AttributeUsage(AttributeTargets.Property)]
public class ResponseAttribute : Attribute { }
public interface IQuestion { }
public class Question1 : IQuestion
{
[Response]
public string Response { get; set; }
public Question1() { Response = "2+1"; }
}
public class Question2 : IQuestion
{
[Response]
public decimal Response { get; set; }
public Question2() { Response = 5; }
}
public class Question3 : IQuestion
{
[Response]
public string Response { get; set; }
public Question3() { Response = "2+1"; }
}
Now, what I'm trying to do is how to verify a class which contains that attribute is equals to another?
I mean:
List<IQuestion> questions = new List<IQuestion>()
{
new Question1(), new Question2()
};
Question3 question3 = new Question3();
foreach (var question in questions)
{
// how to verify this condition:
// if (customAttribute from question3 is equals to customAttribute fromquestion)
// of course the question3 is equals to 1
}
As you can, they are different types, that's the reason why I set as ResponseAttribute.
you could try using an interface, with Resposnse property (type object)
if you can not, you could use a class-level attribute that tell you the "Response property" than, you can use reflection on that property
Example:
public class ResponseAttribute : Attribute {
public string PropertyName { get; set }
}
[ResponseAttribute ("CustomResponse")}
public class Question1 {
public string CustomResponse;
}
via reflection
foreach(var question in questions) {
var responseAttr = (ResponseAttribute) question.GetType().GetCustomAttributes(typeof(ResponseAttribute));
var questionResponse= question.GetType().GetProperty(responseAttr.PropertyName,question,null);
}
try overriding equals method:
public override bool Equals(object obj)
{
if (obj is IQuestion)
return this.Response == ((IQuestion)obj).Response;
else
return base.Equals(obj);
}
hope this helps

How to ensure that the serialization and deserialization with WebServices is symmetric?

I have a couple of standard ASP.NET web methods that I'm calling from javascript with a parameter that is of a custom class in form
[DataContract]
[KnownType(typeof(MyOtherSubclass))]
public class MyClass
{
[DataMember]
public MyOtherClass MyMember { get; set; }
}
where MyOtherClass is a class marked with Serializable but not with DataContract attribute (I don't have a control over its generation). There is a couple of subclasses of MyOtherClass, e.g. MyOtherSubclass :
[Serializable]
public class MyOtherSubClass : MyOtherClass
{
private string valueField;
public string Value
{
get { return valueField; }
set { valueField = value; }
}
}
When I use the DataContractJsonSerializer to serialize an object of MyClass directly, I get a result similar to
{ "MyMember" : { "__type" : "MyOtherSubClass:#Namespace", "valueField" : "xxx" } }
However, when I pass such a JSON into the web method request from javascript, I get an exception while deserializing. I have experimented a little bit and found that when using the following one instead
{ "MyMember" : { "___type" : "Namespace.MyOtherSubClass", "Value" : "xxx" } }
the deserialization works without any problems.
Is there any way to configure the DataContractJsonSerializer in such a way that it would produce the JSON in the second form, so that the web method arguments deserialization would work ?
ASP.NET WebMethods use JavaScriptSerializer, so try serializing with it. You might need a custom type resolver in order to include this property:
public class Parent
{
public string ParentProp { get; set; }
}
public class Child: Parent
{
public string ChildProp { get; set; }
}
public class CustomResolver : JavaScriptTypeResolver
{
public override Type ResolveType(string id)
{
return Type.GetType(id);
}
public override string ResolveTypeId(Type type)
{
return type.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var o = new Child
{
ParentProp = "parent prop",
ChildProp = "child prop",
};
var serializer = new JavaScriptSerializer(new CustomResolver());
var s = serializer.Serialize(o);
Console.WriteLine(s);
}
}

Categories