Populating ANY elements on a web service in C#

后端 未结 3 1456
误落风尘
误落风尘 2020-12-21 04:42

Can someone point me to a C# example where they populate a request and receive the response for a web service where the schema is mostly implemented as ANY elements?

3条回答
  •  心在旅途
    2020-12-21 05:36

    Your question is fairly general so I'm going to narrow it down a bit to the following situation: you have a type with an [XmlAnyElement] member like so:

    public class GenericRequestData_Type
    {
        private System.Xml.XmlElement[] anyField;
    
        [System.Xml.Serialization.XmlAnyElementAttribute()]
        public System.Xml.XmlElement[] Any
        {
            get
            {
                return this.anyField;
            }
            set
            {
                this.anyField = value;
            }
        }
    }
    

    And you would like to initialize the Any field to the following XML:

    
      
        Patrick Hines
        206-555-0144
        
    123 Main St Mercer Island WA 68042

    How can this be done?

    There are several options, so I'll break it down into a few different answers.

    Firstly, you could design c# classes corresponding to your desired XML using a code-generation tool such as http://xmltocsharp.azurewebsites.net/ or Visual Studio's Paste XML as Classes. Then you can serialize those classes directly to an XmlNode hierarchy using XmlSerializer combined with XmlDocument.CreateNavigator().AppendChild().

    First, introduce the following extension methods:

    public static class XmlNodeExtensions
    {
        public static XmlDocument AsXmlDocument(this T o, XmlSerializerNamespaces ns = null, XmlSerializer serializer = null)
        {
            XmlDocument doc = new XmlDocument();
            using (XmlWriter writer = doc.CreateNavigator().AppendChild())
                new XmlSerializer(o.GetType()).Serialize(writer, o, ns ?? NoStandardXmlNamespaces());
            return doc;
        }
    
        public static XmlElement AsXmlElement(this T o, XmlSerializerNamespaces ns = null, XmlSerializer serializer = null)
        {
            return o.AsXmlDocument(ns, serializer).DocumentElement;
        }
    
        public static T Deserialize(this XmlElement element, XmlSerializer serializer = null)
        {
            using (var reader = new ProperXmlNodeReader(element))
                return (T)(serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
        }
    
        /// 
        /// Return an XmlSerializerNamespaces that disables the default xmlns:xsi and xmlns:xsd lines.
        /// 
        /// 
        public static XmlSerializerNamespaces NoStandardXmlNamespaces()
        {
            var ns = new XmlSerializerNamespaces();
            ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
            return ns;
        }
    }
    
    public class ProperXmlNodeReader : XmlNodeReader
    {
        // Bug fix from this answer https://stackoverflow.com/a/30115691/3744182
        // To http://stackoverflow.com/questions/30102275/deserialize-object-property-with-stringreader-vs-xmlnodereader
        // By https://stackoverflow.com/users/8799/nathan-baulch
        public ProperXmlNodeReader(XmlNode node) : base(node) { }
    
        public override string LookupNamespace(string prefix)
        {
            return NameTable.Add(base.LookupNamespace(prefix));
        }
    }
    

    Next, define types corresponding to your hierarchy:

    [XmlRoot(ElementName = "Address")]
    public class Address
    {
        [XmlElement(ElementName = "Street1")]
        public string Street1 { get; set; }
        [XmlElement(ElementName = "City")]
        public string City { get; set; }
        [XmlElement(ElementName = "State")]
        public string State { get; set; }
        [XmlElement(ElementName = "Postal")]
        public string Postal { get; set; }
    }
    
    [XmlRoot(ElementName = "Contact")]
    public class Contact
    {
        [XmlElement(ElementName = "Name")]
        public string Name { get; set; }
        [XmlElement(ElementName = "Phone")]
        public string Phone { get; set; }
        [XmlElement(ElementName = "Address")]
        public Address Address { get; set; }
    }
    
    [XmlRoot(ElementName = "Contacts")]
    public class Contacts
    {
        [XmlElement(ElementName = "Contact")]
        public Contact Contact { get; set; }
    }
    
    [XmlRoot("GenericRequestData_Type")]
    public class Person
    {
        public string Name { get; set; }
        public DateTime BirthDate { get; set; }
        [XmlArray("Emails")]
        [XmlArrayItem("Email")]
        public List Emails { get; set; }
        [XmlArray("Issues")]
        [XmlArrayItem("Id")]
        public List IssueIds { get; set; }
    }
    

    Finally, initialize your GenericRequestData_Type as follows:

    var genericRequest = new GenericRequestData_Type();
    
    var contacts = new Contacts
    {
        Contact = new Contact
        {
            Name = "Patrick Hines",
            Phone = "206-555-0144",
            Address = new Address
            {
                Street1 = "123 Main St",
                City = "Mercer Island",
                State = "WA",
                Postal = "68042",
            },
        }
    };
    genericRequest.Any = new[] { contacts.AsXmlElement() };
    

    Sample fiddle.

提交回复
热议问题