I am trying to serialize a payload to XML to send to an external API. The properties included can vary a few layers down. Here's an example of what I'm working with model-wise:
[Serializable]
[XmlRoot(ElementName = "Envelope", Namespace = "soapenv")]
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public class SoapEnvelope<T> where T : TheBase<T>
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[]
{
new XmlQualifiedName("soapenv", "/"),
new XmlQualifiedName("impl", "/")
});
[XmlElement("Header", Namespace = "soapenv")]
public object Header { get; set; }
[XmlElement("Body", Namespace = "soapenv")]
public SoapBody<T> Body { get; set; }
}
[Serializable]
public class SoapBody<T> where T : TheBase<T>
{
[XmlElement("InnerEnvelope")]
public TheBase<T> Envelope { get; set; }
}
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public class TheBase<T>
{
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public EnvelopeContext EnvelopeContext { get; set; }
}
public class Derived1 : TheBase<Derived1>
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch", ";) });
[XmlElement("EnvelopeBodyList", Namespace = "sch")]
public DerivedClass1Subclass EnvelopeBodyList { get; set; }
}
public class Derived2 : TheBase<Derived2>
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch2", ";) });
[XmlElement("EnvelopeBodyList", Namespace = "sch2")]
public DerivedClass2Subclass EnvelopeBodyList { get; set; }
}
public class Derived3 : TheBase<Derived3>
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch3", ";) });
[XmlElement("EnvelopeBodyList", Namespace = "sch3")]
public DerivedClass3Subclass EnvelopeBodyList { get; set; }
}
My service class is executing this function to write to XML:
public string ConvertRequestToXml<T>(T request) where T : TheBase<T>
{
string returnString;
var envelope = new SoapEnvelope<T>();
envelope.Body = new SoapBody<T>();
envelope.Body.Envelope = request;
try
{
var xmlSerializer = new XmlSerializer(typeof(SoapEnvelope<T>));
using (var stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, envelope);
returnString = stringWriter.ToString();
}
}
catch (Exception ex)
{
_logger.LogError($"{ex.Source} {ex.Message} {ex.InnerException?.Message}");
throw;
}
return returnString;
}
When I call this with Derived3, I get the message:
"The type namespaceblah.namespaceblah.Derived3 was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."
- I've tried with XmlInclude attributes for Derived1, Derived2, Derived3 on SoapEnvelope and on TheBase, on only either one and on both.
- I've tried replacing and tried supplementing the XmlInclude attributes with SoapInclude attributes.
- I've tried the same implementations without the designators.
- I've tried with an without the Serializable attributes.
- I've tried attaching the Serializable attribute all the way down on the classes making up the properties of Derived3.
I've reviewed several/many questions on SO regarding using XmlInclude for derived classes and still can't find something that works.
I always get this error. What am I missing in getting the derived classes to serialize properly here?
Tried this alternative at a below suggestion:
[Serializable]
[XmlRoot(ElementName = "Envelope", Namespace = "soapenv")]
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public class SoapEnvelope
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[]
{
new XmlQualifiedName("soapenv", "/"),
new XmlQualifiedName("impl", "/")
});
[XmlElement("Header", Namespace = "soapenv", IsNullable = true)]
public object Header { get; set; }
[XmlElement("Body", Namespace = "soapenv")]
public SoapBody Body { get; set; }
}
[Serializable]
public class SoapBody
{
[XmlElement("InnerEnvelope")]
public TheBase Envelope { get; set; }
}
[Serializable]
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public abstract class TheBase{ }
[Serializable]
public class Derived1: TheBase
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch", ";) });
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public EnvelopeContext EnvelopeContext { get; set; }
[XmlElement("EnvelopeBodyList", Namespace = "sch")]
public EnvelopeBodyList EnvelopeBodyList { get; set; }
}
[Serializable]
public class Derived2 : TheBase
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch2", ";) });
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public EnvelopeContext EnvelopeContext { get; set; }
[XmlElement("EnvelopeBodyList", Namespace = "sch2")]
public EnvelopeBodyList2 EnvelopeBodyList { get; set; }
}
[Serializable]
public class Derived3 : TheBase
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch3", ";) });
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public EnvelopeContext EnvelopeContext { get; set; }
[XmlElement("EnvelopeBodyList", Namespace = "sch3")]
public EnvelopeBodyList3 EnvelopeBodyList { get; set; }
}
public string ConvertRequestToXml(TheBase request)
{
string returnString;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(SoapEnvelope));
var envelope = new SoapEnvelope();
envelope.Body = new SoapBody();
envelope.Body.Envelope = request;
try
{
using (var stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, envelope);
returnString = stringWriter.ToString();
}
}
catch (Exception ex)
{
_logger.LogError($"{ex.Source} {ex.Message} {ex.InnerException?.Message}");
throw;
}
return returnString;
}
I am still getting this message: The type {namespace}.{namespace}.{namespace}.Derived3 was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
I am trying to serialize a payload to XML to send to an external API. The properties included can vary a few layers down. Here's an example of what I'm working with model-wise:
[Serializable]
[XmlRoot(ElementName = "Envelope", Namespace = "soapenv")]
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public class SoapEnvelope<T> where T : TheBase<T>
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[]
{
new XmlQualifiedName("soapenv", "http://schemas.xmlsoap./soap/envelope/"),
new XmlQualifiedName("impl", "http://v1.blahblah/")
});
[XmlElement("Header", Namespace = "soapenv")]
public object Header { get; set; }
[XmlElement("Body", Namespace = "soapenv")]
public SoapBody<T> Body { get; set; }
}
[Serializable]
public class SoapBody<T> where T : TheBase<T>
{
[XmlElement("InnerEnvelope")]
public TheBase<T> Envelope { get; set; }
}
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public class TheBase<T>
{
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public EnvelopeContext EnvelopeContext { get; set; }
}
public class Derived1 : TheBase<Derived1>
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch", "http://www.blbl/schemas") });
[XmlElement("EnvelopeBodyList", Namespace = "sch")]
public DerivedClass1Subclass EnvelopeBodyList { get; set; }
}
public class Derived2 : TheBase<Derived2>
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch2", "http://www.blbl/schemas") });
[XmlElement("EnvelopeBodyList", Namespace = "sch2")]
public DerivedClass2Subclass EnvelopeBodyList { get; set; }
}
public class Derived3 : TheBase<Derived3>
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch3", "http://www.blbl/schemas") });
[XmlElement("EnvelopeBodyList", Namespace = "sch3")]
public DerivedClass3Subclass EnvelopeBodyList { get; set; }
}
My service class is executing this function to write to XML:
public string ConvertRequestToXml<T>(T request) where T : TheBase<T>
{
string returnString;
var envelope = new SoapEnvelope<T>();
envelope.Body = new SoapBody<T>();
envelope.Body.Envelope = request;
try
{
var xmlSerializer = new XmlSerializer(typeof(SoapEnvelope<T>));
using (var stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, envelope);
returnString = stringWriter.ToString();
}
}
catch (Exception ex)
{
_logger.LogError($"{ex.Source} {ex.Message} {ex.InnerException?.Message}");
throw;
}
return returnString;
}
When I call this with Derived3, I get the message:
"The type namespaceblah.namespaceblah.Derived3 was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."
- I've tried with XmlInclude attributes for Derived1, Derived2, Derived3 on SoapEnvelope and on TheBase, on only either one and on both.
- I've tried replacing and tried supplementing the XmlInclude attributes with SoapInclude attributes.
- I've tried the same implementations without the designators.
- I've tried with an without the Serializable attributes.
- I've tried attaching the Serializable attribute all the way down on the classes making up the properties of Derived3.
I've reviewed several/many questions on SO regarding using XmlInclude for derived classes and still can't find something that works.
I always get this error. What am I missing in getting the derived classes to serialize properly here?
Tried this alternative at a below suggestion:
[Serializable]
[XmlRoot(ElementName = "Envelope", Namespace = "soapenv")]
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public class SoapEnvelope
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[]
{
new XmlQualifiedName("soapenv", "http://schemas.xmlsoap./soap/envelope/"),
new XmlQualifiedName("impl", "http://blhablhab/")
});
[XmlElement("Header", Namespace = "soapenv", IsNullable = true)]
public object Header { get; set; }
[XmlElement("Body", Namespace = "soapenv")]
public SoapBody Body { get; set; }
}
[Serializable]
public class SoapBody
{
[XmlElement("InnerEnvelope")]
public TheBase Envelope { get; set; }
}
[Serializable]
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public abstract class TheBase{ }
[Serializable]
public class Derived1: TheBase
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch", "http://www.vendorcompany/schemas") });
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public EnvelopeContext EnvelopeContext { get; set; }
[XmlElement("EnvelopeBodyList", Namespace = "sch")]
public EnvelopeBodyList EnvelopeBodyList { get; set; }
}
[Serializable]
public class Derived2 : TheBase
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch2", "http://www.vendorcompany/schemas") });
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public EnvelopeContext EnvelopeContext { get; set; }
[XmlElement("EnvelopeBodyList", Namespace = "sch2")]
public EnvelopeBodyList2 EnvelopeBodyList { get; set; }
}
[Serializable]
public class Derived3 : TheBase
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch3", "http://www.vendorcompany/schemas") });
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public EnvelopeContext EnvelopeContext { get; set; }
[XmlElement("EnvelopeBodyList", Namespace = "sch3")]
public EnvelopeBodyList3 EnvelopeBodyList { get; set; }
}
public string ConvertRequestToXml(TheBase request)
{
string returnString;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(SoapEnvelope));
var envelope = new SoapEnvelope();
envelope.Body = new SoapBody();
envelope.Body.Envelope = request;
try
{
using (var stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, envelope);
returnString = stringWriter.ToString();
}
}
catch (Exception ex)
{
_logger.LogError($"{ex.Source} {ex.Message} {ex.InnerException?.Message}");
throw;
}
return returnString;
}
I am still getting this message: The type {namespace}.{namespace}.{namespace}.Derived3 was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
Share Improve this question edited Mar 13 at 14:43 stevestevesteve asked Mar 12 at 21:29 stevestevestevestevestevesteve 788 bronze badges 5 |1 Answer
Reset to default 0I'm not getting any errors with this code. I change some types to XmlElement.
namespace ConsoleApp11
{
class Program
{
static void Main(string[] args)
{
TheBase theBase = new TheBase();
string results = theBase.ConvertRequestToXml(theBase);
}
}
[Serializable]
[XmlRoot(ElementName = "Envelope", Namespace = "soapenv")]
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public class SoapEnvelope
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[]
{
new XmlQualifiedName("soapenv", "http://schemas.xmlsoap./soap/envelope/"),
new XmlQualifiedName("impl", "http://blhablhab/")
});
[XmlElement("Header", Namespace = "soapenv", IsNullable = true)]
public XmlElement Header { get; set; }
[XmlElement("Body", Namespace = "soapenv")]
public SoapBody Body { get; set; }
}
[Serializable]
public class SoapBody
{
[XmlElement("InnerEnvelope")]
public TheBase Envelope { get; set; }
}
[Serializable]
[XmlInclude(typeof(Derived1))]
[XmlInclude(typeof(Derived2))]
[XmlInclude(typeof(Derived3))]
public class TheBase {
public string ConvertRequestToXml(TheBase request)
{
string returnString;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(SoapEnvelope));
var envelope = new SoapEnvelope();
envelope.Body = new SoapBody();
envelope.Body.Envelope = request;
try
{
using (var stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, envelope);
returnString = stringWriter.ToString();
}
}
catch (Exception ex)
{
//_logger.LogError($"{ex.Source} {ex.Message} {ex.InnerException?.Message}");
throw;
}
return returnString;
}
}
[Serializable]
public class Derived1 : TheBase
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch", "http://www.vendorcompany/schemas") });
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public XmlElement EnvelopeContext { get; set; }
[XmlElement("EnvelopeBodyList", Namespace = "sch")]
public XmlElement EnvelopeBodyList { get; set; }
}
[Serializable]
public class Derived2 : TheBase
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch2", "http://www.vendorcompany/schemas") });
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public XmlElement EnvelopeContext { get; set; }
[XmlElement("EnvelopeBodyList", Namespace = "sch2")]
public XmlElement EnvelopeBodyList { get; set; }
}
[Serializable]
public class Derived3 : TheBase
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces { get; set; } = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("sch3", "http://www.vendorcompany/schemas") });
[XmlAttribute("Version")]
public string Version = "1.0";
[XmlElement("EnvelopeContext")]
public XmlElement EnvelopeContext { get; set; }
[XmlElement("EnvelopeBodyList", Namespace = "sch3")]
public XmlElement EnvelopeBodyList { get; set; }
}
}
TheBase<T>
generic? It doesn't seem to use theT
parameter at all. Is there any reason not to simply havepublic class TheBase { }
, maybeabstract
? – dbc Commented Mar 12 at 22:04XmlSerializer
edge case involving generics + polymorphism, I doubt we will be able to guess your problem from an incomplete, non-buildable example. – dbc Commented Mar 13 at 16:17