File: System\ServiceModel\Channels\CallbackContextMessageProperty.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.ServiceModel.Channels
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.IO;
    using System.Net;
    using System.Runtime.Serialization;
    using System.Threading;
    using System.Xml;
    using System.Runtime;
 
    [Serializable]
    public class CallbackContextMessageProperty : IMessageProperty
    {
        const string PropertyName = "CallbackContextMessageProperty";
 
        // these hold init data from ctors
        [NonSerializedAttribute]
        readonly EndpointAddress listenAddress;
        readonly IDictionary<string, string> context;
 
        // used to cache "assembled" EndpointAddress that contains context property
        [NonSerializedAttribute]
        EndpointAddress callbackAddress;
 
        // if this constructor is used, the listen address will have to be provided later by setting it in the ContextBindingElement
        // CallbackContextMessageProperty will flow on the wire only if listenaddress is set.
        public CallbackContextMessageProperty(IDictionary<string, string> context)
            : this((EndpointAddress)null, context)
        {
        }
 
        public CallbackContextMessageProperty(string listenAddress, IDictionary<string, string> context)
            : this(new Uri(listenAddress), context)
        {
        }
 
        public CallbackContextMessageProperty(Uri listenAddress, IDictionary<string, string> context)
            : this(new EndpointAddress(listenAddress), context)
        {
        }
 
        public CallbackContextMessageProperty(EndpointAddress listenAddress, IDictionary<string, string> context)
        {
            if (listenAddress != null && listenAddress.Headers.FindHeader(ContextMessageHeader.ContextHeaderName, ContextMessageHeader.ContextHeaderNamespace) != null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.ListenAddressAlreadyContainsContext));
            }
            this.listenAddress = listenAddress;
            this.context = context;
        }
 
        public CallbackContextMessageProperty(EndpointAddress callbackAddress)
        {
            if (callbackAddress == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackAddress");
            }
            this.callbackAddress = callbackAddress;
        }
 
        public static string Name
        {
            get
            {
                return PropertyName;
            }
        }
 
        public EndpointAddress CallbackAddress
        {
            get
            {
                if (this.callbackAddress == null && this.listenAddress != null)
                {
                    this.callbackAddress = CreateCallbackAddress(this.listenAddress, this.context);
                }
                return this.callbackAddress;
            }
        }
 
        public IDictionary<string, string> Context
        {
            get
            {
                return this.context;
            }
        }
 
        public EndpointAddress CreateCallbackAddress(Uri listenAddress)
        {
            if (listenAddress == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("listenAddress");
            }
 
            return CreateCallbackAddress(new EndpointAddress(listenAddress), this.context);
        }
 
        static EndpointAddress CreateCallbackAddress(EndpointAddress listenAddress, IDictionary<string, string> context)
        {
            if (listenAddress == null)
            {
                return null;
            }
 
            EndpointAddressBuilder builder = new EndpointAddressBuilder(listenAddress);
            if (context != null)
            {
                builder.Headers.Add(new ContextAddressHeader(context));
            }
            return builder.ToEndpointAddress();
        }
 
        public static bool TryGet(Message message, out CallbackContextMessageProperty contextMessageProperty)
        {
            if (message == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
            }
 
            return TryGet(message.Properties, out contextMessageProperty);
        }
 
        public static bool TryGet(MessageProperties properties, out CallbackContextMessageProperty contextMessageProperty)
        {
            if (properties == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties");
            }
 
            object value = null;
            if (properties.TryGetValue(PropertyName, out value))
            {
                contextMessageProperty = value as CallbackContextMessageProperty;
            }
            else
            {
                contextMessageProperty = null;
            }
 
            return contextMessageProperty != null;
        }
 
        public void AddOrReplaceInMessage(Message message)
        {
            if (message == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
            }
 
            this.AddOrReplaceInMessageProperties(message.Properties);
        }
 
        public void AddOrReplaceInMessageProperties(MessageProperties properties)
        {
            if (properties == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties");
            }
 
            properties[PropertyName] = this;
        }
 
        public IMessageProperty CreateCopy()
        {
            if (this.callbackAddress != null)
            {
                return new CallbackContextMessageProperty(this.callbackAddress);
            }
            else
            {
                return new CallbackContextMessageProperty(this.listenAddress, this.context);
            }
        }
 
        [SuppressMessage(FxCop.Category.Design, FxCop.Rule.AvoidOutParameters,
            Justification = "The method needs to return two objects with one parsing")]
        public void GetListenAddressAndContext(out EndpointAddress listenAddress, out IDictionary<string, string> context)
        {
            // we expect the callback address to be already set when this is called
            if (this.CallbackAddress == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackaddress");
            }
            EndpointAddressBuilder builder = new EndpointAddressBuilder(this.CallbackAddress);
            AddressHeader contextHeader = null;
            int contextHeaderIndex = -1;
            for (int i = 0; i < builder.Headers.Count; ++i)
            {
                if (builder.Headers[i].Name == ContextMessageHeader.ContextHeaderName && builder.Headers[i].Namespace == ContextMessageHeader.ContextHeaderNamespace)
                {
                    if (contextHeader != null)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.MultipleContextHeadersFoundInCallbackAddress)));
                    }
                    contextHeader = builder.Headers[i];
                    contextHeaderIndex = i;
                }
            }
            if (contextHeader != null)
            {
                builder.Headers.RemoveAt(contextHeaderIndex);
            }
            context = (contextHeader != null) ? ContextMessageHeader.ParseContextHeader(contextHeader.GetAddressHeaderReader()).Context : null;
            listenAddress = builder.ToEndpointAddress();
        }
    }
}