File: System\ServiceModel\Dispatcher\PrimitiveOperationFormatter.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
    using System.Collections;
    using System.ServiceModel.Channels;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    using System.Reflection;
    using System.Xml;
    using System.ServiceModel.Diagnostics;
    using System.Diagnostics;
    using System.Runtime;
 
    class PrimitiveOperationFormatter : IClientMessageFormatter, IDispatchMessageFormatter
    {
        OperationDescription operation;
        MessageDescription responseMessage;
        MessageDescription requestMessage;
        XmlDictionaryString action;
        XmlDictionaryString replyAction;
        ActionHeader actionHeaderNone;
        ActionHeader actionHeader10;
        ActionHeader actionHeaderAugust2004;
        ActionHeader replyActionHeaderNone;
        ActionHeader replyActionHeader10;
        ActionHeader replyActionHeaderAugust2004;
        XmlDictionaryString requestWrapperName;
        XmlDictionaryString requestWrapperNamespace;
        XmlDictionaryString responseWrapperName;
        XmlDictionaryString responseWrapperNamespace;
        PartInfo[] requestParts;
        PartInfo[] responseParts;
        PartInfo returnPart;
        XmlDictionaryString xsiNilLocalName;
        XmlDictionaryString xsiNilNamespace;
 
        public PrimitiveOperationFormatter(OperationDescription description, bool isRpc)
        {
            if (description == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("description");
 
            OperationFormatter.Validate(description, isRpc, false/*isEncoded*/);
 
            this.operation = description;
#pragma warning suppress 56506 // Microsoft, OperationDescription.Messages never be null
            this.requestMessage = description.Messages[0];
            if (description.Messages.Count == 2)
                this.responseMessage = description.Messages[1];
 
            int stringCount = 3 + requestMessage.Body.Parts.Count;
            if (responseMessage != null)
                stringCount += 2 + responseMessage.Body.Parts.Count;
 
            XmlDictionary dictionary = new XmlDictionary(stringCount * 2);
 
            xsiNilLocalName = dictionary.Add("nil");
            xsiNilNamespace = dictionary.Add(System.Xml.Schema.XmlSchema.InstanceNamespace);
 
            OperationFormatter.GetActions(description, dictionary, out this.action, out this.replyAction);
 
            if (requestMessage.Body.WrapperName != null)
            {
                requestWrapperName = AddToDictionary(dictionary, requestMessage.Body.WrapperName);
                requestWrapperNamespace = AddToDictionary(dictionary, requestMessage.Body.WrapperNamespace);
            }
 
            requestParts = AddToDictionary(dictionary, requestMessage.Body.Parts, isRpc);
 
            if (responseMessage != null)
            {
                if (responseMessage.Body.WrapperName != null)
                {
                    responseWrapperName = AddToDictionary(dictionary, responseMessage.Body.WrapperName);
                    responseWrapperNamespace = AddToDictionary(dictionary, responseMessage.Body.WrapperNamespace);
                }
 
                responseParts = AddToDictionary(dictionary, responseMessage.Body.Parts, isRpc);
 
                if (responseMessage.Body.ReturnValue != null && responseMessage.Body.ReturnValue.Type != typeof(void))
                {
                    returnPart = AddToDictionary(dictionary, responseMessage.Body.ReturnValue, isRpc);
                }
            }
        }
 
        ActionHeader ActionHeaderNone
        {
            get
            {
                if (actionHeaderNone == null)
                {
                    actionHeaderNone =
                        ActionHeader.Create(this.action, AddressingVersion.None);
                }
 
                return actionHeaderNone;
            }
        }
 
        ActionHeader ActionHeader10
        {
            get
            {
                if (actionHeader10 == null)
                {
                    actionHeader10 =
                        ActionHeader.Create(this.action, AddressingVersion.WSAddressing10);
                }
 
                return actionHeader10;
            }
        }
 
        ActionHeader ActionHeaderAugust2004
        {
            get
            {
                if (actionHeaderAugust2004 == null)
                {
                    actionHeaderAugust2004 =
                        ActionHeader.Create(this.action, AddressingVersion.WSAddressingAugust2004);
                }
 
                return actionHeaderAugust2004;
            }
        }
 
        ActionHeader ReplyActionHeaderNone
        {
            get
            {
                if (replyActionHeaderNone == null)
                {
                    replyActionHeaderNone =
                        ActionHeader.Create(this.replyAction, AddressingVersion.None);
                }
 
                return replyActionHeaderNone;
            }
        }
 
        ActionHeader ReplyActionHeader10
        {
            get
            {
                if (replyActionHeader10 == null)
                {
                    replyActionHeader10 =
                        ActionHeader.Create(this.replyAction, AddressingVersion.WSAddressing10);
                }
 
                return replyActionHeader10;
            }
        }
 
        ActionHeader ReplyActionHeaderAugust2004
        {
            get
            {
                if (replyActionHeaderAugust2004 == null)
                {
                    replyActionHeaderAugust2004 =
                        ActionHeader.Create(this.replyAction, AddressingVersion.WSAddressingAugust2004);
                }
 
                return replyActionHeaderAugust2004;
            }
        }
 
        static XmlDictionaryString AddToDictionary(XmlDictionary dictionary, string s)
        {
            XmlDictionaryString dictionaryString;
            if (!dictionary.TryLookup(s, out dictionaryString))
            {
                dictionaryString = dictionary.Add(s);
            }
            return dictionaryString;
        }
 
        static PartInfo[] AddToDictionary(XmlDictionary dictionary, MessagePartDescriptionCollection parts, bool isRpc)
        {
            PartInfo[] partInfos = new PartInfo[parts.Count];
            for (int i = 0; i < parts.Count; i++)
            {
                partInfos[i] = AddToDictionary(dictionary, parts[i], isRpc);
            }
            return partInfos;
        }
 
        ActionHeader GetActionHeader(AddressingVersion addressing)
        {
            if (this.action == null)
            {
                return null;
            }
 
            if (addressing == AddressingVersion.WSAddressingAugust2004)
            {
                return ActionHeaderAugust2004;
            }
            else if (addressing == AddressingVersion.WSAddressing10)
            {
                return ActionHeader10;
            }
            else if (addressing == AddressingVersion.None)
            {
                return ActionHeaderNone;
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new InvalidOperationException(SR.GetString(SR.AddressingVersionNotSupported, addressing)));
            }
        }
 
        ActionHeader GetReplyActionHeader(AddressingVersion addressing)
        {
            if (this.replyAction == null)
            {
                return null;
            }
 
            if (addressing == AddressingVersion.WSAddressingAugust2004)
            {
                return ReplyActionHeaderAugust2004;
            }
            else if (addressing == AddressingVersion.WSAddressing10)
            {
                return ReplyActionHeader10;
            }
            else if (addressing == AddressingVersion.None)
            {
                return ReplyActionHeaderNone;
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new InvalidOperationException(SR.GetString(SR.AddressingVersionNotSupported, addressing)));
            }
        }
 
        static string GetArrayItemName(Type type)
        {
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Boolean:
                    return "boolean";
                case TypeCode.DateTime:
                    return "dateTime";
                case TypeCode.Decimal:
                    return "decimal";
                case TypeCode.Int32:
                    return "int";
                case TypeCode.Int64:
                    return "long";
                case TypeCode.Single:
                    return "float";
                case TypeCode.Double:
                    return "double";
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidUseOfPrimitiveOperationFormatter)));
            }
        }
 
        static PartInfo AddToDictionary(XmlDictionary dictionary, MessagePartDescription part, bool isRpc)
        {
            Type type = part.Type;
            XmlDictionaryString itemName = null;
            XmlDictionaryString itemNamespace = null;
            if (type.IsArray && type != typeof(byte[]))
            {
                const string ns = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
                string name = GetArrayItemName(type.GetElementType());
                itemName = AddToDictionary(dictionary, name);
                itemNamespace = AddToDictionary(dictionary, ns);
            }
            return new PartInfo(part,
                AddToDictionary(dictionary, part.Name),
                AddToDictionary(dictionary, isRpc ? string.Empty : part.Namespace),
                itemName, itemNamespace);
        }
 
        public static bool IsContractSupported(OperationDescription description)
        {
            if (description == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("description");
 
            OperationDescription operation = description;
#pragma warning suppress 56506 // Microsoft, OperationDescription.Messages never be null
            MessageDescription requestMessage = description.Messages[0];
            MessageDescription responseMessage = null;
            if (description.Messages.Count == 2)
                responseMessage = description.Messages[1];
 
            if (requestMessage.Headers.Count > 0)
                return false;
            if (requestMessage.Properties.Count > 0)
                return false;
            if (requestMessage.IsTypedMessage)
                return false;
            if (responseMessage != null)
            {
                if (responseMessage.Headers.Count > 0)
                    return false;
                if (responseMessage.Properties.Count > 0)
                    return false;
                if (responseMessage.IsTypedMessage)
                    return false;
            }
            if (!AreTypesSupported(requestMessage.Body.Parts))
                return false;
            if (responseMessage != null)
            {
                if (!AreTypesSupported(responseMessage.Body.Parts))
                    return false;
                if (responseMessage.Body.ReturnValue != null && !IsTypeSupported(responseMessage.Body.ReturnValue))
                    return false;
            }
            return true;
        }
 
        static bool AreTypesSupported(MessagePartDescriptionCollection bodyDescriptions)
        {
            for (int i = 0; i < bodyDescriptions.Count; i++)
                if (!IsTypeSupported(bodyDescriptions[i]))
                    return false;
            return true;
        }
 
        static bool IsTypeSupported(MessagePartDescription bodyDescription)
        {
            Fx.Assert(bodyDescription != null, "");
            Type type = bodyDescription.Type;
            if (type == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxMessagePartDescriptionMissingType, bodyDescription.Name, bodyDescription.Namespace)));
 
            if (bodyDescription.Multiple)
                return false;
 
            if (type == typeof(void))
                return true;
            if (type.IsEnum)
                return false;
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Boolean:
                case TypeCode.DateTime:
                case TypeCode.Decimal:
                case TypeCode.Double:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.Single:
                case TypeCode.String:
                    return true;
                case TypeCode.Object:
                    if (type.IsArray && type.GetArrayRank() == 1 && IsArrayTypeSupported(type.GetElementType()))
                        return true;
                    break;
                default:
                    break;
            }
            return false;
        }
 
        static bool IsArrayTypeSupported(Type type)
        {
            if (type.IsEnum)
                return false;
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Byte:
                case TypeCode.Boolean:
                case TypeCode.DateTime:
                case TypeCode.Decimal:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.Single:
                case TypeCode.Double:
                    return true;
                default:
                    return false;
            }
        }
 
        public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
        {
            if (messageVersion == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("messageVersion");
 
            if (parameters == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameters");
 
            return Message.CreateMessage(messageVersion, GetActionHeader(messageVersion.Addressing), new PrimitiveRequestBodyWriter(parameters, this));
        }
 
        public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
        {
            if (messageVersion == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("messageVersion");
 
            if (parameters == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameters");
 
            return Message.CreateMessage(messageVersion, GetReplyActionHeader(messageVersion.Addressing), new PrimitiveResponseBodyWriter(parameters, result, this));
        }
 
        public object DeserializeReply(Message message, object[] parameters)
        {
            if (message == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
            if (parameters == null)
                throw TraceUtility.ThrowHelperError(new ArgumentNullException("parameters"), message);
            try
            {
                if (message.IsEmpty)
                {
                    if (responseWrapperName == null)
                        return null;
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.SFxInvalidMessageBodyEmptyMessage)));
                }
 
                XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
                using (bodyReader)
                {
                    object returnValue = DeserializeResponse(bodyReader, parameters);
                    message.ReadFromBodyContentsToEnd(bodyReader);
                    return returnValue;
                }
            }
            catch (XmlException xe)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
                    SR.GetString(SR.SFxErrorDeserializingReplyBodyMore, operation.Name, xe.Message), xe));
            }
            catch (FormatException fe)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
                    SR.GetString(SR.SFxErrorDeserializingReplyBodyMore, operation.Name, fe.Message), fe));
            }
            catch (SerializationException se)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
                    SR.GetString(SR.SFxErrorDeserializingReplyBodyMore, operation.Name, se.Message), se));
            }
        }
 
        public void DeserializeRequest(Message message, object[] parameters)
        {
            if (message == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
            if (parameters == null)
                throw TraceUtility.ThrowHelperError(new ArgumentNullException("parameters"), message);
            try
            {
                if (message.IsEmpty)
                {
                    if (requestWrapperName == null)
                        return;
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.SFxInvalidMessageBodyEmptyMessage)));
                }
 
                XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
                using (bodyReader)
                {
                    DeserializeRequest(bodyReader, parameters);
                    message.ReadFromBodyContentsToEnd(bodyReader);
                }
            }
            catch (XmlException xe)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    OperationFormatter.CreateDeserializationFailedFault(
                        SR.GetString(SR.SFxErrorDeserializingRequestBodyMore, operation.Name, xe.Message), 
                        xe));
            }
            catch (FormatException fe)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    OperationFormatter.CreateDeserializationFailedFault(
                        SR.GetString(SR.SFxErrorDeserializingRequestBodyMore, operation.Name, fe.Message), 
                        fe));
            }
            catch (SerializationException se)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
                    SR.GetString(SR.SFxErrorDeserializingRequestBodyMore, operation.Name, se.Message), 
                    se));
            }
        }
 
        void DeserializeRequest(XmlDictionaryReader reader, object[] parameters)
        {
            if (requestWrapperName != null)
            {
                if (!reader.IsStartElement(requestWrapperName, requestWrapperNamespace))
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.SFxInvalidMessageBody, requestWrapperName, requestWrapperNamespace, reader.NodeType, reader.Name, reader.NamespaceURI)));
                bool isEmptyElement = reader.IsEmptyElement;
                reader.Read();
                if (isEmptyElement)
                {
                    return;
                }
            }
 
            DeserializeParameters(reader, requestParts, parameters);
 
            if (requestWrapperName != null)
            {
                reader.ReadEndElement();
            }
        }
 
        object DeserializeResponse(XmlDictionaryReader reader, object[] parameters)
        {
            if (responseWrapperName != null)
            {
                if (!reader.IsStartElement(responseWrapperName, responseWrapperNamespace))
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.SFxInvalidMessageBody, responseWrapperName, responseWrapperNamespace, reader.NodeType, reader.Name, reader.NamespaceURI)));
                bool isEmptyElement = reader.IsEmptyElement;
                reader.Read();
                if (isEmptyElement)
                {
                    return null;
                }
            }
 
            object returnValue = null;
            if (returnPart != null)
            {
                while (true)
                {
                    if (IsPartElement(reader, returnPart))
                    {
                        returnValue = DeserializeParameter(reader, returnPart);
                        break;
                    }
                    if (!reader.IsStartElement())
                        break;
                    if (IsPartElements(reader, responseParts))
                        break;
                    OperationFormatter.TraceAndSkipElement(reader);
                }
            }
            DeserializeParameters(reader, responseParts, parameters);
 
            if (responseWrapperName != null)
            {
                reader.ReadEndElement();
            }
 
            return returnValue;
        }
 
 
        void DeserializeParameters(XmlDictionaryReader reader, PartInfo[] parts, object[] parameters)
        {
            if (parts.Length != parameters.Length)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentException(SR.GetString(SR.SFxParameterCountMismatch, "parts", parts.Length, "parameters", parameters.Length), "parameters"));
 
            int nextPartIndex = 0;
            while (reader.IsStartElement())
            {
                for (int i = nextPartIndex; i < parts.Length; i++)
                {
                    PartInfo part = parts[i];
                    if (IsPartElement(reader, part))
                    {
                        parameters[part.Description.Index] = DeserializeParameter(reader, parts[i]);
                        nextPartIndex = i + 1;
                    }
                    else
                        parameters[part.Description.Index] = null;
                }
 
                if (reader.IsStartElement())
                    OperationFormatter.TraceAndSkipElement(reader);
            }
        }
 
        private bool IsPartElements(XmlDictionaryReader reader, PartInfo[] parts)
        {
            foreach (PartInfo part in parts)
                if (IsPartElement(reader, part))
                    return true;
            return false;
        }
 
        bool IsPartElement(XmlDictionaryReader reader, PartInfo part)
        {
            return reader.IsStartElement(part.DictionaryName, part.DictionaryNamespace);
        }
 
        object DeserializeParameter(XmlDictionaryReader reader, PartInfo part)
        {
            if (reader.AttributeCount > 0 &&
                reader.MoveToAttribute(xsiNilLocalName.Value, xsiNilNamespace.Value) &&
                reader.ReadContentAsBoolean())
            {
                reader.Skip();
                return null;
            }
            return part.ReadValue(reader);
        }
 
        void SerializeParameter(XmlDictionaryWriter writer, PartInfo part, object graph)
        {
 
            writer.WriteStartElement(part.DictionaryName, part.DictionaryNamespace);
            if (graph == null)
            {
                writer.WriteStartAttribute(xsiNilLocalName, xsiNilNamespace);
                writer.WriteValue(true);
                writer.WriteEndAttribute();
            }
            else
                part.WriteValue(writer, graph);
            writer.WriteEndElement();
        }
 
        void SerializeParameters(XmlDictionaryWriter writer, PartInfo[] parts, object[] parameters)
        {
            if (parts.Length != parameters.Length)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentException(SR.GetString(SR.SFxParameterCountMismatch, "parts", parts.Length, "parameters", parameters.Length), "parameters"));
 
 
            for (int i = 0; i < parts.Length; i++)
            {
                PartInfo part = parts[i];
                SerializeParameter(writer, part, parameters[part.Description.Index]);
            }
        }
 
        void SerializeRequest(XmlDictionaryWriter writer, object[] parameters)
        {
            if (requestWrapperName != null)
                writer.WriteStartElement(requestWrapperName, requestWrapperNamespace);
 
            SerializeParameters(writer, requestParts, parameters);
 
            if (requestWrapperName != null)
                writer.WriteEndElement();
        }
 
        void SerializeResponse(XmlDictionaryWriter writer, object returnValue, object[] parameters)
        {
            if (responseWrapperName != null)
                writer.WriteStartElement(responseWrapperName, responseWrapperNamespace);
 
            if (returnPart != null)
                SerializeParameter(writer, returnPart, returnValue);
 
            SerializeParameters(writer, responseParts, parameters);
 
            if (responseWrapperName != null)
                writer.WriteEndElement();
        }
 
        class PartInfo
        {
            XmlDictionaryString dictionaryName;
            XmlDictionaryString dictionaryNamespace;
            XmlDictionaryString itemName;
            XmlDictionaryString itemNamespace;
            MessagePartDescription description;
            TypeCode typeCode;
            bool isArray;
 
            public PartInfo(MessagePartDescription description, XmlDictionaryString dictionaryName, XmlDictionaryString dictionaryNamespace, XmlDictionaryString itemName, XmlDictionaryString itemNamespace)
            {
                this.dictionaryName = dictionaryName;
                this.dictionaryNamespace = dictionaryNamespace;
                this.itemName = itemName;
                this.itemNamespace = itemNamespace;
                this.description = description;
                if (description.Type.IsArray)
                {
                    this.isArray = true;
                    this.typeCode = Type.GetTypeCode(description.Type.GetElementType());
                }
                else
                {
                    this.isArray = false;
                    this.typeCode = Type.GetTypeCode(description.Type);
                }
            }
 
            public MessagePartDescription Description
            {
                get { return description; }
            }
 
            public XmlDictionaryString DictionaryName
            {
                get { return dictionaryName; }
            }
 
            public XmlDictionaryString DictionaryNamespace
            {
                get { return dictionaryNamespace; }
            }
 
            public object ReadValue(XmlDictionaryReader reader)
            {
                object value;
                if (isArray)
                {
                    switch (typeCode)
                    {
                        case TypeCode.Byte:
                            value = reader.ReadElementContentAsBase64();
                            break;
                        case TypeCode.Boolean:
                            if (!reader.IsEmptyElement)
                            {
                                reader.ReadStartElement();
                                value = reader.ReadBooleanArray(itemName, itemNamespace);
                                reader.ReadEndElement();
                            }
                            else
                            {
                                reader.Read();
                                value = new bool[0];
                            }
                            break;
                        case TypeCode.DateTime:
                            if (!reader.IsEmptyElement)
                            {
                                reader.ReadStartElement();
                                value = reader.ReadDateTimeArray(itemName, itemNamespace);
                                reader.ReadEndElement();
                            }
                            else
                            {
                                reader.Read();
                                value = new DateTime[0];
                            }
                            break;
                        case TypeCode.Decimal:
                            if (!reader.IsEmptyElement)
                            {
                                reader.ReadStartElement();
                                value = reader.ReadDecimalArray(itemName, itemNamespace);
                                reader.ReadEndElement();
                            }
                            else
                            {
                                reader.Read();
                                value = new Decimal[0];
                            }
                            break;
                        case TypeCode.Int32:
                            if (!reader.IsEmptyElement)
                            {
                                reader.ReadStartElement();
                                value = reader.ReadInt32Array(itemName, itemNamespace);
                                reader.ReadEndElement();
                            }
                            else
                            {
                                reader.Read();
                                value = new Int32[0];
                            }
                            break;
                        case TypeCode.Int64:
                            if (!reader.IsEmptyElement)
                            {
                                reader.ReadStartElement();
                                value = reader.ReadInt64Array(itemName, itemNamespace);
                                reader.ReadEndElement();
                            }
                            else
                            {
                                reader.Read();
                                value = new Int64[0];
                            }
                            break;
                        case TypeCode.Single:
                            if (!reader.IsEmptyElement)
                            {
                                reader.ReadStartElement();
                                value = reader.ReadSingleArray(itemName, itemNamespace);
                                reader.ReadEndElement();
                            }
                            else
                            {
                                reader.Read();
                                value = new Single[0];
                            }
                            break;
                        case TypeCode.Double:
                            if (!reader.IsEmptyElement)
                            {
                                reader.ReadStartElement();
                                value = reader.ReadDoubleArray(itemName, itemNamespace);
                                reader.ReadEndElement();
                            }
                            else
                            {
                                reader.Read();
                                value = new Double[0];
                            }
                            break;
                        default:
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidUseOfPrimitiveOperationFormatter)));
                    }
                }
                else
                {
                    switch (typeCode)
                    {
                        case TypeCode.Boolean:
                            value = reader.ReadElementContentAsBoolean();
                            break;
                        case TypeCode.DateTime:
                            value = reader.ReadElementContentAsDateTime();
                            break;
                        case TypeCode.Decimal:
                            value = reader.ReadElementContentAsDecimal();
                            break;
                        case TypeCode.Double:
                            value = reader.ReadElementContentAsDouble();
                            break;
                        case TypeCode.Int32:
                            value = reader.ReadElementContentAsInt();
                            break;
                        case TypeCode.Int64:
                            value = reader.ReadElementContentAsLong();
                            break;
                        case TypeCode.Single:
                            value = reader.ReadElementContentAsFloat();
                            break;
                        case TypeCode.String:
                            return reader.ReadElementContentAsString();
                        default:
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidUseOfPrimitiveOperationFormatter)));
                    }
                }
                return value;
            }
 
            public void WriteValue(XmlDictionaryWriter writer, object value)
            {
                if (isArray)
                {
                    switch (typeCode)
                    {
                        case TypeCode.Byte:
                            {
                                byte[] arrayValue = (byte[])value;
                                writer.WriteBase64(arrayValue, 0, arrayValue.Length);
                            }
                            break;
                        case TypeCode.Boolean:
                            {
                                bool[] arrayValue = (bool[])value;
                                writer.WriteArray(null, itemName, itemNamespace, arrayValue, 0, arrayValue.Length);
                            }
                            break;
                        case TypeCode.DateTime:
                            {
                                DateTime[] arrayValue = (DateTime[])value;
                                writer.WriteArray(null, itemName, itemNamespace, arrayValue, 0, arrayValue.Length);
                            }
                            break;
                        case TypeCode.Decimal:
                            {
                                decimal[] arrayValue = (decimal[])value;
                                writer.WriteArray(null, itemName, itemNamespace, arrayValue, 0, arrayValue.Length);
                            }
                            break;
                        case TypeCode.Int32:
                            {
                                Int32[] arrayValue = (Int32[])value;
                                writer.WriteArray(null, itemName, itemNamespace, arrayValue, 0, arrayValue.Length);
                            }
                            break;
                        case TypeCode.Int64:
                            {
                                Int64[] arrayValue = (Int64[])value;
                                writer.WriteArray(null, itemName, itemNamespace, arrayValue, 0, arrayValue.Length);
                            }
                            break;
                        case TypeCode.Single:
                            {
                                float[] arrayValue = (float[])value;
                                writer.WriteArray(null, itemName, itemNamespace, arrayValue, 0, arrayValue.Length);
                            }
                            break;
                        case TypeCode.Double:
                            {
                                double[] arrayValue = (double[])value;
                                writer.WriteArray(null, itemName, itemNamespace, arrayValue, 0, arrayValue.Length);
                            }
                            break;
                        default:
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidUseOfPrimitiveOperationFormatter)));
                    }
                }
                else
                {
                    switch (typeCode)
                    {
                        case TypeCode.Boolean:
                            writer.WriteValue((bool)value);
                            break;
                        case TypeCode.DateTime:
                            writer.WriteValue((DateTime)value);
                            break;
                        case TypeCode.Decimal:
                            writer.WriteValue((Decimal)value);
                            break;
                        case TypeCode.Double:
                            writer.WriteValue((double)value);
                            break;
                        case TypeCode.Int32:
                            writer.WriteValue((int)value);
                            break;
                        case TypeCode.Int64:
                            writer.WriteValue((long)value);
                            break;
                        case TypeCode.Single:
                            writer.WriteValue((float)value);
                            break;
                        case TypeCode.String:
                            writer.WriteString((string)value);
                            break;
                        default:
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidUseOfPrimitiveOperationFormatter)));
                    }
                }
            }
        }
 
        class PrimitiveRequestBodyWriter : BodyWriter
        {
            object[] parameters;
            PrimitiveOperationFormatter primitiveOperationFormatter;
 
            public PrimitiveRequestBodyWriter(object[] parameters, PrimitiveOperationFormatter primitiveOperationFormatter)
                : base(true)
            {
                this.parameters = parameters;
                this.primitiveOperationFormatter = primitiveOperationFormatter;
            }
 
            protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
            {
                primitiveOperationFormatter.SerializeRequest(writer, parameters);
            }
        }
 
        class PrimitiveResponseBodyWriter : BodyWriter
        {
            object[] parameters;
            object returnValue;
            PrimitiveOperationFormatter primitiveOperationFormatter;
 
            public PrimitiveResponseBodyWriter(object[] parameters, object returnValue,
                PrimitiveOperationFormatter primitiveOperationFormatter)
                : base(true)
            {
                this.parameters = parameters;
                this.returnValue = returnValue;
                this.primitiveOperationFormatter = primitiveOperationFormatter;
            }
 
            protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
            {
                primitiveOperationFormatter.SerializeResponse(writer, returnValue, parameters);
            }
        }
    }
}