File: System\ServiceModel\Activities\MessageBuilder.cs
Project: ndp\cdf\src\NetFx40\System.ServiceModel.Activities\System.ServiceModel.Activities.csproj (System.ServiceModel.Activities)
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------
 
namespace System.ServiceModel.Activities
{
    using System;
    using System.Runtime;
    using System.Runtime.Serialization;
    using System.ServiceModel.Description;
    using System.Xml;
    using System.Xml.Serialization;
 
    static class MessageBuilder
    {
        static Type messageContractAttributeType;
        static XsdDataContractExporter xsdDataContractExporter;
        static XmlReflectionImporter xmlReflectionImporter;
 
        public static Type MessageContractAttributeType
        {
            get
            {
                if (messageContractAttributeType == null)
                {
                    messageContractAttributeType = typeof(MessageContractAttribute);
                }
                return messageContractAttributeType;
            }
        }
 
        public static XsdDataContractExporter XsdDataContractExporter
        {
            get
            {
                if (xsdDataContractExporter == null)
                {
                    xsdDataContractExporter = new XsdDataContractExporter();
                }
                return xsdDataContractExporter;
            }
        }
 
        public static XmlReflectionImporter XmlReflectionImporter
        {
            get
            {
                if (xmlReflectionImporter == null)
                {
                    xmlReflectionImporter = new XmlReflectionImporter();
                }
                return xmlReflectionImporter;
            }
        }
 
        public static MessageDescription CreateMessageDescription(OperationDescription operation, bool isResponse,
            MessageDirection direction, string overridingAction, Type type, SerializerOption serializerOption)
        {
            MessageDescription result;
            if (type != null && IsMessageContract(type))
            {
                result = CreateFromMessageContract(operation, isResponse, direction, overridingAction, type);
            }
            else
            {
                // For Send/Receive, we do not wrap message
                result = CreateEmptyMessageDescription(operation, isResponse, direction, overridingAction);
                AddMessagePartDescription(operation, isResponse, result, type, serializerOption);
            }
 
            return result;
        }
 
        public static MessageDescription CreateMessageDescription(OperationDescription operation, bool isResponse,
            MessageDirection direction, string overridingAction, string[] argumentNames, Type[] argumentTypes)
        {
            MessageDescription result;
            if (argumentTypes.Length == 1 && argumentTypes[0] == MessageDescription.TypeOfUntypedMessage)
            {
                result = CreateEmptyMessageDescription(operation, isResponse, direction, overridingAction);
                AddMessagePartDescription(operation, isResponse, result, argumentNames, argumentTypes);
            }
            else if (argumentTypes.Length == 1 && IsMessageContract(argumentTypes[0]))
            {
                result = CreateFromMessageContract(operation, isResponse, direction, overridingAction, argumentTypes[0]);
            }
            else
            {
                // For SendParameters/ReceiveParameters, we wrap for non-Message cases
                result = CreateEmptyMessageDescription(operation, isResponse, direction, overridingAction);
                AddMessagePartDescription(operation, isResponse, result, argumentNames, argumentTypes);
                SetWrapperName(operation, isResponse, result);
            }
 
            return result;
        }
 
        public static bool IsMessageContract(Type type)
        {
            if (type == null)
            {
                return false;
            }
            else
            {
                return type.IsDefined(MessageContractAttributeType, false);
            }
        }
 
        public static MessageDescription CreateFromMessageContract(OperationDescription operation, bool isResponse,
            MessageDirection direction, string overridingAction, Type messageContractType)
        {
            string action = overridingAction ?? NamingHelper.GetMessageAction(operation, isResponse);
 
            // 
 
            TypeLoader typeLoader = new TypeLoader();
            return typeLoader.CreateTypedMessageDescription(messageContractType, null, null,
                operation.DeclaringContract.Namespace, action, direction);
        }
 
        public static MessageDescription CreateEmptyMessageDescription(OperationDescription operation, bool isResponse,
            MessageDirection direction, string overridingAction)
        {
            string action = overridingAction ?? NamingHelper.GetMessageAction(operation, isResponse);
            MessageDescription result = new MessageDescription(action, direction);
 
            // Clear message wrapper
            result.Body.WrapperName = null;
            result.Body.WrapperNamespace = null;
 
            return result;
        }
 
        public static void AddMessagePartDescription(OperationDescription operation, bool isResponse,
            MessageDescription message, Type type, SerializerOption serializerOption)
        {
            if (type != null)
            {
                string partName;
                string partNamespace;
 
                if (serializerOption == SerializerOption.DataContractSerializer)
                {
                    XmlQualifiedName xmlQualifiedName = XsdDataContractExporter.GetRootElementName(type);
                    if (xmlQualifiedName == null)
                    {
                        xmlQualifiedName = XsdDataContractExporter.GetSchemaTypeName(type);
                    }
 
                    if (!xmlQualifiedName.IsEmpty)
                    {
                        partName = xmlQualifiedName.Name;
                        partNamespace = xmlQualifiedName.Namespace;
                    }
                    else
                    {
                        // For anonymous type, we assign CLR type name and contract namespace to MessagePartDescription
                        partName = type.Name;
                        partNamespace = operation.DeclaringContract.Namespace;
                    }
                }
                else
                {
                    XmlTypeMapping xmlTypeMapping = XmlReflectionImporter.ImportTypeMapping(type);
                    partName = xmlTypeMapping.ElementName;
                    partNamespace = xmlTypeMapping.Namespace;
                }
 
                MessagePartDescription messagePart = new MessagePartDescription(NamingHelper.XmlName(partName), partNamespace)
                {
                    Index = 0,
                    Type = type
 
                    // We do not infer MessagePartDescription.ProtectionLevel
                };
 
                message.Body.Parts.Add(messagePart);
            }
            
            if (isResponse)
            {
                SetReturnValue(message, operation);
            }
        }
 
        public static void AddMessagePartDescription(OperationDescription operation, bool isResponse,
            MessageDescription message, string[] argumentNames, Type[] argumentTypes)
        {
            Fx.Assert(argumentNames != null && argumentTypes != null, "Argument cannot be null!");
            Fx.Assert(argumentNames.Length == argumentTypes.Length, "Name and Type do not match!");
 
            // Infer MessagePartDescription.Namespace from contract namespace
            string partNamespace = operation.DeclaringContract.Namespace;
 
            for (int index = 0; index < argumentNames.Length; index++)
            {
                // Infer MessagePartDescription.Name from parameter name
                string partName = argumentNames[index];
 
                MessagePartDescription messagePart = new MessagePartDescription(NamingHelper.XmlName(partName), partNamespace)
                {
                    Index = index,
                    Type = argumentTypes[index]
 
                    // We do not infer MessagePartDescription.ProtectionLevel
                };
 
                message.Body.Parts.Add(messagePart);
            }
 
            if (isResponse)
            {
                SetReturnValue(message, operation);
            }
        }
 
        static void SetReturnValue(MessageDescription message, OperationDescription operation)
        {
            if (message.IsUntypedMessage)
            {
                message.Body.ReturnValue = message.Body.Parts[0];
                message.Body.Parts.RemoveAt(0);
            }
            else if (!message.IsTypedMessage)
            {
                message.Body.ReturnValue = new MessagePartDescription(operation.Name + TypeLoader.ReturnSuffix,
                    operation.DeclaringContract.Namespace);
                message.Body.ReturnValue.Type = TypeHelper.VoidType;
            }
        }
 
        public static void SetWrapperName(OperationDescription operation, bool isResponse, MessageDescription message)
        {
            message.Body.WrapperName = operation.Name + (isResponse ? TypeLoader.ResponseSuffix : string.Empty);
            message.Body.WrapperNamespace = operation.DeclaringContract.Namespace;
        }
 
        public static void ClearWrapperNames(OperationDescription operation)
        {
            // Reproduce logic from TypeLoader.CreateOperationDescription
            if (!operation.IsOneWay)
            {
                MessageDescription requestMessage = operation.Messages[0];
                MessageDescription responseMessage = operation.Messages[1];
                if (responseMessage.IsVoid &&
                    (requestMessage.IsUntypedMessage || requestMessage.IsTypedMessage))
                {
                    responseMessage.Body.WrapperName = null;
                    responseMessage.Body.WrapperNamespace = null;
                }
                else if (requestMessage.IsVoid &&
                    (responseMessage.IsUntypedMessage || responseMessage.IsTypedMessage))
                {
                    requestMessage.Body.WrapperName = null;
                    requestMessage.Body.WrapperNamespace = null;
                }
            }
        }
 
        public static FaultDescription CreateFaultDescription(OperationDescription operation, Type faultType, string overridingAction)
        {
            string name = NamingHelper.TypeName(faultType) + TypeLoader.FaultSuffix;
            string action = overridingAction ?? NamingHelper.GetMessageAction(operation, false) + name;
            FaultDescription result = new FaultDescription(action)
            {
                Namespace = operation.DeclaringContract.Namespace,
                DetailType = faultType
            };
            result.SetNameOnly(new XmlName(name));
            return result;
        }
    }
}