admin管理员组

文章数量:1391969

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
  • Which line is giving error? This line looks wrong : xmlSerializer.Serialize(stringWriter, envelope); envelope should be an XML element. It is : var envelope = new SoapEnvelope<T>(); Try to avoid using "var" unless necessary. If you used the correct type you wo8uld of gotten an error when you compiled instead of getting an abstract error message at runtime. – jdweng Commented Mar 12 at 21:51
  • Why is TheBase<T> generic? It doesn't seem to use the T parameter at all. Is there any reason not to simply have public class TheBase { }, maybe abstract? – dbc Commented Mar 12 at 22:04
  • Yeah dbc I started off with just that… abstract class like you have there. Fot to say include that… been at it a while. – stevestevesteve Commented Mar 12 at 23:42
  • @dbc I put TheBase back to abstract and appended the relevant changes to the original question, still with the same error. I know you are very knowledgeable in this arena... do you see anything I could be missing? Or should I just punt and make three completely different SoapEnvelope models for each of the derived classes and just be a bit less SOLID? – stevestevesteve Commented Mar 13 at 14:45
  • I'm trying to reproduce your problem with your original code, but it doesn't compile, see dotnetfiddle/SpBKrq. And your alternative at a below doesn't compile either, see dotnetfiddle/lZRiea. Please edit your question to share a minimal reproducible example as indicated in How to Ask. Since you're possibly hitting some obscure XmlSerializer 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
Add a comment  | 

1 Answer 1

Reset to default 0
I'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; }
    }


}

本文标签: xmlHow to use XmlInclude for a Derived Nested Property of XmlSerializer InstanceStack Overflow