File: System\ServiceModel\Activities\ContractValidationHelper.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.Activities;
    using System.Activities.Validation;
    using System.Collections;
    using System.Collections.Generic;
    using System.Runtime;
    using System.ServiceModel.Description;
    using System.Xml;
    using System.Xml.Linq;
    using System.Xml.Serialization;
    using SR2 = System.ServiceModel.Activities.SR;
 
    static class ContractValidationHelper
    {
        public static void ValidateReceiveWithReceive(Receive receive1, Receive receive2)
        {
            Fx.Assert(receive1 != null && receive2 != null, "Validation argument cannot be null!");
            Fx.Assert(receive1.OperationName != null, "OperationName cannot be null in Receive");
            string receiveOperationName = receive1.OperationName;
 
            if (receive1.Action != receive2.Action)
            {
                throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentAction(receiveOperationName)));
            }
 
            if (receive1.InternalContent is ReceiveMessageContent && receive2.InternalContent is ReceiveMessageContent)
            {
                ReceiveMessageContent receiveMessage1 = receive1.InternalContent as ReceiveMessageContent;
                ReceiveMessageContent receiveMessage2 = receive2.InternalContent as ReceiveMessageContent;
 
                ValidateReceiveWithReceive(receiveMessage1, receiveMessage2, receiveOperationName);
            }
            else if (receive1.InternalContent is ReceiveParametersContent && receive2.InternalContent is ReceiveParametersContent)
            {
                ReceiveParametersContent receiveParameters1 = receive1.InternalContent as ReceiveParametersContent;
                ReceiveParametersContent receiveParameters2 = receive2.InternalContent as ReceiveParametersContent;
 
                ValidateReceiveParametersWithReceiveParameters(receiveParameters1, receiveParameters2, receiveOperationName);
            }
            else
            {
                throw FxTrace.Exception.AsError(new ValidationException(SR2.ReceiveAndReceiveParametersHaveSameName(receiveOperationName)));
            }
 
            if (receive1.HasReply && receive2.HasReply)
            {
                ValidateSendReplyWithSendReply(receive1.FollowingReplies[0], receive2.FollowingReplies[0]);
            }
            else if ((receive1.HasReply || receive1.HasFault) != (receive2.HasReply || receive2.HasFault))
            {
                throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentIsOneWay(receiveOperationName)));
            }
 
            if ((receive1.InternalReceive.AdditionalData.IsInsideTransactedReceiveScope != receive2.InternalReceive.AdditionalData.IsInsideTransactedReceiveScope) ||
                (receive1.InternalReceive.AdditionalData.IsFirstReceiveOfTransactedReceiveScopeTree != receive2.InternalReceive.AdditionalData.IsFirstReceiveOfTransactedReceiveScopeTree))
            {
                throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentTxProperties(receiveOperationName)));
            }
        }
 
        static void ValidateReceiveWithReceive(ReceiveMessageContent receive1, ReceiveMessageContent receive2, string receiveOperationName)
        {
            Fx.Assert(receive1 != null && receive2 != null, "Validation argument cannot be null!");
 
            if (receive1.InternalDeclaredMessageType != receive2.InternalDeclaredMessageType)
            {
                throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentValueType(receiveOperationName)));
            }
        }
 
        static void ValidateReceiveParametersWithReceiveParameters(ReceiveParametersContent receiveParameters1, ReceiveParametersContent receiveParameters2, string receiveOperationName)
        {
            Fx.Assert(receiveParameters1 != null && receiveParameters2 != null, "Validation argument cannot be null!");
 
            int count = receiveParameters1.ArgumentNames.Length;
            if (count != receiveParameters2.ArgumentNames.Length)
            {
                throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceiveParametersWithSameNameButDifferentParameterCount(receiveOperationName)));
            }
            for (int i = 0; i < count; i++)
            {
                if (receiveParameters1.ArgumentNames[i] != receiveParameters2.ArgumentNames[i])
                {
                    throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceiveParametersWithSameNameButDifferentParameterName(receiveOperationName)));
                }
                if (receiveParameters1.ArgumentTypes[i] != receiveParameters2.ArgumentTypes[i])
                {
                    throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceiveParametersWithSameNameButDifferentParameterType(receiveOperationName)));
                }
            }
        }
 
        public static void ValidateSendReplyWithSendReply(SendReply sendReply1, SendReply sendReply2)
        {
            Fx.Assert(sendReply1 != null && sendReply2 != null, "Validation argument cannot be null!");
            Fx.Assert(sendReply1.Request != null, "Request cannot be null in SendReply");
            string operationName = sendReply1.Request.OperationName;
 
            if (sendReply1.Action != sendReply2.Action)
            {
                throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendRepliesWithSameNameButDifferentAction(operationName)));
            }
 
            if (sendReply1.InternalContent is SendMessageContent && sendReply2.InternalContent is SendMessageContent)
            {
                SendMessageContent sendMessage1 = sendReply1.InternalContent as SendMessageContent;
                SendMessageContent sendMessage2 = sendReply2.InternalContent as SendMessageContent;
 
                if (sendMessage1.InternalDeclaredMessageType != sendMessage2.InternalDeclaredMessageType)
                {
                    throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendRepliesWithSameNameButDifferentValueType(operationName)));
                }
            }
            else if (sendReply1.InternalContent is SendParametersContent && sendReply2.InternalContent is SendParametersContent)
            {
                SendParametersContent sendReplyParameters1 = sendReply1.InternalContent as SendParametersContent;
                SendParametersContent sendReplyParameters2 = sendReply2.InternalContent as SendParametersContent;
 
                int count = sendReplyParameters1.ArgumentNames.Length;
                if (count != sendReplyParameters2.ArgumentNames.Length)
                {
                    throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendReplyParametersWithSameNameButDifferentParameterCount(operationName)));
                }
                for (int i = 0; i < count; i++)
                {
                    if (sendReplyParameters1.ArgumentNames[i] != sendReplyParameters2.ArgumentNames[i])
                    {
                        throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendReplyParametersWithSameNameButDifferentParameterName(operationName)));
                    }
                    if (sendReplyParameters1.ArgumentTypes[i] != sendReplyParameters2.ArgumentTypes[i])
                    {
                        throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendReplyParametersWithSameNameButDifferentParameterType(operationName)));
                    }
                }
            }
            else
            {
                throw FxTrace.Exception.AsError(new ValidationException(SR2.ReceivePairedWithSendReplyAndSendReplyParameters(operationName)));
            }
        }
        
        public static void ValidateFault(NativeActivityContext context, OperationDescription targetOperation, string overridingAction, Type faultType)
        {
            bool faultTypeExistOnContract = false;
 
            for (int index = 0; index < targetOperation.Faults.Count; index++)
            {
                FaultDescription targetFault = targetOperation.Faults[index];
 
                if (targetFault.DetailType == faultType)
                {
                    string name = NamingHelper.TypeName(faultType) + TypeLoader.FaultSuffix;
                    string action = overridingAction ?? NamingHelper.GetMessageAction(targetOperation, false) + name;
 
                    if (targetFault.Action != action)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(action, "Fault Action", targetFault.Action, targetOperation.Name, targetOperation.DeclaringContract.Name)));
                    }
                    if (targetFault.Name != NamingHelper.XmlName(name))
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(NamingHelper.XmlName(name), "Fault Name", targetFault.Name, targetOperation.Name, targetOperation.DeclaringContract.Name)));
                    }
                    if (targetFault.Namespace != targetOperation.DeclaringContract.Namespace)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(targetOperation.DeclaringContract.Namespace, "Fault Namespace", targetFault.Namespace, targetOperation.Name, targetOperation.DeclaringContract.Name)));
                    }
                    if (targetFault.HasProtectionLevel)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.ProtectionLevelNotSupported(targetOperation.Name, targetOperation.DeclaringContract.Name)));
                    }
 
                    // TypeLoader guarantees that fault types are unique in the Faults collection.
                    faultTypeExistOnContract = true;
                    break;
                }
            }
 
            // It is OK to have fewer fault types than defined on the contract.
            // But we do not allow workflow to define more fault types than specified on the contract.
            if (!faultTypeExistOnContract)
            {
                Constraint.AddValidationError(context, new ValidationError(SR2.FaultTypeMismatch(faultType.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
            }
        }
 
        public static void ValidateAction(NativeActivityContext context, MessageDescription targetMessage, string overridingAction,
            OperationDescription targetOperation, bool isResponse)
        {
            if (overridingAction == null && targetMessage.Action != NamingHelper.GetMessageAction(targetOperation, isResponse)
                || overridingAction != null && overridingAction != targetMessage.Action)
            {
                Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(overridingAction, "Action", targetMessage.Action, targetOperation.Name, targetOperation.DeclaringContract.Name)));
            }
        }
 
        public static void ValidateMessageContent(NativeActivityContext context, MessageDescription targetMessage, Type declaredMessageType,
            SerializerOption serializerOption, OperationDescription operation, bool isResponse)
        {
            // MessageContract is allowed only if the WCF contract interface specifies the same message contract type.
            if (MessageBuilder.IsMessageContract(declaredMessageType))
            {
                // if it is a typed message contract, we just validate the type of the message matches
                if (targetMessage.MessageType != null )
                {
                    if (declaredMessageType != targetMessage.MessageType)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(declaredMessageType.ToString(), "type", targetMessage.MessageType.ToString(), operation.Name, operation.DeclaringContract.Name)));
                    }
                }
                else
                {
                    Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(declaredMessageType.ToString(), "type", "null", operation.Name, operation.DeclaringContract.Name))); 
                }
                return;
            }
            else if (declaredMessageType != null && declaredMessageType.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
            {
                //This is an untyped message contract
                if (targetMessage.Body == null)
                {
                    Constraint.AddValidationError(context, new ValidationError(SR2.BodyCannotBeNull));
                }
                else
                {
                    if (isResponse)
                    {
                        if (targetMessage.Body.ReturnValue == null)
                        {
                            Constraint.AddValidationError(context, new ValidationError(SR2.ExtraReturnValue));
                        }
                        else if (!targetMessage.Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
                        {
                            Constraint.AddValidationError(context, new ValidationError(SR2.FirstParameterDoesnotMatchTheReturnValue(declaredMessageType.FullName, targetMessage.Body.ReturnValue.Type.Name, operation.Name, operation.DeclaringContract.Name)));
                        }
                    }
                    else
                    {
                        if (targetMessage.Body.Parts.Count == 0)
                        {
                            Constraint.AddValidationError(context, new ValidationError(SR2.ParameterNumberMismatch(declaredMessageType.FullName, operation.Name, operation.DeclaringContract.Name)));
                        }
                        else if (targetMessage.Body.Parts.Count > 1)
                        {
                            Constraint.AddValidationError(context, new ValidationError(SR2.MessageContentCannotHaveMoreThanOneParameter(operation.Name, operation.DeclaringContract.Name)));
                        }
                        else
                        {
                            if (!targetMessage.Body.Parts[0].Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
                            {
                                Constraint.AddValidationError(context, new ValidationError(SR2.MessageTypeMismatch(targetMessage.Body.Parts[0].Type.FullName, operation.Name, operation.DeclaringContract.Name)));
                            }
                        }
                    }
                }
 
                return;
            }
 
            // In case the WCF contract is a typed message, and the Receive activity also uses ReceiveMessageContent to infer a typed message, the contract needs to be matched
            Fx.Assert(targetMessage.Body != null, "MessageDescription.Body is never null!");
 
            // MessageDescription: Headers, Properties, ProtectionLevel
            // MessageBodyDescription: ReturnValue, WrapperName, WrapperNamespace
            // MessagePartDescription: Name, Namespace, Type, ProtectionLevel, Multiple, Index
            if (targetMessage.Headers.Count > 0)
            {
                Constraint.AddValidationError(context, new ValidationError(SR2.MessageHeaderNotSupported(operation.Name, operation.DeclaringContract.Name)));
            }
            if (targetMessage.Properties.Count > 0)
            {
                Constraint.AddValidationError(context, new ValidationError(SR2.MessagePropertyIsNotSupported(operation.Name, operation.DeclaringContract.Name)));
            }
            if (targetMessage.HasProtectionLevel)
            {
                Constraint.AddValidationError(context, new ValidationError(SR2.ProtectionLevelIsNotSupported(operation.Name, operation.DeclaringContract.Name)));
            }
            
            if (declaredMessageType == null || declaredMessageType == TypeHelper.VoidType)
            {
                if (!targetMessage.IsVoid)
                {
                    Constraint.AddValidationError(context, new ValidationError(SR2.MessageCannotBeEmpty(operation.Name, operation.DeclaringContract.Name)));
                }
            }
            else
            {
                string partName;
                string partNamespace;
 
                if (serializerOption == SerializerOption.DataContractSerializer)
                {
                    XmlQualifiedName xmlQualifiedName = MessageBuilder.XsdDataContractExporter.GetRootElementName(declaredMessageType);
                    if (xmlQualifiedName == null)
                    {
                        xmlQualifiedName = MessageBuilder.XsdDataContractExporter.GetSchemaTypeName(declaredMessageType);
                    }
 
                    if (!xmlQualifiedName.IsEmpty)
                    {
                        partName = xmlQualifiedName.Name;
                        partNamespace = xmlQualifiedName.Namespace;
                    }
                    else
                    {
                        // For anonymous type, we assign CLR type name and contract namespace to MessagePartDescription
                        partName = declaredMessageType.Name;
                        partNamespace = operation.DeclaringContract.Namespace;
                    }
                }
                else
                {
                    XmlTypeMapping xmlTypeMapping = MessageBuilder.XmlReflectionImporter.ImportTypeMapping(declaredMessageType);
                    partName = xmlTypeMapping.ElementName;
                    partNamespace = xmlTypeMapping.Namespace;
                }
 
                MessagePartDescription targetPart = null;
 
                if (isResponse && targetMessage.Body.ReturnValue != null && targetMessage.Body.ReturnValue.Type != TypeHelper.VoidType)
                {
                    if (targetMessage.Body.Parts.Count > 0)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.NotSupportMoreThanOneParametersInMessageContract(operation.Name, operation.DeclaringContract.Name)));
                    }
                    targetPart = targetMessage.Body.ReturnValue;
                }
                else if (!isResponse)
                {
                    if (targetMessage.Body.WrapperName != null && targetMessage.Body.WrapperName != String.Empty)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.WrapperNotSupportedInMessageContract(operation.Name, operation.DeclaringContract.Name)));
                    }
 
                    if (targetMessage.Body.WrapperNamespace != null && targetMessage.Body.WrapperNamespace != String.Empty)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.WrapperNotSupportedInMessageContract(operation.Name, operation.DeclaringContract.Name)));
                    }
 
                    if (targetMessage.Body.Parts.Count == 0)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.ParameterNumberMismatch(declaredMessageType.FullName, operation.Name, operation.DeclaringContract.Name)));
                    }
                    else if (targetMessage.Body.Parts.Count > 1)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.MessageContentCannotHaveMoreThanOneParameter(operation.Name, operation.DeclaringContract.Name)));
                    }
                    else
                    {
                        targetPart = targetMessage.Body.Parts[0];
                    }
                }
 
                if (targetPart != null)
                {
                    if (partName != targetPart.Name)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(partName, "parameter name", targetPart.Name, operation.Name, operation.DeclaringContract.Name)));
                    }
                    if (partNamespace != targetPart.Namespace)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(partNamespace, "parameter namespace", targetPart.Namespace, operation.Name, operation.DeclaringContract.Name)));
                    }
                    if (declaredMessageType != targetPart.Type)
                    {
                        if (declaredMessageType != null)
                        {
                            Constraint.AddValidationError(context, new ValidationError(SR2.ParameterTypeMismatch(declaredMessageType.FullName, targetPart.Type.FullName, operation.Name, operation.DeclaringContract.Name)));
                        }
                        else
                        {
                            Constraint.AddValidationError(context, new ValidationError(SR2.ParameterTypeMismatch(TypeHelper.VoidType.FullName, targetPart.Type.FullName, operation.Name, operation.DeclaringContract.Name)));
                        }
                    }
                    if (targetPart.HasProtectionLevel)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.ProtectionLevelIsNotSupported(operation.Name, operation.DeclaringContract.Name)));
                    }
 
                    // Multiple and Index do not need to be validate because there is only one part in the message.
                }
            }
        }
 
        public static void ValidateParametersContent(NativeActivityContext context, MessageDescription targetMessage, IDictionary parameters,
            OperationDescription targetOperation, bool isResponse)
        {
            // The following properties can only be set via message contract. Therefore, we do not need to validate them here.
            // MessageDescription: Headers, Properties, ProtectionLevel
            // MessagePartDescription: Namespace, ProtectionLevel, Multiple, Index
            MessageBodyDescription targetMessageBody = targetMessage.Body;
            Fx.Assert(targetMessageBody != null, "MessageDescription.Body is never null!");
 
            if (targetMessageBody.WrapperName == null)
            {
                Constraint.AddValidationError(context, new ValidationError(SR2.UnwrappedMessageNotSupported(targetOperation.Name, targetOperation.DeclaringContract.Name)));
            }
            if (targetMessageBody.WrapperNamespace == null)
            {
                Constraint.AddValidationError(context, new ValidationError(SR2.UnwrappedMessageNotSupported(targetOperation.Name, targetOperation.DeclaringContract.Name)));
            }
 
            IDictionaryEnumerator iterator = parameters.GetEnumerator();
            int benchmarkIndex = 0;
            int hitCount = 0;
 
            // Return value needs to be treated specially since ReceiveParametersContent does not have return value on the OM.
            bool targetHasReturnValue = isResponse && targetMessageBody.ReturnValue != null && targetMessageBody.ReturnValue.Type != TypeHelper.VoidType;
            if (targetHasReturnValue)
            {
                if (iterator.MoveNext() && (string)iterator.Key == targetMessageBody.ReturnValue.Name)
                {
                    Argument argument = (Argument)iterator.Value;
                    if (argument != null && argument.ArgumentType != targetMessageBody.ReturnValue.Type)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.FirstParameterDoesnotMatchTheReturnValue(argument.ArgumentType.FullName, targetMessageBody.ReturnValue.Type.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
                    }
                    hitCount++;
                }
                else if (parameters.Contains(targetMessageBody.ReturnValue.Name))
                {
                    Constraint.AddValidationError(context, new ValidationError(SR2.ParameterPositionMismatch(targetMessageBody.ReturnValue.Name, targetOperation.Name, targetOperation.DeclaringContract.Name, "0")));
                    hitCount++;
                }
                else
                {
                    Constraint.AddValidationError(context, new ValidationError(SR2.ReturnValueMissing(targetMessageBody.ReturnValue.Type.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
                }
 
                benchmarkIndex++;
            }
 
            foreach (MessagePartDescription targetPart in targetMessageBody.Parts)
            {
                if (iterator.MoveNext() && (string)iterator.Key == targetPart.Name)
                {
                    Argument argument = (Argument)iterator.Value;
                    if (argument != null && argument.ArgumentType != targetPart.Type)
                    {
                        Constraint.AddValidationError(context, new ValidationError(SR2.ParameterTypeMismatch(targetPart.Name, targetPart.Type.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
                    }
                    hitCount++;
                }
                else if (parameters.Contains(targetPart.Name))
                {
                    Constraint.AddValidationError(context, new ValidationError(SR2.ParameterPositionMismatch(targetPart.Name, targetOperation.Name, targetOperation.DeclaringContract.Name, benchmarkIndex)));
                    hitCount++;
                }
                else
                {
                    Constraint.AddValidationError(context, new ValidationError(SR2.MissingParameter(targetPart.Name, targetOperation.Name, targetOperation.DeclaringContract.Name)));
                }
 
                benchmarkIndex++;
            }
 
            if (hitCount != parameters.Count)
            {
                foreach (string name in parameters.Keys)
                {
                    XmlQualifiedName qName = new XmlQualifiedName(name, targetOperation.DeclaringContract.Namespace);
                    if (!targetMessageBody.Parts.Contains(qName))
                    {
                        if (!targetHasReturnValue || targetHasReturnValue && name != targetMessageBody.ReturnValue.Name)
                        {
                            Constraint.AddValidationError(context, new ValidationError(SR2.ExtraParameter(name, targetOperation.Name, targetOperation.DeclaringContract.Name)));
                        }
                    }
                }
            }
        }
                
        // This method trying to validate if the receive message from the operation description should be Parameter content or Message Content
        public static bool IsReceiveParameterContent(OperationDescription operation)
        {
            Fx.Assert(operation != null, "OperationDescription should not be null");
            MessageDescription message;
            bool contentIsParameter = false;
            bool noReceiveMessageContent = false;
 
            message = operation.Messages[0];
 
            // MessageType is null indicating it is not typed message contract
            if (message.MessageType == null)
            {
                if (message.Body.Parts != null)
                {
                    if (message.Body.Parts.Count != 0)
                    {
                        foreach (MessagePartDescription messagePart in message.Body.Parts)
                        {
                            if (messagePart.Index > 0)
                            {
                                contentIsParameter = true;
                                break;
                            }
                            // Indicating it is a untyped message contract
                            if (!messagePart.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
                            {
                                contentIsParameter = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        noReceiveMessageContent = true;
                    }
                }
                else
                {
                    noReceiveMessageContent = true;
                }
            }
 
            if (noReceiveMessageContent)
            {
                if ((message.Body.ReturnValue != null && message.Body.ReturnValue.Type.IsDefined(typeof(MessageContractAttribute), false))
                    || (message.Body.ReturnValue != null && message.Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message))))
                {
                    contentIsParameter = false;
                }
                else if (operation.Messages.Count > 1)
                {
                    if (operation.Messages[1].MessageType != null || operation.Messages[1].Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
                    {
                        contentIsParameter = false;
                    }
                    else
                    {
                        contentIsParameter = true;
                    }
                }
                else
                {
                    contentIsParameter = true;
                }
            }
 
            return contentIsParameter;
        }
 
        public static bool IsSendParameterContent(OperationDescription operation)
        {
            Fx.Assert(operation != null, "OperationDescription should not be null");
            if (operation.IsOneWay)
            {
                return false;
            }
 
            bool contentIsParameter = false;
            bool isSendContentEmpty = false;
            MessageDescription message;
 
            if (operation.Messages.Count > 1)
            {
                message = operation.Messages[1];
                contentIsParameter = false;
 
                if (message.MessageType == null)
                {
                    if (message.Body.ReturnValue != null && message.Body.ReturnValue.Type != typeof(void))
                    {
                        if (!message.Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
                        {
                            contentIsParameter = true;
                        }
 
                        isSendContentEmpty = true;
                    }
                }
 
                if (message.MessageType == null)
                {
                    if (message.Body.Parts != null)
                    {
                        if (message.Body.Parts.Count > 0)
                        {
                            MessagePartDescriptionCollection parts = message.Body.Parts;
                            foreach (MessagePartDescription messagePart in parts)
                            {
                                if (messagePart.Index >= 0)
                                {
                                    contentIsParameter = true;
                                    break;
                                }
                                if (!messagePart.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
                                {
                                    contentIsParameter = true;
                                }
                            }
                            isSendContentEmpty = true;
                        }
                    }
                }
 
                if (!isSendContentEmpty)
                {
                    if (message.MessageType != null && message.MessageType.IsDefined(typeof(MessageContractAttribute), false))
                    {
                        contentIsParameter = false;
                    }
                    else if (operation.Messages[0].MessageType != null)
                    {
                        contentIsParameter = false;
                    }
                    else if (operation.Messages[0].Body.Parts != null
                        && operation.Messages[0].Body.Parts.Count == 1
                        && operation.Messages[0].Body.Parts[0].Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
                    {
                        contentIsParameter = false;
                    }
                    else
                    {
                        contentIsParameter = true;
                    }
                }
            }
 
            return contentIsParameter;
        }
 
        public static string GetErrorMessageEndpointName(string endpointName)
        {
            return !string.IsNullOrEmpty(endpointName) ? endpointName : SR.NotSpecified;
        }
 
        public static string GetErrorMessageEndpointServiceContractName(XName serviceContractName)
        {
            return serviceContractName != null ? serviceContractName.LocalName : SR.NotSpecified;
        }
 
        public static string GetErrorMessageOperationName(string operationName)
        {
            return !string.IsNullOrEmpty(operationName) ? operationName : SR.NotSpecified;
        }
    }
}