Problem
I am trying to XML serialize the class "ProfileSerialize" but I get this inner exception when calling xsSubmit.Serialize(writer, obj)
in the Serialize function shown below.
Exception
Message = "The type ProfileFormatNumber was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."
What I already tried
I tried to implement the solutions mentioned in these threads:
Reproducible example
Imports System
Imports System.Collections.Generic
Imports System.Collections
Imports System.IO
Imports System.Text
Imports System.Linq
Imports System.Reflection
Imports System.Xml.Serialization
Imports System.XML
' https://stackoverflow.com/questions/72856211/why-does-xmlserializer-fail-to-serialize-this-class-even-though-i-added-the-xmli
<XmlInclude(GetType(ProfileFormatNumber))>
Public Class ProfileFormat
<XmlElement(ElementName:="e1")>
Public Property Name As String = String.Empty
End Class
Public Class ProfileFormatNumber
Inherits ProfileFormat
<XmlElement(ElementName:="e1")>
Public Property Divider As Integer = 1
End Class
Public Class Serializer(Of T)
Public Shared Function Serialize(ByVal obj As T) As String
Dim xsSubmit As XmlSerializer = New XmlSerializer(GetType(T))
Using sww = New StringWriter()
Using writer As XmlTextWriter = New XmlTextWriter(sww) With {.Formatting = Formatting.Indented}
xsSubmit.Serialize(writer, obj)
Return sww.ToString() ' I would recommend moving this out of the inner Using statement to guarantee the XmlWriter is flushed and closed
End Using
End Using
End Function
End Class
Public Module Module1
Public Sub Main()
Dim profileFormat = New ProfileFormatNumber With { .Name = "my name", .Divider = 111 }
Dim xml2 = Serializer(Of ProfileFormat).Serialize(profileFormat)
Console.WriteLine(xml2)
End Sub
End Module
My question
How do I need to modify my code to correctly use the <XmlInclude(GetType())> attribute? I tried adding it in multiple places but always receive the same exception.
CodePudding user response:
Your problem is not with XmlInclude
. Your problem is that you are trying to assign the two properties of ProfileFormatNumber
, Divider
and (from the base class) Name
, to the same element name <e1>
by setting <XmlElement(ElementName:="e1")>
on both. I.e. if were able to serialize your ProfileFormatNumber
as-is, the XML would look like:
<ProfileFormat xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="ProfileFormatNumber">
<e1>my name</e1>
<e1>111</e1>
</ProfileFormat>
However XmlSerializer
does not support this (perhaps because there would be ambiguity in deserialization), hence the (slightly inscrutable) error complaining that the element name e1
is already present:
The XML element 'e1' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.]
Instead, use a different obfuscated element name for ProfileFormatNumber.Divider
such as <f1>
:
<XmlInclude(GetType(ProfileFormatNumber))>
Public Class ProfileFormat
<XmlElement(ElementName:="e1")>
Public Property Name As String = String.Empty
End Class
Public Class ProfileFormatNumber
Inherits ProfileFormat
<XmlElement(ElementName:="f1")>
Public Property Divider As Integer = 1
End Class
Demo fiddle here.