File: System\ServiceModel\Description\WebHttpBehavior.cs
Project: ndp\cdf\src\NetFx35\System.ServiceModel.Web\System.ServiceModel.Web.csproj (System.ServiceModel.Web)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Description
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.IO;
    using System.Linq;
    using System.ServiceModel;
    using System.ServiceModel.Administration;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel.Web;
 
    public class WebHttpBehavior : IEndpointBehavior, IWmiInstanceProvider
    {
        internal const string GET = "GET";
        internal const string POST = "POST";
        internal const string WildcardAction = "*";
        internal const string WildcardMethod = "*";
        internal static readonly string defaultStreamContentType = "application/octet-stream";
        internal static readonly string defaultCallbackParameterName = "callback";
        const string AddressPropertyName = "Address";
        WebMessageBodyStyle defaultBodyStyle;
        WebMessageFormat defaultOutgoingReplyFormat;
        WebMessageFormat defaultOutgoingRequestFormat;
        XmlSerializerOperationBehavior.Reflector reflector;
        UnwrappedTypesXmlSerializerManager xmlSerializerManager;
 
        public WebHttpBehavior()
        {
            defaultOutgoingRequestFormat = WebMessageFormat.Xml;
            defaultOutgoingReplyFormat = WebMessageFormat.Xml;
            this.defaultBodyStyle = WebMessageBodyStyle.Bare;
            xmlSerializerManager = new UnwrappedTypesXmlSerializerManager();
        }
 
        internal delegate void Effect();
 
        public virtual WebMessageBodyStyle DefaultBodyStyle
        {
            get { return this.defaultBodyStyle; }
            set
            {
                if (!WebMessageBodyStyleHelper.IsDefined(value))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
                this.defaultBodyStyle = value;
            }
        }
 
        public virtual WebMessageFormat DefaultOutgoingRequestFormat
        {
            get
            {
                return this.defaultOutgoingRequestFormat;
            }
            set
            {
                if (!WebMessageFormatHelper.IsDefined(value))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
                this.defaultOutgoingRequestFormat = value;
            }
        }
 
        public virtual WebMessageFormat DefaultOutgoingResponseFormat
        {
            get
            {
                return this.defaultOutgoingReplyFormat;
            }
            set
            {
                if (!WebMessageFormatHelper.IsDefined(value))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
                this.defaultOutgoingReplyFormat = value;
            }
        }
 
        public virtual bool HelpEnabled { get; set; }
 
        public virtual bool AutomaticFormatSelectionEnabled { get; set; }
 
        public virtual bool FaultExceptionEnabled { get; set; }
 
        internal Uri HelpUri { get; set; }
 
        protected internal string JavascriptCallbackParameterName { get; set; }
 
        public virtual void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
            // do nothing
        }
 
        public virtual void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            if (endpoint == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
            }
            if (clientRuntime == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("clientRuntime");
            }
            WebMessageEncodingBindingElement webEncodingBindingElement = endpoint.Binding.CreateBindingElements().Find<WebMessageEncodingBindingElement>();
            if (webEncodingBindingElement != null && webEncodingBindingElement.CrossDomainScriptAccessEnabled)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.CrossDomainJavascriptNotsupported));
            }
#pragma warning disable 56506 // Microsoft, endpoint.Contract is never null
            this.reflector = new XmlSerializerOperationBehavior.Reflector(endpoint.Contract.Namespace, null);
            foreach (OperationDescription od in endpoint.Contract.Operations)
#pragma warning restore 56506
            {
#pragma warning disable 56506 // Microsoft, clientRuntime.Operations is never null
                if (clientRuntime.Operations.Contains(od.Name))
#pragma warning restore 56506
                {
                    ClientOperation cop = clientRuntime.Operations[od.Name];
                    IClientMessageFormatter requestClient = GetRequestClientFormatter(od, endpoint);
                    IClientMessageFormatter replyClient = GetReplyClientFormatter(od, endpoint);
                    cop.Formatter = new CompositeClientFormatter(requestClient, replyClient);
                    cop.SerializeRequest = true;
                    cop.DeserializeReply = od.Messages.Count > 1 && !IsUntypedMessage(od.Messages[1]);
                }
            }
            AddClientErrorInspector(endpoint, clientRuntime);
        }
 
        public virtual void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            if (endpoint == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
            }
            if (endpointDispatcher == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointDispatcher");
            }
            WebMessageEncodingBindingElement webEncodingBindingElement = endpoint.Binding.CreateBindingElements().Find<WebMessageEncodingBindingElement>();
            if (webEncodingBindingElement != null && webEncodingBindingElement.CrossDomainScriptAccessEnabled)
            {
                ISecurityCapabilities securityCapabilities = endpoint.Binding.GetProperty<ISecurityCapabilities>(new BindingParameterCollection());
                if (securityCapabilities.SupportsClientAuthentication)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.CrossDomainJavascriptAuthNotSupported));
                }
                if (endpoint.Contract.Behaviors.Contains(typeof(JavascriptCallbackBehaviorAttribute)))
                {
                    JavascriptCallbackBehaviorAttribute behavior = endpoint.Contract.Behaviors[typeof(JavascriptCallbackBehaviorAttribute)] as JavascriptCallbackBehaviorAttribute;
                    this.JavascriptCallbackParameterName = behavior.UrlParameterName;
                }
                else
                {
                    this.JavascriptCallbackParameterName = defaultCallbackParameterName;
                }
                endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new JavascriptCallbackMessageInspector(this.JavascriptCallbackParameterName));
            }
            if (this.HelpEnabled)
            {
                this.HelpUri = new UriTemplate(HelpPage.OperationListHelpPageUriTemplate).BindByPosition(endpoint.ListenUri);
            }
#pragma warning disable 56506 // Microsoft, endpoint.Contract is never null
            this.reflector = new XmlSerializerOperationBehavior.Reflector(endpoint.Contract.Namespace, null);
#pragma warning restore 56506
 
            // endpoint filter
            endpointDispatcher.AddressFilter = new PrefixEndpointAddressMessageFilter(endpoint.Address);
            endpointDispatcher.ContractFilter = new MatchAllMessageFilter();
            // operation selector
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime is never null
            endpointDispatcher.DispatchRuntime.OperationSelector = this.GetOperationSelector(endpoint);
#pragma warning restore 56506
            // unhandled operation
            string actionStarOperationName = null;
#pragma warning disable 56506 // Microsoft, endpoint.Contract is never null
            foreach (OperationDescription od in endpoint.Contract.Operations)
#pragma warning restore 56506
            {
                if (od.Messages[0].Direction == MessageDirection.Input
                    && od.Messages[0].Action == WildcardAction)
                {
                    actionStarOperationName = od.Name;
                    break;
                }
            }
            if (actionStarOperationName != null)
            {
                // WCF v1 installs any Action="*" op into UnhandledDispatchOperation, but WebHttpBehavior
                // doesn't want this, so we 'move' that operation back into normal set of operations
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime.{Operations,UnhandledDispatchOperation} is never null
                endpointDispatcher.DispatchRuntime.Operations.Add(
                    endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation);
#pragma warning restore 56506
            }
 
            FormatSelectingMessageInspector formatSelectingMessageInspector = null;
            string xmlContentType = null;
            string jsonContentType = null;
 
 
            if (webEncodingBindingElement != null)
            {
                XmlFormatMapping xmlFormatMapping = new XmlFormatMapping(webEncodingBindingElement.WriteEncoding, webEncodingBindingElement.ContentTypeMapper);
                JsonFormatMapping jsonFormatMapping = new JsonFormatMapping(webEncodingBindingElement.WriteEncoding, webEncodingBindingElement.ContentTypeMapper);
 
                xmlContentType = xmlFormatMapping.DefaultContentType.ToString();
                jsonContentType = jsonFormatMapping.DefaultContentType.ToString();
 
                if (AutomaticFormatSelectionEnabled)
                {
                    formatSelectingMessageInspector = new FormatSelectingMessageInspector(this, new List<MultiplexingFormatMapping> { xmlFormatMapping, jsonFormatMapping });
                    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(formatSelectingMessageInspector);
                }
            }
            else
            {
                xmlContentType = TextMessageEncoderFactory.GetContentType(XmlFormatMapping.defaultMediaType, TextEncoderDefaults.Encoding);
                jsonContentType = JsonMessageEncoderFactory.GetContentType(null);
            }
 
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation is never null
            // always install UnhandledDispatchOperation (WebHttpDispatchOperationSelector may choose not to use it)
            endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation = new DispatchOperation(endpointDispatcher.DispatchRuntime, "*", WildcardAction, WildcardAction);
            endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation.DeserializeRequest = false;
            endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation.SerializeReply = false;
            endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation.Invoker = new HttpUnhandledOperationInvoker { HelpUri = this.HelpUri };
#pragma warning restore 56506
            // install formatters and parameter inspectors
            foreach (OperationDescription od in endpoint.Contract.Operations)
            {
                DispatchOperation dop = null;
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime, DispatchRuntime.Operations are never null
                if (endpointDispatcher.DispatchRuntime.Operations.Contains(od.Name))
#pragma warning restore 56506
                {
                    dop = endpointDispatcher.DispatchRuntime.Operations[od.Name];
                }
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation is never null
                else if (endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation.Name == od.Name)
                {
                    dop = endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation;
                }
#pragma warning restore 56506
                if (dop != null)
                {
                    IDispatchMessageFormatter requestDispatch = GetRequestDispatchFormatter(od, endpoint);
                    IDispatchMessageFormatter replyDispatch = GetReplyDispatchFormatter(od, endpoint);
 
                    MultiplexingDispatchMessageFormatter replyDispatchAsMultiplexing = replyDispatch as MultiplexingDispatchMessageFormatter;
 
                    if (replyDispatchAsMultiplexing != null)
                    {
                        // here we are adding all default content types, despite the fact that
                        // some of the formatters in MultiplexingDispatchMessageFormatter might not be present
                        // i.e. the JSON formatter
 
                        replyDispatchAsMultiplexing.DefaultContentTypes.Add(WebMessageFormat.Xml, xmlContentType);
                        replyDispatchAsMultiplexing.DefaultContentTypes.Add(WebMessageFormat.Json, jsonContentType);
 
                        if (formatSelectingMessageInspector != null)
                        {
                            formatSelectingMessageInspector.RegisterOperation(od.Name, replyDispatchAsMultiplexing);
                        }
                    }
 
                    dop.Formatter = new CompositeDispatchFormatter(requestDispatch, replyDispatch);
                    dop.FaultFormatter = new WebFaultFormatter(dop.FaultFormatter);
                    dop.DeserializeRequest = (requestDispatch != null);
                    dop.SerializeReply = od.Messages.Count > 1 && (replyDispatch != null);
                }
            }
            
            if (this.HelpEnabled)
            {
                HelpPage helpPage = new HelpPage(this, endpoint.Contract);
                DispatchOperation dispatchOperation = new DispatchOperation(endpointDispatcher.DispatchRuntime, HelpOperationInvoker.OperationName, null, null)
                {
                    DeserializeRequest = false,
                    SerializeReply = false,
                    Invoker = new HelpOperationInvoker(helpPage, endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation.Invoker),
                };
                endpointDispatcher.DispatchRuntime.Operations.Add(dispatchOperation);
            }
            AddServerErrorHandlers(endpoint, endpointDispatcher);
        }
 
        internal virtual Dictionary<string, string> GetWmiProperties()
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            result.Add("DefaultBodyStyle", this.DefaultBodyStyle.ToString());
            result.Add("DefaultOutgoingRequestFormat", this.DefaultOutgoingRequestFormat.ToString());
            result.Add("DefaultOutgoingResponseFormat", this.DefaultOutgoingResponseFormat.ToString());
            return result;
        }
 
        internal virtual string GetWmiTypeName()
        {
            return "WebHttpBehavior";
        }
 
        void IWmiInstanceProvider.FillInstance(IWmiInstance wmiInstance)
        {
            if (wmiInstance == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("wmiInstance");
            }
            Dictionary<string, string> properties = this.GetWmiProperties();
            foreach (string key in properties.Keys)
            {
                wmiInstance.SetProperty(key, properties[key]);
            }
        }
 
        string IWmiInstanceProvider.GetInstanceType()
        {
            return GetWmiTypeName();
        }
 
        public virtual void Validate(ServiceEndpoint endpoint)
        {
            if (endpoint == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
            }
            ValidateNoMessageHeadersPresent(endpoint);
            ValidateBinding(endpoint);
            ValidateContract(endpoint);
        }
 
        void ValidateNoMessageHeadersPresent(ServiceEndpoint endpoint)
        {
            if (endpoint == null || endpoint.Address == null)
            {
                return;
            }
            EndpointAddress address = endpoint.Address;
            if (address.Headers.Count > 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.WebHttpServiceEndpointCannotHaveMessageHeaders, address)));
            }
        }
 
        protected virtual void ValidateBinding(ServiceEndpoint endpoint)
        {
            ValidateIsWebHttpBinding(endpoint, this.GetType().ToString());
        }
 
        internal static string GetWebMethod(OperationDescription od)
        {
            WebGetAttribute wga = od.Behaviors.Find<WebGetAttribute>();
            WebInvokeAttribute wia = od.Behaviors.Find<WebInvokeAttribute>();
            EnsureOk(wga, wia, od);
            if (wga != null)
            {
                return GET;
            }
            else if (wia != null)
            {
                return wia.Method ?? POST;
            }
            else
            {
                return POST;
            }
        }
 
        internal static string GetWebUriTemplate(OperationDescription od)
        {
            // return exactly what is on the attribute
            WebGetAttribute wga = od.Behaviors.Find<WebGetAttribute>();
            WebInvokeAttribute wia = od.Behaviors.Find<WebInvokeAttribute>();
            EnsureOk(wga, wia, od);
            if (wga != null)
            {
                return wga.UriTemplate;
            }
            else if (wia != null)
            {
                return wia.UriTemplate;
            }
            else
            {
                return null;
            }
        }
 
        internal static string GetDescription(OperationDescription od)
        {
            object[] attributes = null;
            if (od.SyncMethod != null)
            {
                attributes = od.SyncMethod.GetCustomAttributes(typeof(DescriptionAttribute), true);
            }
            else if (od.BeginMethod != null)
            {
                attributes = od.BeginMethod.GetCustomAttributes(typeof(DescriptionAttribute), true);
            }
            else if (od.TaskMethod != null)
            {
                attributes = od.TaskMethod.GetCustomAttributes(typeof(DescriptionAttribute), true);
            }
 
            if (attributes != null && attributes.Length > 0)
            {
                return ((DescriptionAttribute)attributes[0]).Description;
            }
            else
            {
                return String.Empty;
            }
        }
 
        internal static bool IsTypedMessage(MessageDescription message)
        {
            return (message != null && message.MessageType != null);
        }
 
        internal static bool IsUntypedMessage(MessageDescription message)
        {
            if (message == null)
            {
                return false;
            }
            return (message.Body.ReturnValue != null && message.Body.Parts.Count == 0 && message.Body.ReturnValue.Type == typeof(Message)) ||
                (message.Body.ReturnValue == null && message.Body.Parts.Count == 1 && message.Body.Parts[0].Type == typeof(Message));
        }
 
        internal static MessageDescription MakeDummyMessageDescription(MessageDirection direction)
        {
            MessageDescription messageDescription = new MessageDescription("urn:dummyAction", direction);
            return messageDescription;
        }
 
        internal static bool SupportsJsonFormat(OperationDescription od)
        {
            // if the type is XmlSerializable, then we cannot create a json serializer for it
            DataContractSerializerOperationBehavior dcsob = od.Behaviors.Find<DataContractSerializerOperationBehavior>();
            return (dcsob != null);
        }
 
        internal static void ValidateIsWebHttpBinding(ServiceEndpoint serviceEndpoint, string behaviorName)
        {
            Binding binding = serviceEndpoint.Binding;
            if (binding.Scheme != "http" && binding.Scheme != "https")
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    SR2.GetString(SR2.WCFBindingCannotBeUsedWithUriOperationSelectorBehaviorBadScheme,
                    serviceEndpoint.Contract.Name, behaviorName)));
            }
            if (binding.MessageVersion != MessageVersion.None)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    SR2.GetString(SR2.WCFBindingCannotBeUsedWithUriOperationSelectorBehaviorBadMessageVersion,
                    serviceEndpoint.Address.Uri.AbsoluteUri, behaviorName)));
            }
            TransportBindingElement transportBindingElement = binding.CreateBindingElements().Find<TransportBindingElement>();
            if (transportBindingElement != null && !transportBindingElement.ManualAddressing)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    SR2.GetString(SR2.ManualAddressingCannotBeFalseWithTransportBindingElement,
                    serviceEndpoint.Address.Uri.AbsoluteUri, behaviorName, transportBindingElement.GetType().Name)));
            }
        }
 
        internal WebMessageBodyStyle GetBodyStyle(OperationDescription od)
        {
            WebGetAttribute wga = od.Behaviors.Find<WebGetAttribute>();
            WebInvokeAttribute wia = od.Behaviors.Find<WebInvokeAttribute>();
            EnsureOk(wga, wia, od);
            if (wga != null)
            {
                return wga.GetBodyStyleOrDefault(this.DefaultBodyStyle);
            }
            else if (wia != null)
            {
                return wia.GetBodyStyleOrDefault(this.DefaultBodyStyle);
            }
            else
            {
                return this.DefaultBodyStyle;
            }
        }
 
        internal IClientMessageFormatter GetDefaultClientFormatter(OperationDescription od, bool useJson, bool isWrapped)
        {
            DataContractSerializerOperationBehavior dcsob = od.Behaviors.Find<DataContractSerializerOperationBehavior>();
            if (useJson)
            {
                if (dcsob == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.JsonFormatRequiresDataContract, od.Name, od.DeclaringContract.Name, od.DeclaringContract.Namespace)));
                }
                return CreateDataContractJsonSerializerOperationFormatter(od, dcsob, isWrapped);
            }
            else
            {
                ClientRuntime clientRuntime = new ClientRuntime("name", "");
                ClientOperation cop = new ClientOperation(clientRuntime, "dummyClient", "urn:dummy");
                cop.Formatter = null;
 
                if (dcsob != null)
                {
                    (dcsob as IOperationBehavior).ApplyClientBehavior(od, cop);
                    return cop.Formatter;
                }
                XmlSerializerOperationBehavior xsob = od.Behaviors.Find<XmlSerializerOperationBehavior>();
                if (xsob != null)
                {
                    xsob = new XmlSerializerOperationBehavior(od, xsob.XmlSerializerFormatAttribute, this.reflector);
                    (xsob as IOperationBehavior).ApplyClientBehavior(od, cop);
                    return cop.Formatter;
                }
            }
            return null;
        }
 
        protected virtual void AddClientErrorInspector(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            if (!this.FaultExceptionEnabled)
            {
                clientRuntime.MessageInspectors.Add(new WebFaultClientMessageInspector());
            }
            else
            {
                clientRuntime.MessageVersionNoneFaultsEnabled = true;
            }
        }
 
        protected virtual void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            if (!this.FaultExceptionEnabled)
            {
                WebErrorHandler errorHandler = new WebErrorHandler(this, endpoint.Contract, endpointDispatcher.DispatchRuntime.ChannelDispatcher.IncludeExceptionDetailInFaults);
                endpointDispatcher.DispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
 
        protected virtual WebHttpDispatchOperationSelector GetOperationSelector(ServiceEndpoint endpoint)
        {
            return new WebHttpDispatchOperationSelector(endpoint);
        }
 
        protected virtual QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
        {
            return new QueryStringConverter();
        }
 
        protected virtual IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
        {
            if (operationDescription.Messages.Count < 2)
            {
                return null;
            }
            ValidateBodyParameters(operationDescription, false);
            Type type;
            if (TryGetStreamParameterType(operationDescription.Messages[1], operationDescription, false, out type))
            {
                return new HttpStreamFormatter(operationDescription);
            }
            if (IsUntypedMessage(operationDescription.Messages[1]))
            {
                return new MessagePassthroughFormatter();
            }
            WebMessageBodyStyle style = GetBodyStyle(operationDescription);
            Type parameterType;
            if (UseBareReplyFormatter(style, operationDescription, GetResponseFormat(operationDescription), out parameterType))
            {
                return SingleBodyParameterMessageFormatter.CreateXmlAndJsonClientFormatter(operationDescription, parameterType, false, this.xmlSerializerManager);
            }
            else
            {
                MessageDescription temp = operationDescription.Messages[0];
                operationDescription.Messages[0] = MakeDummyMessageDescription(MessageDirection.Input);
                IClientMessageFormatter result;
                result = GetDefaultXmlAndJsonClientFormatter(operationDescription, !IsBareResponse(style));
                operationDescription.Messages[0] = temp;
                return result;
            }
        }
 
        internal virtual bool UseBareReplyFormatter(WebMessageBodyStyle style, OperationDescription operationDescription, WebMessageFormat responseFormat, out Type parameterType)
        {
            parameterType = null;
            return IsBareResponse(style) && TryGetNonMessageParameterType(operationDescription.Messages[1], operationDescription, false, out parameterType);
        }
 
        protected virtual IDispatchMessageFormatter GetReplyDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
        {
            if (operationDescription.Messages.Count < 2)
            {
                return null;
            }
            ValidateBodyParameters(operationDescription, false);
            WebMessageFormat responseFormat = GetResponseFormat(operationDescription);
 
            //  Determine if we should add a json formatter; If the ResponseFormat is json, we always add the json formatter even if the
            //  operation is XmlSerializerFormat because the formatter constructor throws the exception: "json not valid with XmlSerializerFormat" [Microsoft]
            bool useJson = (responseFormat == WebMessageFormat.Json || SupportsJsonFormat(operationDescription));
 
            IDispatchMessageFormatter innerFormatter;
            Type type;
 
            if (TryGetStreamParameterType(operationDescription.Messages[1], operationDescription, false, out type))
            {
                innerFormatter = new ContentTypeSettingDispatchMessageFormatter(defaultStreamContentType, new HttpStreamFormatter(operationDescription));
            }
            else if (IsUntypedMessage(operationDescription.Messages[1]))
            {
                innerFormatter = new MessagePassthroughFormatter();
            }
            else
            {
                Type parameterType;
                WebMessageBodyStyle style = GetBodyStyle(operationDescription);
                Dictionary<WebMessageFormat, IDispatchMessageFormatter> formatters = new Dictionary<WebMessageFormat, IDispatchMessageFormatter>();
 
                if (UseBareReplyFormatter(style, operationDescription, responseFormat, out parameterType))
                {
                    formatters.Add(WebMessageFormat.Xml, SingleBodyParameterMessageFormatter.CreateDispatchFormatter(operationDescription, parameterType, false, false, this.xmlSerializerManager, null));
                    if (useJson)
                    {
                        formatters.Add(WebMessageFormat.Json, SingleBodyParameterMessageFormatter.CreateDispatchFormatter(operationDescription, parameterType, false, true, this.xmlSerializerManager, this.JavascriptCallbackParameterName));
                    }
                }
                else
                {
                    MessageDescription temp = operationDescription.Messages[0];
                    operationDescription.Messages[0] = MakeDummyMessageDescription(MessageDirection.Input);
                    formatters.Add(WebMessageFormat.Xml, GetDefaultDispatchFormatter(operationDescription, false, !IsBareResponse(style)));
                    if (useJson)
                    {
                        formatters.Add(WebMessageFormat.Json, GetDefaultDispatchFormatter(operationDescription, true, !IsBareResponse(style)));
                    }
                    operationDescription.Messages[0] = temp;
                }
                innerFormatter = new MultiplexingDispatchMessageFormatter(formatters, responseFormat);
            }
 
            return innerFormatter;
        }
 
        protected virtual IClientMessageFormatter GetRequestClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
        {
            WebMessageFormat requestFormat = GetRequestFormat(operationDescription);
            bool useJson = (requestFormat == WebMessageFormat.Json);
            WebMessageEncodingBindingElement webEncoding = (useJson) ? endpoint.Binding.CreateBindingElements().Find<WebMessageEncodingBindingElement>() : null;
            IClientMessageFormatter innerFormatter = null;
 
            // get some validation errors by creating "throwAway" formatter
 
            // validate that endpoint.Address is not null before accessing the endpoint.Address.Uri. This is to avoid throwing a NullRefException while constructing a UriTemplateClientFormatter
            if (endpoint.Address == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SR2.GetString(SR2.ServiceEndpointMustHaveNonNullAddress, typeof(ServiceEndpoint), typeof(ChannelFactory), typeof(WebHttpEndpoint), AddressPropertyName, typeof(ServiceEndpoint))));
            }
 
            UriTemplateClientFormatter throwAway = new UriTemplateClientFormatter(operationDescription, null, GetQueryStringConverter(operationDescription), endpoint.Address.Uri, false, endpoint.Contract.Name);
            int numUriVariables = throwAway.pathMapping.Count + throwAway.queryMapping.Count;
            bool isStream = false;
            HideReplyMessage(operationDescription, delegate()
            {
                WebMessageBodyStyle style = GetBodyStyle(operationDescription);
                bool isUntypedWhenUriParamsNotConsidered = false;
                Effect doBodyFormatter = delegate()
                {
                    if (numUriVariables != 0)
                    {
                        EnsureNotUntypedMessageNorMessageContract(operationDescription);
                    }
                    // get body formatter
                    ValidateBodyParameters(operationDescription, true);
                    IClientMessageFormatter baseFormatter;
                    Type parameterType;
                    if (TryGetStreamParameterType(operationDescription.Messages[0], operationDescription, true, out parameterType))
                    {
                        isStream = true;
                        baseFormatter = new HttpStreamFormatter(operationDescription);
                    }
                    else if (UseBareRequestFormatter(style, operationDescription, out parameterType))
                    {
                        baseFormatter = SingleBodyParameterMessageFormatter.CreateClientFormatter(operationDescription, parameterType, true, useJson, this.xmlSerializerManager);
                    }
                    else
                    {
                        baseFormatter = GetDefaultClientFormatter(operationDescription, useJson, !IsBareRequest(style));
                    }
                    innerFormatter = baseFormatter;
                    isUntypedWhenUriParamsNotConsidered = IsUntypedMessage(operationDescription.Messages[0]);
                };
                if (numUriVariables == 0)
                {
                    if (IsUntypedMessage(operationDescription.Messages[0]))
                    {
                        ValidateBodyParameters(operationDescription, true);
                        innerFormatter = new MessagePassthroughFormatter();
                        isUntypedWhenUriParamsNotConsidered = true;
                    }
                    else if (IsTypedMessage(operationDescription.Messages[0]))
                    {
                        ValidateBodyParameters(operationDescription, true);
                        innerFormatter = GetDefaultClientFormatter(operationDescription, useJson, !IsBareRequest(style));
                    }
                    else
                    {
                        doBodyFormatter();
                    }
                }
                else
                {
                    HideRequestUriTemplateParameters(operationDescription, throwAway, delegate()
                    {
                        CloneMessageDescriptionsBeforeActing(operationDescription, delegate()
                        {
                            doBodyFormatter();
                        });
                    });
                }
                innerFormatter = new UriTemplateClientFormatter(operationDescription, innerFormatter, GetQueryStringConverter(operationDescription), endpoint.Address.Uri, isUntypedWhenUriParamsNotConsidered, endpoint.Contract.Name);
            });
            string defaultContentType = GetDefaultContentType(isStream, useJson, webEncoding);
            if (!string.IsNullOrEmpty(defaultContentType))
            {
                innerFormatter = new ContentTypeSettingClientMessageFormatter(defaultContentType, innerFormatter);
            }
            return innerFormatter;
        }
 
        protected virtual IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
        {
            IDispatchMessageFormatter result = null;
            // get some validation errors by creating "throwAway" formatter
            UriTemplateDispatchFormatter throwAway = new UriTemplateDispatchFormatter(operationDescription, null, GetQueryStringConverter(operationDescription), endpoint.Contract.Name, endpoint.Address.Uri);
            int numUriVariables = throwAway.pathMapping.Count + throwAway.queryMapping.Count;
            HideReplyMessage(operationDescription, delegate()
            {
                WebMessageBodyStyle style = GetBodyStyle(operationDescription);
                Effect doBodyFormatter = delegate()
                {
                    if (numUriVariables != 0)
                    {
                        EnsureNotUntypedMessageNorMessageContract(operationDescription);
                    }
                    // get body formatter
                    ValidateBodyParameters(operationDescription, true);
                    Type type;
                    if (TryGetStreamParameterType(operationDescription.Messages[0], operationDescription, true, out type))
                    {
                        result = new HttpStreamFormatter(operationDescription);
                    }
                    else
                    {
                        Type parameterType;
                        if (UseBareRequestFormatter(style, operationDescription, out parameterType))
                        {
                            result = SingleBodyParameterMessageFormatter.CreateXmlAndJsonDispatchFormatter(operationDescription, parameterType, true, this.xmlSerializerManager, this.JavascriptCallbackParameterName);
                        }
                        else
                        {
                            result = GetDefaultXmlAndJsonDispatchFormatter(operationDescription, !IsBareRequest(style));
                        }
                    }
                };
                if (numUriVariables == 0)
                {
                    if (IsUntypedMessage(operationDescription.Messages[0]))
                    {
                        ValidateBodyParameters(operationDescription, true);
                        result = new MessagePassthroughFormatter();
                    }
                    else if (IsTypedMessage(operationDescription.Messages[0]))
                    {
                        ValidateBodyParameters(operationDescription, true);
                        result = GetDefaultXmlAndJsonDispatchFormatter(operationDescription, !IsBareRequest(style));
                    }
                    else
                    {
                        doBodyFormatter();
                    }
                }
                else
                {
                    HideRequestUriTemplateParameters(operationDescription, throwAway, delegate()
                    {
                        CloneMessageDescriptionsBeforeActing(operationDescription, delegate()
                        {
                            doBodyFormatter();
                        });
                    });
                }
                result = new UriTemplateDispatchFormatter(operationDescription, result, GetQueryStringConverter(operationDescription), endpoint.Contract.Name, endpoint.Address.Uri);
            });
            return result;
        }
 
        static void CloneMessageDescriptionsBeforeActing(OperationDescription operationDescription, Effect effect)
        {
            MessageDescription originalRequest = operationDescription.Messages[0];
            bool thereIsAReply = operationDescription.Messages.Count > 1;
            MessageDescription originalReply = thereIsAReply ? operationDescription.Messages[1] : null;
            operationDescription.Messages[0] = originalRequest.Clone();
            if (thereIsAReply)
            {
                operationDescription.Messages[1] = originalReply.Clone();
            }
            effect();
            operationDescription.Messages[0] = originalRequest;
            if (thereIsAReply)
            {
                operationDescription.Messages[1] = originalReply;
            }
        }
 
        internal virtual bool UseBareRequestFormatter(WebMessageBodyStyle style, OperationDescription operationDescription, out Type parameterType)
        {
            parameterType = null;
            return IsBareRequest(style) && TryGetNonMessageParameterType(operationDescription.Messages[0], operationDescription, true, out parameterType);
        }
 
        static Collection<MessagePartDescription> CloneParts(MessageDescription md)
        {
            MessagePartDescriptionCollection bodyParameters = md.Body.Parts;
            Collection<MessagePartDescription> bodyParametersClone = new Collection<MessagePartDescription>();
            for (int i = 0; i < bodyParameters.Count; ++i)
            {
                MessagePartDescription copy = bodyParameters[i].Clone();
                bodyParametersClone.Add(copy);
            }
            return bodyParametersClone;
        }
 
        static void EnsureNotUntypedMessageNorMessageContract(OperationDescription operationDescription)
        {
            // Called when there are UriTemplate parameters.  UT does not compose with Message
            // or MessageContract because the SOAP and REST programming models must be uniform here.
            bool isUnadornedWebGet = false;
            if (GetWebMethod(operationDescription) == GET && GetWebUriTemplate(operationDescription) == null)
            {
                isUnadornedWebGet = true;
            }
            if (IsTypedMessage(operationDescription.Messages[0]))
            {
                if (isUnadornedWebGet)
                {
                    // WebGet will give you UriTemplate parameters by default.
                    // We need a special error message for this case to prevent confusion.
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                        SR2.GetString(SR2.GETCannotHaveMCParameter, operationDescription.Name, operationDescription.DeclaringContract.Name, operationDescription.Messages[0].MessageType.Name)));
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(
                        SR2.UTParamsDoNotComposeWithMessageContract, operationDescription.Name, operationDescription.DeclaringContract.Name)));
                }
            }
 
            if (IsUntypedMessage(operationDescription.Messages[0]))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(
                    SR2.UTParamsDoNotComposeWithMessage, operationDescription.Name, operationDescription.DeclaringContract.Name)));
            }
        }
 
        static void EnsureOk(WebGetAttribute wga, WebInvokeAttribute wia, OperationDescription od)
        {
            if (wga != null && wia != null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    SR2.GetString(SR2.MultipleWebAttributes, od.Name, od.DeclaringContract.Name)));
            }
        }
 
        static void HideReplyMessage(OperationDescription operationDescription, Effect effect)
        {
            MessageDescription temp = null;
            if (operationDescription.Messages.Count > 1)
            {
                temp = operationDescription.Messages[1];
                operationDescription.Messages[1] = MakeDummyMessageDescription(MessageDirection.Output);
            }
            effect();
            if (operationDescription.Messages.Count > 1)
            {
                operationDescription.Messages[1] = temp;
            }
        }
 
        static void HideRequestUriTemplateParameters(OperationDescription operationDescription, UriTemplateClientFormatter throwAway, Effect effect)
        {
            HideRequestUriTemplateParameters(operationDescription, throwAway.pathMapping, throwAway.queryMapping, effect);
        }
 
        internal static void HideRequestUriTemplateParameters(OperationDescription operationDescription, UriTemplateDispatchFormatter throwAway, Effect effect)
        {
            HideRequestUriTemplateParameters(operationDescription, throwAway.pathMapping, throwAway.queryMapping, effect);
        }
 
        static void HideRequestUriTemplateParameters(OperationDescription operationDescription, Dictionary<int, string> pathMapping, Dictionary<int, KeyValuePair<string, Type>> queryMapping, Effect effect)
        {
            // mutate description to hide UriTemplate parameters
            Collection<MessagePartDescription> originalParts = CloneParts(operationDescription.Messages[0]);
            Collection<MessagePartDescription> parts = CloneParts(operationDescription.Messages[0]);
            operationDescription.Messages[0].Body.Parts.Clear();
            int newIndex = 0;
            for (int i = 0; i < parts.Count; ++i)
            {
                if (!pathMapping.ContainsKey(i) && !queryMapping.ContainsKey(i))
                {
                    operationDescription.Messages[0].Body.Parts.Add(parts[i]);
                    parts[i].Index = newIndex++;
                }
            }
            effect();
            // unmutate description
            operationDescription.Messages[0].Body.Parts.Clear();
            for (int i = 0; i < originalParts.Count; ++i)
            {
                operationDescription.Messages[0].Body.Parts.Add(originalParts[i]);
            }
        }
 
        static bool IsBareRequest(WebMessageBodyStyle style)
        {
            return (style == WebMessageBodyStyle.Bare || style == WebMessageBodyStyle.WrappedResponse);
        }
 
        static bool IsBareResponse(WebMessageBodyStyle style)
        {
            return (style == WebMessageBodyStyle.Bare || style == WebMessageBodyStyle.WrappedRequest);
        }
 
        internal static bool TryGetNonMessageParameterType(MessageDescription message, OperationDescription declaringOperation, bool isRequest, out Type type)
        {
            type = null;
            if (message == null)
            {
                return true;
            }
            if (IsTypedMessage(message) || IsUntypedMessage(message))
            {
                return false;
            }
            if (isRequest)
            {
                if (message.Body.Parts.Count > 1)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.AtMostOneRequestBodyParameterAllowedForUnwrappedMessages, declaringOperation.Name, declaringOperation.DeclaringContract.Name)));
                }
                if (message.Body.Parts.Count == 1 && message.Body.Parts[0].Type != typeof(void))
                {
                    type = message.Body.Parts[0].Type;
                }
                return true;
            }
            else
            {
                if (message.Body.Parts.Count > 0)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.OnlyReturnValueBodyParameterAllowedForUnwrappedMessages, declaringOperation.Name, declaringOperation.DeclaringContract.Name)));
                }
                if (message.Body.ReturnValue != null && message.Body.ReturnValue.Type != typeof(void))
                {
                    type = message.Body.ReturnValue.Type;
                }
                return true;
            }
        }
 
        static bool TryGetStreamParameterType(MessageDescription message, OperationDescription declaringOperation, bool isRequest, out Type type)
        {
            type = null;
            if (message == null || IsTypedMessage(message) || IsUntypedMessage(message))
            {
                return false;
            }
            if (isRequest)
            {
                bool hasStream = false;
                for (int i = 0; i < message.Body.Parts.Count; ++i)
                {
                    if (typeof(Stream) == message.Body.Parts[i].Type)
                    {
                        type = message.Body.Parts[i].Type;
                        hasStream = true;
                        break;
                    }
 
                }
                if (hasStream && message.Body.Parts.Count > 1)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR2.GetString(SR2.AtMostOneRequestBodyParameterAllowedForStream, declaringOperation.Name, declaringOperation.DeclaringContract.Name)));
                }
                return hasStream;
            }
            else
            {
                // validate that the stream is not an out or ref param
                for (int i = 0; i < message.Body.Parts.Count; ++i)
                {
                    if (typeof(Stream) == message.Body.Parts[i].Type)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR2.GetString(SR2.NoOutOrRefStreamParametersAllowed, message.Body.Parts[i].Name, declaringOperation.Name, declaringOperation.DeclaringContract.Name)));
                    }
                }
                if (message.Body.ReturnValue != null && typeof(Stream) == message.Body.ReturnValue.Type)
                {
                    // validate that there are no out or ref params
                    if (message.Body.Parts.Count > 0)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR2.GetString(SR2.NoOutOrRefParametersAllowedWithStreamResult, declaringOperation.Name, declaringOperation.DeclaringContract.Name)));
                    }
                    type = message.Body.ReturnValue.Type;
                    return true;
                }
 
                else
                {
                    return false;
                }
            }
        }
 
        static void ValidateAtMostOneStreamParameter(OperationDescription operation, bool request)
        {
            Type dummy;
            if (request)
            {
                TryGetStreamParameterType(operation.Messages[0], operation, true, out dummy);
            }
            else
            {
                if (operation.Messages.Count > 1)
                {
                    TryGetStreamParameterType(operation.Messages[1], operation, false, out dummy);
                }
            }
        }
 
        string GetDefaultContentType(bool isStream, bool useJson, WebMessageEncodingBindingElement webEncoding)
        {
            if (isStream)
            {
                return defaultStreamContentType;
            }
            else if (useJson)
            {
                return JsonMessageEncoderFactory.GetContentType(webEncoding);
            }
            else
            {
                return null;
            }
        }
 
        IDispatchMessageFormatter GetDefaultDispatchFormatter(OperationDescription od, bool useJson, bool isWrapped)
        {
            DataContractSerializerOperationBehavior dcsob = od.Behaviors.Find<DataContractSerializerOperationBehavior>();
            if (useJson)
            {
                if (dcsob == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.JsonFormatRequiresDataContract, od.Name, od.DeclaringContract.Name, od.DeclaringContract.Namespace)));
                }
                return CreateDataContractJsonSerializerOperationFormatter(od, dcsob, isWrapped);
            }
            else
            {
                EndpointDispatcher dummyED = new EndpointDispatcher(new EndpointAddress("http://localhost/"), "name", "");
                DispatchRuntime dispatchRuntime = dummyED.DispatchRuntime;
                DispatchOperation dop = new DispatchOperation(dispatchRuntime, "dummyDispatch", "urn:dummy");
                dop.Formatter = null;
 
                if (dcsob != null)
                {
                    (dcsob as IOperationBehavior).ApplyDispatchBehavior(od, dop);
                    return dop.Formatter;
                }
                XmlSerializerOperationBehavior xsob = od.Behaviors.Find<XmlSerializerOperationBehavior>();
                if (xsob != null)
                {
                    xsob = new XmlSerializerOperationBehavior(od, xsob.XmlSerializerFormatAttribute, this.reflector);
                    (xsob as IOperationBehavior).ApplyDispatchBehavior(od, dop);
                    return dop.Formatter;
                }
            }
            return null;
        }
 
        internal virtual DataContractJsonSerializerOperationFormatter CreateDataContractJsonSerializerOperationFormatter(OperationDescription od, DataContractSerializerOperationBehavior dcsob, bool isWrapped)
        {
            return new DataContractJsonSerializerOperationFormatter(od, dcsob.MaxItemsInObjectGraph, dcsob.IgnoreExtensionDataObject, dcsob.DataContractSurrogate, isWrapped, false, JavascriptCallbackParameterName);
        }
 
        IClientMessageFormatter GetDefaultXmlAndJsonClientFormatter(OperationDescription od, bool isWrapped)
        {
            IClientMessageFormatter xmlFormatter = GetDefaultClientFormatter(od, false, isWrapped);
            if (!SupportsJsonFormat(od))
            {
                return xmlFormatter;
            }
            IClientMessageFormatter jsonFormatter = GetDefaultClientFormatter(od, true, isWrapped);
            Dictionary<WebContentFormat, IClientMessageFormatter> map = new Dictionary<WebContentFormat, IClientMessageFormatter>();
            map.Add(WebContentFormat.Xml, xmlFormatter);
            map.Add(WebContentFormat.Json, jsonFormatter);
            // In case there is no format property, the default formatter to use is XML
            return new DemultiplexingClientMessageFormatter(map, xmlFormatter);
        }
 
        IDispatchMessageFormatter GetDefaultXmlAndJsonDispatchFormatter(OperationDescription od, bool isWrapped)
        {
            IDispatchMessageFormatter xmlFormatter = GetDefaultDispatchFormatter(od, false, isWrapped);
            if (!SupportsJsonFormat(od))
            {
                return xmlFormatter;
            }
            IDispatchMessageFormatter jsonFormatter = GetDefaultDispatchFormatter(od, true, isWrapped);
            Dictionary<WebContentFormat, IDispatchMessageFormatter> map = new Dictionary<WebContentFormat, IDispatchMessageFormatter>();
            map.Add(WebContentFormat.Xml, xmlFormatter);
            map.Add(WebContentFormat.Json, jsonFormatter);
            return new DemultiplexingDispatchMessageFormatter(map, xmlFormatter);
        }
 
        internal WebMessageFormat GetRequestFormat(OperationDescription od)
        {
            WebGetAttribute wga = od.Behaviors.Find<WebGetAttribute>();
            WebInvokeAttribute wia = od.Behaviors.Find<WebInvokeAttribute>();
            EnsureOk(wga, wia, od);
            if (wga != null)
            {
                return wga.IsRequestFormatSetExplicitly ? wga.RequestFormat : this.DefaultOutgoingRequestFormat;
            }
            else if (wia != null)
            {
                return wia.IsRequestFormatSetExplicitly ? wia.RequestFormat : this.DefaultOutgoingRequestFormat;
            }
            else
            {
                return this.DefaultOutgoingRequestFormat;
            }
        }
 
        internal WebMessageFormat GetResponseFormat(OperationDescription od)
        {
            WebGetAttribute wga = od.Behaviors.Find<WebGetAttribute>();
            WebInvokeAttribute wia = od.Behaviors.Find<WebInvokeAttribute>();
            EnsureOk(wga, wia, od);
            if (wga != null)
            {
                return wga.IsResponseFormatSetExplicitly ? wga.ResponseFormat : this.DefaultOutgoingResponseFormat;
            }
            else if (wia != null)
            {
                return wia.IsResponseFormatSetExplicitly ? wia.ResponseFormat : this.DefaultOutgoingResponseFormat;
            }
            else
            {
                return this.DefaultOutgoingResponseFormat;
            }
        }
 
        void ValidateBodyParameters(OperationDescription operation, bool request)
        {
            string method = GetWebMethod(operation);
            if (request)
            {
                ValidateGETHasNoBody(operation, method);
            }
            // validate that if bare is chosen for request/response, then at most 1 parameter is possible
            ValidateBodyStyle(operation, request);
            // validate if the request or response body is a stream, no other body parameters
            // can be specified
            ValidateAtMostOneStreamParameter(operation, request);
        }
 
        void ValidateBodyStyle(OperationDescription operation, bool request)
        {
            WebMessageBodyStyle style = GetBodyStyle(operation);
            Type dummy;
            if (request && IsBareRequest(style))
            {
                TryGetNonMessageParameterType(operation.Messages[0], operation, true, out dummy);
            }
            if (!request && operation.Messages.Count > 1 && IsBareResponse(style))
            {
                TryGetNonMessageParameterType(operation.Messages[1], operation, false, out dummy);
            }
        }
 
        void ValidateGETHasNoBody(OperationDescription operation, string method)
        {
            if (method == GET)
            {
                if (!IsUntypedMessage(operation.Messages[0]) && operation.Messages[0].Body.Parts.Count != 0)
                {
                    if (!IsTypedMessage(operation.Messages[0]))
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SR2.GetString(SR2.GETCannotHaveBody, operation.Name, operation.DeclaringContract.Name, operation.Messages[0].Body.Parts[0].Name)));
                    }
                    else
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SR2.GetString(SR2.GETCannotHaveMCParameter, operation.Name, operation.DeclaringContract.Name, operation.Messages[0].MessageType.Name)));
                    }
                }
            }
        }
 
        void ValidateContract(ServiceEndpoint endpoint)
        {
            foreach (OperationDescription od in endpoint.Contract.Operations)
            {
                ValidateNoOperationHasEncodedXmlSerializer(od);
                ValidateNoMessageContractHeaders(od.Messages[0], od.Name, endpoint.Contract.Name);
                ValidateNoBareMessageContractWithMultipleParts(od.Messages[0], od.Name, endpoint.Contract.Name);
                ValidateNoMessageContractWithStream(od.Messages[0], od.Name, endpoint.Contract.Name);
                if (od.Messages.Count > 1)
                {
                    ValidateNoMessageContractHeaders(od.Messages[1], od.Name, endpoint.Contract.Name);
                    ValidateNoBareMessageContractWithMultipleParts(od.Messages[1], od.Name, endpoint.Contract.Name);
                    ValidateNoMessageContractWithStream(od.Messages[1], od.Name, endpoint.Contract.Name);
                }
            }
        }
 
        internal static bool IsXmlSerializerFaultFormat(OperationDescription operationDescription)
        {
            XmlSerializerOperationBehavior xsob = operationDescription.Behaviors.Find<XmlSerializerOperationBehavior>();
            return (xsob != null && xsob.XmlSerializerFormatAttribute.SupportFaults);
        }
 
        void ValidateNoMessageContractWithStream(MessageDescription md, string opName, string contractName)
        {
            if (IsTypedMessage(md))
            {
                foreach (MessagePartDescription description in md.Body.Parts)
                {
                    if (description.Type == typeof(Stream))
                    {
                        throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            new InvalidOperationException(System.ServiceModel.SR2.GetString(System.ServiceModel.SR2.StreamBodyMemberNotSupported, this.GetType().ToString(), contractName, opName, md.MessageType.ToString(), description.Name)));
                    }
                }
            }
        }
 
        void ValidateNoOperationHasEncodedXmlSerializer(OperationDescription od)
        {
            XmlSerializerOperationBehavior xsob = od.Behaviors.Find<XmlSerializerOperationBehavior>();
            if (xsob != null && (xsob.XmlSerializerFormatAttribute.Style == OperationFormatStyle.Rpc || xsob.XmlSerializerFormatAttribute.IsEncoded))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.RpcEncodedNotSupportedForNoneMessageVersion, od.Name, od.DeclaringContract.Name, od.DeclaringContract.Namespace)));
            }
        }
 
        void ValidateNoBareMessageContractWithMultipleParts(MessageDescription md, string opName, string contractName)
        {
            if (IsTypedMessage(md) && md.Body.WrapperName == null)
            {
                if (md.Body.Parts.Count > 1)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                        SR2.GetString(SR2.InvalidMessageContractWithoutWrapperName, opName, contractName, md.MessageType)));
                }
                if (md.Body.Parts.Count == 1 && md.Body.Parts[0].Multiple)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.MCAtMostOneRequestBodyParameterAllowedForUnwrappedMessages, opName, contractName, md.MessageType)));
                }
            }
        }
 
        void ValidateNoMessageContractHeaders(MessageDescription md, string opName, string contractName)
        {
            if (md.Headers.Count != 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    SR2.GetString(SR2.InvalidMethodWithSOAPHeaders, opName, contractName)));
            }
        }
 
        internal class MessagePassthroughFormatter : IClientMessageFormatter, IDispatchMessageFormatter
        {
            public object DeserializeReply(Message message, object[] parameters)
            {
                return message;
            }
 
            public void DeserializeRequest(Message message, object[] parameters)
            {
                parameters[0] = message;
            }
 
            public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
            {
                return result as Message;
            }
 
            public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
            {
                return parameters[0] as Message;
            }
        }
 
        static internal JavascriptCallbackResponseMessageProperty TrySetupJavascriptCallback(string callbackParameterName)
        {
            JavascriptCallbackResponseMessageProperty javascriptProperty = null;
            if (!String.IsNullOrEmpty(callbackParameterName) &&
                !OperationContext.Current.OutgoingMessageProperties.TryGetValue<JavascriptCallbackResponseMessageProperty>(JavascriptCallbackResponseMessageProperty.Name, out javascriptProperty))
            {
                UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;
                if (match != null &&
                    match.QueryParameters.AllKeys.Contains(callbackParameterName))
                {
                    string callbackName = match.QueryParameters[callbackParameterName];
 
                    if (!String.IsNullOrEmpty(callbackName))
                    {
                        javascriptProperty = new JavascriptCallbackResponseMessageProperty
                        {
                            CallbackFunctionName = callbackName
                        };
                        OperationContext.Current.OutgoingMessageProperties.Add(JavascriptCallbackResponseMessageProperty.Name, javascriptProperty);
                    }
                }
            }
            return javascriptProperty;
        }
    }
}