SoapProcessingBehavior.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.ServiceModel.Routing / System / ServiceModel / Routing / SoapProcessingBehavior.cs / 1305376 / SoapProcessingBehavior.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------

//Turn on to log info about the before and after headers/messages 
//#define DEBUG_MARSHALING
 
namespace System.ServiceModel.Routing 
{
    using System; 
    using System.Collections.Generic;
    using System.Globalization;
    using System.ServiceModel;
    using System.ServiceModel.Channels; 
    using System.ServiceModel.Dispatcher;
    using System.Runtime; 
    using System.ServiceModel.Description; 
    using System.ServiceModel.Configuration;
    using System.ServiceModel.Security; 
    using System.Xml;
    using SR2 = System.ServiceModel.Routing.SR;

    public class SoapProcessingBehavior : IEndpointBehavior 
    {
        const string IncomingViaName = "IncomingVia"; 
        const string IncomingHttpRequestName = "IncomingHttpRequest"; 

        public SoapProcessingBehavior() 
        {
            this.ProcessMessages = true;
        }
 
        public bool ProcessMessages
        { 
            get; 
            set;
        } 

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        } 

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
        { 
            if (endpoint == null)
            { 
                throw FxTrace.Exception.ArgumentNull("endpoint");
            }

            if (this.ProcessMessages) 
            {
                SoapProcessingInspector inspector = new SoapProcessingInspector(endpoint, clientRuntime); 
                clientRuntime.MessageInspectors.Add(inspector); 
                clientRuntime.CallbackDispatchRuntime.MessageInspectors.Add(inspector);
                foreach (ClientOperation clientOp in clientRuntime.Operations) 
                {
                    clientOp.ParameterInspectors.Add(inspector);
                }
            } 
        }
 
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
        {
            throw FxTrace.Exception.AsError(new NotSupportedException(SR2.MarshalingBehaviorNotSupported)); 
        }

        public void Validate(ServiceEndpoint endpoint)
        { 
        }
 
        class SoapProcessingInspector : IClientMessageInspector, IDispatchMessageInspector, IParameterInspector 
        {
            static HashSet addressingHeadersToFlow = InitializeHeadersToFlow(); 

            bool manualAddressing;
            MessageVersion sourceMessageVersion;
            MessageVersion sendMessageVersion; 

            public SoapProcessingInspector(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
            { 
                Fx.Assert(endpoint != null, "endpoint cannot be null");
                this.sendMessageVersion = endpoint.Binding.MessageVersion; 
                this.manualAddressing = clientRuntime.ManualAddressing;
            }

            void IParameterInspector.AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) 
            {
                // This call occurs AFTER IClientMessageInspector.AfterReceiveReply. 
                // We don't need to do any additional marshaling here. 
            }
 
            object IParameterInspector.BeforeCall(string operationName, object[] inputs)
            {
                if (inputs == null || inputs.Length == 0)
                { 
                    throw FxTrace.Exception.ArgumentNullOrEmpty("inputs");
                } 
 
                //We have to remove some addressing headers to avoid errors before the
                //Soap Processing MessageInspector gets called.  See CSDMain 117167. 
                Message request = (Message)inputs[0];
                this.PreProcess(request);
                return null;
            } 

            void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState) 
            { 
                if (reply != null)
                { 
                    Message originalMessage = (Message)correlationState;
                    MessageHeaders originalHeaders = originalMessage.Headers;
                    Uri to = originalHeaders.To;
                    MessageVersion version = originalMessage.Version; 
                    reply = MarshalMessage(reply, to, version);
 
                    //BasicHttpContext looks at the original request message when 
                    //constructing the Set-Cookie header, need to put these back.
                    Uri incomingVia; 
                    MessageProperties originalProperties = originalMessage.Properties;
                    if (originalProperties.TryGetValue(IncomingViaName, out incomingVia))
                    {
                        originalProperties.Via = incomingVia; 
                    }
                    object incomingHttpRequest; 
                    if (originalProperties.TryGetValue(IncomingHttpRequestName, out incomingHttpRequest)) 
                    {
                        originalProperties[HttpRequestMessageProperty.Name] = incomingHttpRequest; 
                    }

                    //Reponses from BasicHttp (Addressing.None) don't have any action.  If we're marshaling
                    //to any addressing version other than none, we create a ReplyAction here 
                    MessageHeaders replyHeaders = reply.Headers;
                    if (replyHeaders.Action == null && 
                        version.Addressing != AddressingVersion.None && 
                        originalHeaders.Action != null)
                    { 
                        replyHeaders.Action = originalHeaders.Action + "Response";
                    }
                }
            } 

            object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel) 
            { 
                Message originalRequest = request;
                if (this.sourceMessageVersion == null) 
                {
                    this.sourceMessageVersion = originalRequest.Version;
                }
                request = MarshalMessage(request, request.Headers.To, sendMessageVersion); 
                return originalRequest;
            } 
 
            object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
            { 
                request = MarshalMessage(request, request.Headers.To, this.sourceMessageVersion);
                return null;
            }
 
            void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
            { 
                if (reply != null) 
                {
                    reply = MarshalMessage(reply, reply.Headers.To, sendMessageVersion); 
                }
            }

            static HashSet InitializeHeadersToFlow() 
            {
                HashSet headersToFlow = new HashSet(StringComparer.Ordinal); 
                headersToFlow.Add("Action"); 
                headersToFlow.Add("MessageID");
                headersToFlow.Add("RelatesTo"); 
                headersToFlow.Add("To");
                return headersToFlow;
            }
 
            void PreProcess(Message message)
            { 
                //If the user does not have manual addressing enabled then clear these out 
                if (!this.manualAddressing)
                { 
                    MessageHeaders headers = message.Headers;
                    string addressingNamespace = RoutingUtilities.GetAddressingNamespace(headers.MessageVersion.Addressing);

                    //Go through in reverse to reduce shifting after RemoveAt(i) 
                    for (int i = headers.Count - 1; i >= 0; --i)
                    { 
                        MessageHeaderInfo header = headers[i]; 
                        if (string.Equals(header.Namespace, addressingNamespace, StringComparison.Ordinal))
                        { 
                            if (!addressingHeadersToFlow.Contains(header.Name))
                            {
                                headers.RemoveAt(i);
                            } 
                        }
                    } 
                } 
            }
 
            internal Message MarshalMessage(Message source, Uri to, MessageVersion targetVersion)
            {
                Message result;
                MessageHeaders sourceHeaders = source.Headers; 
                MessageVersion sourceVersion = source.Version;
                UnderstoodHeaders understoodHeaders = sourceHeaders.UnderstoodHeaders; 
                HashSet understoodHeadersSet = CreateKeys(understoodHeaders); 

#if DEBUG_MARSHALING 
                System.Text.StringBuilder details = new System.Text.StringBuilder();
                details.AppendFormat("Original Message:\r\n{0}\r\n", source);
                details.AppendLine("Understood Headers:");
                foreach (MessageHeaderInfo understoodHeader in understoodHeaders) 
                {
                    details.AppendFormat("\t{0}\t({1})\r\n", understoodHeader.Name, understoodHeader.Namespace); 
                } 
                details.AppendLine("Properties:");
                foreach (KeyValuePair item in source.Properties) 
                {
                    details.AppendFormat("\t{0}\t({1})\r\n", item.Key, item.Value);
                }
#endif //DEBUG_MARSHALING 

 
                //if we've understood and verified the security of the message, we need to create a new message 
                if (sourceVersion == targetVersion && !RoutingUtilities.IsMessageUsingWSSecurity(understoodHeaders))
                { 
                    FilterHeaders(sourceHeaders, understoodHeadersSet);
                    FilterProperties(source.Properties);
                    result = source;
                } 
                else
                { 
                    if (source.IsFault) 
                    {
                        MessageFault messageFault = MessageFault.CreateFault(source, int.MaxValue); 
                        string action = sourceHeaders.Action;
                        if (string.Equals(action, sourceVersion.Addressing.DefaultFaultAction, StringComparison.Ordinal))
                        {
                            //The action was the default for the sourceVersion set it to the default for the targetVersion. 
                            action = targetVersion.Addressing.DefaultFaultAction;
                        } 
                        result = Message.CreateMessage(targetVersion, messageFault, action); 
                    }
                    else if (source.IsEmpty) 
                    {
                        result = Message.CreateMessage(targetVersion, sourceHeaders.Action);
                    }
                    else 
                    {
                        XmlDictionaryReader bodyReader = source.GetReaderAtBodyContents(); 
                        result = Message.CreateMessage(targetVersion, sourceHeaders.Action, bodyReader); 
                    }
 
                    CloneHeaders(result.Headers, sourceHeaders, to, understoodHeadersSet);
                    CloneProperties(result.Properties, source.Properties);
                }
 
#if DEBUG_MARSHALING
                details.AppendFormat("\r\nMarshaled Message:\r\n{0}\r\n", result); 
                details.AppendLine("Properties:"); 
                foreach (KeyValuePair item in result.Properties)
                { 
                    details.AppendFormat("\t{0}\t({1})\r\n", item.Key, item.Value);
                }
                System.Diagnostics.Trace.WriteLine(details);
                TD.RoutingServiceDisplayConfig(details.ToString(), ""); 
#endif //DEBUG_MARSHALING
 
                return result; 
            }
 
            static HashSet CreateKeys(UnderstoodHeaders headers)
            {
                HashSet toReturn = new HashSet();
                foreach (MessageHeaderInfo header in headers) 
                {
                    toReturn.Add(MessageHeaderKey(header)); 
                } 
                return toReturn;
            } 

            static string MessageHeaderKey(MessageHeaderInfo header)
            {
                return header.Name + "+" + header.Namespace; 
            }
 
            void FilterHeaders(MessageHeaders headers, HashSet understoodHeadersSet) 
            {
                string addressingNamespace = RoutingUtilities.GetAddressingNamespace(headers.MessageVersion.Addressing); 

                //Go in reverse to reduce shifting after RemoveAt(i)
                for (int i = headers.Count - 1; i >= 0; --i)
                { 
                    MessageHeaderInfo header = headers[i];
                    bool removeHeader = false; 
 
                    if (string.Equals(header.Namespace, addressingNamespace, StringComparison.Ordinal) &&
                        (addressingHeadersToFlow.Contains(header.Name) || this.manualAddressing)) 
                    {
                        continue;
                    }
 
                    if (understoodHeadersSet.Contains(MessageHeaderKey(header)))
                    { 
                        // This header was understood at this endpoint, do _not_ flow it 
                        removeHeader = true;
                    } 
                    else if (ActorIsNextDestination(header, headers.MessageVersion))
                    {
                        //This was a header targeted at the SOAP Intermediary ("actor/next", which is us)
                        //It can explicitly tell us to relay this header when we don't understand it. 
                        if (!header.Relay)
                        { 
                            removeHeader = true; 
                        }
                    } 

                    if (removeHeader)
                    {
                        headers.RemoveAt(i); 
                    }
                } 
            } 

            static bool ActorIsNextDestination(MessageHeaderInfo header, MessageVersion messageVersion) 
            {
                return (header.Actor != null && string.Equals(header.Actor, messageVersion.Envelope.NextDestinationActorValue));
            }
 
            void CloneHeaders(MessageHeaders targetHeaders, MessageHeaders sourceHeaders, Uri to, HashSet understoodHeadersSet)
            { 
                for (int i = 0; i < sourceHeaders.Count; ++i) 
                {
                    MessageHeaderInfo header = sourceHeaders[i]; 
                    if (!understoodHeadersSet.Contains(MessageHeaderKey(header)))
                    {
                        //If Actor is SOAP Intermediary ("*actor/next" which is us) check the Relay flag
                        if (!ActorIsNextDestination(header, sourceHeaders.MessageVersion) || header.Relay) 
                        {
                            //Always wrap the header because BufferedHeader isn't smart enough to allow custom 
                            //headers to switch message versions 
                            MessageHeader messageHeader = new DelegatingHeader(header, sourceHeaders);
                            targetHeaders.Add(messageHeader); 
                        }
                    }
                }
 
                // To and Action (already specified) are 'special' and may be set even with AddressingVersion.None
                targetHeaders.To = to; 
                if (targetHeaders.MessageVersion.Addressing != AddressingVersion.None) 
                {
                    //These are used as correlation IDs. Copy these regardless of manual addressing. 
                    targetHeaders.MessageId = sourceHeaders.MessageId;
                    targetHeaders.RelatesTo = sourceHeaders.RelatesTo;

                    if (this.manualAddressing) 
                    {
                        //These are addresses, only copy when ManualAddressing is enabled 
                        targetHeaders.FaultTo = sourceHeaders.FaultTo; 
                        targetHeaders.ReplyTo = sourceHeaders.ReplyTo;
                        targetHeaders.From = sourceHeaders.From; 
                    }
                }
            }
 
            static void CloneProperties(MessageProperties destination, MessageProperties source)
            { 
                MessageEncoder encoder = destination.Encoder; 
                destination.CopyProperties(source);
                destination.Encoder = encoder; 
                FilterProperties(destination);
            }

            static void FilterProperties(MessageProperties destination) 
            {
                // We have the clear out the HTTP Req/Resp props, so we don't accidentally 
                // tell the outbound binding to use whatever Content-Type/Method/QueryString 
                // that the inboudnd message/response used.  Otherwise BasicHttp<->WsHttp won't work.
                object incomingHttpRequest; 
                if (destination.TryGetValue(HttpRequestMessageProperty.Name, out incomingHttpRequest))
                {
                    //Store the inbound value for later retoration
                    destination[IncomingHttpRequestName] = incomingHttpRequest; 
                    destination.Remove(HttpRequestMessageProperty.Name);
                } 
                destination.Remove(HttpResponseMessageProperty.Name); 

                //Preserve the Via on the outbound message, HTTP Context using cookies looks at this value 
                //on the original request when sending the response "Set-Cookie" header.
                Uri incomingVia = destination.Via;
                if (incomingVia != null)
                { 
                    destination[IncomingViaName] = incomingVia;
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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