WebHttpBehavior.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / NetFx35 / System.ServiceModel.Web / System / ServiceModel / Description / WebHttpBehavior.cs / 2 / WebHttpBehavior.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Description 
{
    using System; 
    using System.Text; 
    using System.ServiceModel;
    using System.ServiceModel.Channels; 
    using System.ServiceModel.Dispatcher;
    using System.IO;
    using System.Collections.Generic;
    using System.Net; 
    using System.ServiceModel.Web;
    using System.Collections.ObjectModel; 
    using System.Diagnostics.CodeAnalysis; 
    using System.ServiceModel.Administration;
 
    public class WebHttpBehavior : IEndpointBehavior, IWmiInstanceProvider
    {
        internal const string GET = "GET";
        internal const string POST = "POST"; 
        internal const string WildcardAction = "*";
        internal const string WildcardMethod = "*"; 
        static readonly string defaultStreamContentType = "application/octet-stream"; 
        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 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");
            }
#pragma warning disable 56506 // [....], 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 // [....], 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"); 
            }
#pragma warning disable 56506 // [....], 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 // [....], endpointDispatcher.DispatchRuntime is never null
            endpointDispatcher.DispatchRuntime.OperationSelector = this.GetOperationSelector(endpoint); 
#pragma warning restore 56506 
            // unhandled operation
            string actionStarOperationName = null; 
#pragma warning disable 56506 // [....], 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 // [....], endpointDispatcher.DispatchRuntime.{Operations,UnhandledDispatchOperation} is never null 
                endpointDispatcher.DispatchRuntime.Operations.Add(
                    endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation); 
#pragma warning restore 56506
            }
#pragma warning disable 56506 // [....], 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();
#pragma warning restore 56506 
            // install formatters and parameter inspectors
            foreach (OperationDescription od in endpoint.Contract.Operations)
            {
                DispatchOperation dop = null; 
#pragma warning disable 56506 // [....], 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 // [....], 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);
                    dop.Formatter = new CompositeDispatchFormatter(requestDispatch, replyDispatch);
                    dop.DeserializeRequest = (requestDispatch != null); 
                    dop.SerializeReply = od.Messages.Count > 1 && (replyDispatch != null);
                } 
            } 
            AddServerErrorHandlers(endpoint, endpointDispatcher);
        } 

        internal virtual Dictionary GetWmiProperties()
        {
            Dictionary result = new Dictionary(); 
            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 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();
            WebInvokeAttribute wia = od.Behaviors.Find();
            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(); 
            WebInvokeAttribute wia = od.Behaviors.Find();
            EnsureOk(wga, wia, od); 
            if (wga != null) 
            {
                return wga.UriTemplate; 
            }
            else if (wia != null)
            {
                return wia.UriTemplate; 
            }
            else 
            { 
                return null;
            } 
        }

        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();
            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();
            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(); 
            WebInvokeAttribute wia = od.Behaviors.Find();
            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();
            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(); 
                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) 
        {
            clientRuntime.MessageInspectors.Add(new WebFaultClientMessageInspector());
        }
 
        protected virtual void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        { 
            endpointDispatcher.DispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(new WebErrorHandler(endpointDispatcher.DispatchRuntime.ChannelDispatcher.IncludeExceptionDetailInFaults)); 
        }
 
        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);
            bool useJson = (responseFormat == WebMessageFormat.Json); 
            WebMessageEncodingBindingElement webEncoding = (useJson) ? endpoint.Binding.CreateBindingElements().Find() : null;
            IDispatchMessageFormatter innerFormatter; 
            Type type; 
            bool isStream = false;
            if (TryGetStreamParameterType(operationDescription.Messages[1], operationDescription, false, out type)) 
            {
                isStream = true;
                innerFormatter = new HttpStreamFormatter(operationDescription);
            } 
            else if (IsUntypedMessage(operationDescription.Messages[1]))
            { 
                innerFormatter = new MessagePassthroughFormatter(); 
            }
            else 
            {
                Type parameterType;
                WebMessageBodyStyle style = GetBodyStyle(operationDescription);
                if (UseBareReplyFormatter(style, operationDescription, responseFormat, out parameterType)) 
                {
                    innerFormatter = SingleBodyParameterMessageFormatter.CreateDispatchFormatter(operationDescription, parameterType, false, useJson, this.xmlSerializerManager); 
                } 
                else
                { 
                    MessageDescription temp = operationDescription.Messages[0];
                    operationDescription.Messages[0] = MakeDummyMessageDescription(MessageDirection.Input);
                    innerFormatter = GetDefaultDispatchFormatter(operationDescription, useJson, !IsBareResponse(style));
                    operationDescription.Messages[0] = temp; 
                }
            } 
            string defaultContentType = GetDefaultContentType(isStream, useJson, webEncoding); 
            if (!string.IsNullOrEmpty(defaultContentType))
            { 
                return new ContentTypeSettingDispatchMessageFormatter(defaultContentType, innerFormatter);
            }
            else
            { 
                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() : null; 
            IClientMessageFormatter innerFormatter = null;
 
            // get some validation errors by creating "throwAway" formatter 
            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); 
                        }
                        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 CloneParts(MessageDescription md)
        { 
            MessagePartDescriptionCollection bodyParameters = md.Body.Parts;
            Collection bodyParametersClone = new Collection();
            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 pathMapping, Dictionary> queryMapping, Effect effect)
        { 
            // mutate description to hide UriTemplate parameters 
            Collection originalParts = CloneParts(operationDescription.Messages[0]);
            Collection 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); 
        }

        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();
            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(); 
                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);
        } 

        IClientMessageFormatter GetDefaultXmlAndJsonClientFormatter(OperationDescription od, bool isWrapped)
        {
            IClientMessageFormatter xmlFormatter = GetDefaultClientFormatter(od, false, isWrapped); 
            if (!SupportsJsonFormat(od))
            { 
                return xmlFormatter; 
            }
            IClientMessageFormatter jsonFormatter = GetDefaultClientFormatter(od, true, isWrapped); 
            Dictionary map = new Dictionary();
            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 map = new Dictionary(); 
            map.Add(WebContentFormat.Xml, xmlFormatter);
            map.Add(WebContentFormat.Json, jsonFormatter); 
            return new DemultiplexingDispatchMessageFormatter(map, xmlFormatter);
        }

        WebMessageFormat GetRequestFormat(OperationDescription od) 
        {
            WebGetAttribute wga = od.Behaviors.Find(); 
            WebInvokeAttribute wia = od.Behaviors.Find(); 
            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;
            }
        }
 
        WebMessageFormat GetResponseFormat(OperationDescription od)
        { 
            WebGetAttribute wga = od.Behaviors.Find(); 
            WebInvokeAttribute wia = od.Behaviors.Find();
            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);
                } 
            }
        } 
 
        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(); 
            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;
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK