Out of memory exception on deserializing IPAddress - c#

When I try to deserialize from MyConfig.xml I get an out of memory exception at
System.Net.IPAddress.InternalParse(String ipString, Boolean tryParse)
System.Net.IPAddress.Parse(String ipString)
MyNamespace.IPRange.ReadXml(XmlReader reader)
IPRange.cs
public class IPRange : IXmlSerializable
{
public IPRange () { }
public IPAddress StartIP { get; set; }
public IPAddress EndIP { get; set; }
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
this.StartIP = IPAddress.Parse(reader.GetAttribute("StartIP"));
this.EndIP = IPAddress.Parse(reader.GetAttribute("EndIP"));
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("StartIP", this.StartIP.ToString());
writer.WriteAttributeString("EndIP", this.EndIP.ToString());
}
}
MyConfig.cs
public class MyConfig
{
[XmlArrayItem("IPRange")]
public List<IPRange> DMZ { get; set; }
}
MyConfig.xml
<?xml version="1.0" encoding="utf-8" ?>
<MyConfig>
<DMZ>
<IPRange StartIP="{some start ip}" EndIP="{some end ip}" />
<IPRange StartIP="{some start ip}" EndIP="{some end ip}" />
</DMZ>
</MyConfig>
I don't know what I'm doing wrong.
Please help me with this problem.
Thanks!

I've fixed it by writing reader.Read() at the end of the function...
public void ReadXml(XmlReader reader)
{
this.StartIP = IPAddress.Parse(reader.GetAttribute("StartIP"));
this.EndIP = IPAddress.Parse(reader.GetAttribute("EndIP"));
reader.Read();
}

Related

How do I serialize a class to a string?

How to serialize the OrganizationType class?
No additional properties - wrappers.
public class INNType : IConvertToString
{
protected INNType() { }
public string Value { get; }
public INNType(string inn)
{
if (!Regex.IsMatch(inn, #"^\d{10}$")) throw new Exception(#"");
Value = inn;
}
public override string ToString() => Value;
public static implicit operator INNType(string inn) => new INNType(inn);
public static implicit operator string(INNType inn) => inn?.Value;
}
[Serializable]
[XmlType(Namespace = "http://roskazna.ru/gisgmp/xsd/Organization/2.2.0")]
public class OrganizationType
{
protected OrganizationType() {}
[XmlAttribute("inn")]
public INNType Inn {get; set;}
}
After serialization, it should look like below.
<OrganizationType inn="1234567890" />
The method used to serialize objects looks like this
public static XmlDocument SerializerObject<T>(T obj, XmlSerializerNamespaces xsn) where T : class
{
XmlDocument xmlDocument = new XmlDocument();
using (var xs = xmlDocument.CreateNavigator().AppendChild())
{
new XmlSerializer(typeof(T)).Serialize(xs, obj, xsn);
}
return xmlDocument;
}
Exception
System.InvalidOperationException : Cannot serialize member 'Inn' of type GisGmp.INNType. XmlAttribute/XmlText cannot be used to encode complex types.
I have to do it. Not good.
[XmlIgnore]
public INNType Inn {get; set;}
[XmlAttribute("inn")]
public string WrapperInn { get => Inn; set => Inn = value; }
You could implement IXmlSerializable:
[Serializable]
public class OrganizationType : IXmlSerializable
{
public OrganizationType()
{
// Demo
this.Inn = new INNType("0123456789");
}
[XmlAttribute("inn")]
public INNType Inn { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
return;
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("inn", this.Inn.Value);
}
}
Output:
<OrganizationType inn="0123456789" />

custom Xml Serializer to make value as an xml element

Classes:
public class Employee
{
public int Id { get; set; }
public PhoneNumber[] Numbers { get; set; }
}
public class PhoneNumber
{
public string Type { get; set; }
public string Number { get; set; }
}
Code to serialize:
var xmlSerializer = new XmlSerializer(typeof(Employee));
var xwSettings = new XmlWriterSettings {Indent = true, OmitXmlDeclaration = true};
string serializedResult;
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, xwSettings))
{
xmlSerializer.Serialize(writer, emp);
serializedResult = stream.ToString();
}
Current Result:
<Employee>
<Id>1</Id>
<Numbers>
<PhoneNumber>
<Type>Home</Type>
<Number>1231231231</Number>
</PhoneNumber>
<PhoneNumber>
<Type>Office</Type>
<Number>3453453453</Number>
</PhoneNumber>
</Numbers>
</Employee>
Desired Result:
<Employee>
<Id>1</Id>
<Numbers>
<Home>1231231231</Home>
<Office>3453453453</Office>
</Numbers>
</Employee>
PhoneNumber Type can be added dynamically like "GuestRoomPhone" etc, so adding properties for each phone number type is not an option.
You can do this by implementing the IXmlSerializable interface on your classes. This allows you to control how the values are written and read.
public class Employee : IXmlSerializable
{
public int Id { get; set; }
public PhoneNumber[] Numbers { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
reader.ReadStartElement("Employee");
reader.ReadStartElement("Id");
Id = reader.ReadContentAsInt();
reader.ReadEndElement(); // Id
reader.ReadStartElement("Numbers");
List<PhoneNumber> numbers = new List<PhoneNumber>();
while (reader.MoveToContent() == XmlNodeType.Element)
{
PhoneNumber num = new PhoneNumber();
num.ReadXml(reader);
numbers.Add(num);
}
Numbers = numbers.ToArray();
reader.ReadEndElement(); // Numbers
reader.ReadEndElement(); // Employee
}
public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement("Id");
writer.WriteValue(Id);
writer.WriteEndElement();
writer.WriteStartElement("Numbers");
foreach (PhoneNumber num in Numbers)
{
num.WriteXml(writer);
}
writer.WriteEndElement(); // Numbers
}
}
Similarly for the PhoneNumber class.
public class PhoneNumber : IXmlSerializable
{
public string Type { get; set; }
public string Number { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
while (!reader.IsStartElement())
reader.Read();
Type = reader.Name;
Number = reader.ReadElementContentAsString();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement(Type);
writer.WriteString(Number);
writer.WriteEndElement();
}
}

How to serialize an object to a raw XML

Background :
I am working on this integration solution where I have to implement a WCF service (BizTalk) with a custom fault contract. The fault message should look like follows,
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>002</faultcode>
<faultstring>some fault</faultstring>
<detail>
<wor:invalidMessageFault xmlns:wor="somenamespace">
<faultCode>002</faultCode>
<faultReference>Client WebService</faultReference>
<faultText>some fault</faultText>
</wor:invalidMessageFault>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
So far: I have created a custom fault inspector to intercept the fault message and send back the fault.
Problem : I need to construct the <detail> section of the fault message and as far as I figured out only way to do it is to dump raw xml into it, because in the fault message construction,
var faultException = new FaultException<RawXMLString>(raw, fault.faultText, new FaultCode(fault.faultCode)).CreateMessageFault();
It only accept an object (which can be serialized) as detail, and I tried different things but I could construct the same message with object.
Finally I thought of using a custom serialization to generate the exact message,
public class RawXMLString : IXmlSerializable
{
private string xmlTemplate = #"<wor:invalidMessageFault xmlns:wor="some namespace">
<faultCode>{0}</faultCode>
<faultReference>Client WebService</faultReference>
<faultText>{1}</faultText>
</wor:invalidMessageFault>";
public string FaultCode { get; set; }
public string FaultText { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteRaw(string.Format(xmlTemplate,FaultCode,FaultText));
}
}
Now there is another issue, because I don't want <RawXMLString> tag, is there any way to force serializer to ignore the root?
Does this fit the bill?
[XmlRoot(Namespace = "somenamespace",
ElementName = "invalidMessageFault")]
public class InvalidMessageFault : IXmlSerializable
{
public string FaultCode { get; set; }
public string FaultText { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteElementString("faultCode", FaultCode);
writer.WriteElementString("faultReference", "Client WebService");
writer.WriteElementString("faultText", FaultText);
}
}
Change the code to:
[XmlRoot("wor:invalidMessageFault xmlns:wor=\"some namespace\"")]
public class RawXMLString : IXmlSerializable
{
private string xmlTemplate = #"<faultCode>{0}</faultCode>
<faultReference>Client WebService</faultReference>
<faultText>{1}</faultText>";
public string FaultCode { get; set; }
public string FaultText { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteRaw(string.Format(xmlTemplate,FaultCode,FaultText));
}
}

XML Serialization on a custom data

I have a XML file:
<Hand cards="C5,SQ,DQ,H8,C9,H7,S9,D5,DA,CJ,S6,HK,D4">
</Hand>
I define a class
[Serializable()]
[XmlRoot("Hand")]
public class Hand
{
[XmlAttribute("cards")]
public List<string> Cards{get;set;}
}
How to deserialize a XML to object in this case? Hand object result must have Cards = {C5,SQ,DQ,H8,C9,H7,S9,D5,DA,CJ,S6,HK,D4}.
You cannot.
What you can do is to create a property which will do this conversion in its getter/setter
[XmlIgnore]
public List<string> CardList { get; private set; }
[XmlAttribute("cards")]
public string Cards {
get { return String.Join(",", CardList); }
set { CardList = value.Split(",").ToList(); }
}
You can do this with the help of IXmlSerializable. Read more about it on MSDN.
This way
[Serializable()]
[XmlRoot("Hand")]
public class Hand : IXmlSerializable {
[XmlAttribute("cards")]
public List<string> Cards { get; set; }
public System.Xml.Schema.XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader) {
this.Cards = new List<string>(reader.GetAttribute("cards").Split(','));
}
public void WriteXml(XmlWriter writer) {
writer.WriteAttributeString("cards",
string.Join(",",
this.Cards != null ? this.Cards : new List<string>()));
}
}
Hope this helps you.

Implementing IXmlSerializable on a collection object

I have an xml file looking somewhat like this:
<xml>
<A>value</A>
<B>value</B>
<listitems>
<item>
<C>value</C>
<D>value</D>
</item>
</listitems>
</xml>
And I have a two objects representing this xml:
class XmlObject
{
public string A { get; set; }
public string B { get; set; }
List<Item> listitems { get; set; }
}
class Item : IXmlSerializable
{
public string C { get; set; }
public string D { get; set; }
//Implemented IXmlSerializeable read/write
public void ReadXml(System.Xml.XmlReader reader)
{
this.C = reader.ReadElementString();
this.D = reader.ReadElementString();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteElementString("C", this.C);
writer.WriteElementString("D", this.D);
}
}
I use the XmlSerializer to serialize/deserialize the XmlObject to file.
The problem is that when I implemented the custom IXmlSerializable functions on my "sub-object" Item I always only get one item(the first) in my XmlObject.listitems collection when deserializing the file.
If I remove the : IXmlSerializable everything works as expected.
What do I do wrong?
Edit: I have have implemented IXmlSerializable.GetSchema and I need to use IXmlSerializable on my "child-object" for doing some custom value transformation.
Modify your code like this:
public void ReadXml(System.Xml.XmlReader reader)
{
reader.Read();
this.C = reader.ReadElementString();
this.D = reader.ReadElementString();
reader.Read();
}
First you skip the start of the Item node, read the two strings, then read past the end node so the reader is at the correct place. This will read all nodes in the array.
You need to pay attention when modifying xml yourself :)
You don't need to use IXmlSerializable. But if you want you should implement GetShema() method. After some modification code that works looks like that:
[XmlRoot("XmlObject")]
public class XmlObject
{
[XmlElement("A")]
public string A { get; set; }
[XmlElement("B")]
public string B { get; set; }
[XmlElement("listitems")]
public List<Item> listitems { get; set; }
}
public class Item : IXmlSerializable
{
[XmlElement("C")]
public string C { get; set; }
[XmlElement("D")]
public string D { get; set; }
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(System.Xml.XmlReader reader)
{
this.C = reader.ReadElementString();
this.D = reader.ReadElementString();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteElementString("C", this.C);
writer.WriteElementString("D", this.D);
}
#endregion
}
Results for 2 items in itemlist will look like that:
<?xml version="1.0" encoding="utf-8"?>
<XmlObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<A>value</A>
<B>value</B>
<listitems>
<C>value0</C>
<D>value0</D>
</listitems>
<listitems>
<C>value1</C>
<D>value1</D>
</listitems>
</XmlObject>

Categories