Controlling Namespace Prefixes in WCF XML Output

2019-05-15 15:27发布

问题:

The current output of my WCF service is as follows (only a portion is shown below):

<s:Body>
  <executeSelectSP2Response xmlns="http://tempuri.org/">
     <executeSelectSP2Result xmlns:a="http://schemas.datacontract.org/2004/07/WCF_Services.DataContract" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:Rows>
           <a:RowDetail>
              <a:Fields>
                 <a:FieldDetail>
                    <a:name>STATE_CD</a:name>
                    <a:value>1</a:value>
                 </a:FieldDetail>
                 <a:FieldDetail>
                    <a:name>STATE_CD_TXT</a:name>
                    <a:value>Alabama</a:value>
                 </a:FieldDetail>
                 <a:FieldDetail>
                    <a:name>STATE_CD_SHORT_TXT</a:name>
                    <a:value>AL</a:value>
                 </a:FieldDetail>
              </a:Fields>
           </a:RowDetail>

In the example, the "RowDetail" element is repeated for each US state.

I have two questions:

  1. How can I remove the "a:" prefix in the tags. I am assuming i need to change the xmlns setting, but I am not sure how to do this without throwing an error. I viewed other threads, but could not get it to work.

  2. Is it possible to remove the extraneous elements from the output, namely "Rows" and "Fields"? I understand why they are there - it is due to how I set up my classes (posted below), but it is messy to look at IMO.

Classes:

[DataContract]
public class Results2Detail
{
    [DataMember]
    public RowDetail[] Rows;
}

[DataContract]
public class RowDetail
{
    [DataMember]
    public FieldDetail[] Fields;
}

[DataContract]
public class FieldDetail
{
    [DataMember]
    public String name;
    [DataMember]
    public String value;
}

回答1:

The issues here are as follows:

  1. You have some outer class corresponding to executeSelectSP2Response (not shown in your question) that is being placed in a default namespace "http://tempuri.org/" while being serialized. You probably don't want this since it is the test default namespace for ASP.Net Web Services and you are expected to replace it with a company-specific namespace.

    For instructions in replacing it, see here or here.

  2. The DataContract attributes for the classes shown have no NameSpace property, so by default your classes are all to be serialized into the namespace "http://schemas.datacontract.org/2004/07/Clr.Namespace". This differs from the default namespace of their parent element so an override namespace must be specified. The a: prefixes refer to the xmlns:a="http://schemas.datacontract.org/2004/07/WCF_Services.DataContract" attribute and specifies that each element so tagged belongs in that namespace.

    If you want to specify that Results2Detail et. al. do not belong in a specific namespace (i.e. inherit their namespace from their parent) you can do:

    [DataContract(Namespace="")]
    public class Results2Detail
    {
        [DataMember]
        public RowDetail[] Rows;
    }
    
    [DataContract(Namespace = "")]
    public class RowDetail
    {
        [DataMember]
        public FieldDetail[] Fields;
    }
    
    [DataContract(Namespace = "")]
    public class FieldDetail
    {
        [DataMember]
        public String name;
        [DataMember]
        public String value;
    }
    

    If you want a specific namespace, you can do [DataContract(Namespace = Namespaces.CompanyNameSpace)] where Namespaces is some static class like:

    public static class Namespaces
    {
        const string CompanyNameSpace = "http://company.namespace.org"; // or whatever.
    }
    
  3. Your question #2 is unclear. Are you saying you want your arrays to appear as a single level of elements rather than two nested levels of elements, i.e.:

    <executeSelectSP2Result>
        <RowDetail>
            <FieldDetail>
            </FieldDetail>
        </RowDetail>
        <RowDetail>
            <FieldDetail>
            </FieldDetail>
        </RowDetail>
    </executeSelectSP2Result>
    

    If so, then no, this level of control is not immediately possible with DataContractSerializer. You must either implement IXmlSerializable and do it manually, or switch to XmlSerializer and decorate your arrays with the XmlElement attribute.