C# WebAPI serialize a List of Strings

2020-08-01 11:21发布

问题:

This should be a relatively easy question I derped online for a while and still can't find a solution.

Right now my webapi returns an output like this

<Merchant>
    <Cuisine xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <d3p1:string>Japanese</d3p1:string>
        <d3p1:string>Korean</d3p1:string>
        <d3p1:string>French</d3p1:string>
    </Cuisine>
</Merchant>

I want it to return like this

<Merchant>
    <Cuisines>
        <Cuisine>Japanese</Cuisine>
        <Cuisine>Korean</Cuisine>
        <Cuisine>French</Cuisine>
    </Cuisines>
</Merchant>

What is the easiest way to accomplish such a task?

So basically there is two things I want to do

1)Get rid of the namespace xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" 2)change the name of outter element from

<Cuisine> 

to

<Cuisines> 

3)Change the name of inner element from

<d2p1:string>

to

<Cuisine>

And my datamember within the Merchant class is like this

[DataMember(EmitDefaultValue = false)]
public List<String> WebCuisine { get; set; }

Thank you in advnace

回答1:

You have to use your own serializer.

  1. Create a data structure

    [XmlRoot("Merchant")]
    public class Merchant
    {
        [XmlArray("Cuisines"), XmlArrayItem("Cuisine")]
        public List<String> WebCuisine { get; set; }
    }
    
  2. Create a class inherited from XmlObjectSerializer

    public class MerchantSerializer : XmlObjectSerializer
    {
        XmlSerializer serializer;
    
        public MerchantSerializer()
        {
            this.serializer = new XmlSerializer(typeof(Merchant));
        }
    
        public override void WriteObject(XmlDictionaryWriter writer, object graph)
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            serializer.Serialize(writer, graph, ns);
        }
    
        public override bool IsStartObject(XmlDictionaryReader reader)
        {
            throw new NotImplementedException();
        }
    
        public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
        {
            throw new NotImplementedException();
        }
    
        public override void WriteEndObject(XmlDictionaryWriter writer)
        {
            throw new NotImplementedException();
        }
    
        public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
        {
            throw new NotImplementedException();
        }
    
        public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
        {
            throw new NotImplementedException();
        }
    }
    

As you can see I am only interested to write , but not to read. However, you can easy implement ReadObject if you need.

  1. After in WebApiConfig in public static void Register(HttpConfiguration config) you add

      config.Formatters.XmlFormatter.SetSerializer<Merchant>(new MerchantSerializer());
    

And you should get

<Merchant>
   <Cuisines>
       <Cuisine>Japanese</Cuisine>
       <Cuisine>Korean</Cuisine>
       <Cuisine>French</Cuisine>
   </Cuisines>
</Merchant>


回答2:

I don't know if this will help anyone but I took the Merchant Serializer and modified it into a Generic Serializer

using System;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Serialization;

namespace NoNamespaceXml
{

  public class GenericSerializer : XmlObjectSerializer
  {        
    #region Private Variables
    private XmlSerializer serializer;
    #endregion

    #region Constructor
    /// <summary>
    /// Create a new instance of a GenericSerializer  
    /// </summary>
    /// <param name="objectToSerialize"></param>
    public GenericSerializer (object objectToSerialize)
    {
        // If the objectToSerialize object exists
        if (objectToSerialize != null)
        {
            // Create the Serializer
            this.Serializer = new XmlSerializer(objectToSerialize.GetType());
        }
    }
    #endregion

    #region Methods

        #region IsStartObject(XmlDictionaryReader reader)
        /// <summary>
        /// This method Is Start Object
        /// </summary>
        public override bool IsStartObject(XmlDictionaryReader reader)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
        /// <summary>
        /// This method Read Object
        /// </summary>
        public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region WriteEndObject(XmlDictionaryWriter writer)
        /// <summary>
        /// This method Write End Object
        /// </summary>
        public override void WriteEndObject(XmlDictionaryWriter writer)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region WriteObject(XmlDictionaryWriter writer, object graph)
        /// <summary>
        /// This method Write Object
        /// </summary>
        public override void WriteObject(XmlDictionaryWriter writer, object graph)
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            serializer.Serialize(writer, graph, ns);
        }
        #endregion

        #region WriteObjectContent(XmlDictionaryWriter writer, object graph)
        /// <summary>
        /// This method Write Object Content
        /// </summary>
        public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region WriteStartObject(XmlDictionaryWriter writer, object graph)
        /// <summary>
        /// This method Write Start Object
        /// </summary>
        public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
        {
            throw new NotImplementedException();
        }
        #endregion

    #endregion

    #region Properties

        #region HasSerializer
        /// <summary>
        /// This property returns true if this object has a 'Serializer'.
        /// </summary>
        public bool HasSerializer
        {
            get
            {
                // initial value
                bool hasSerializer = (this.Serializer != null);

                // return value
                return hasSerializer;
            }
        }
        #endregion

        #region Serializer
        /// <summary>
        //  This property gets or sets the value for 'Serializer'.
        /// </summary>
        public XmlSerializer Serializer
        {
            get { return serializer; }
            set { serializer = value; }
        }
        #endregion

    #endregion

}
#endregion

}

Then all you have to do is register any types you want to use this serializser:

// Set the Serializer for certain objects
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SetSerializer<NetworkSearchResponse>(serializer);
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SetSerializer<SynxiBooleanResponse>(serializer);