//------------------------------------------------------------ // 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 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 context) : this((EndpointAddress)null, context) { } public CallbackContextMessageProperty(string listenAddress, IDictionary context) : this(new Uri(listenAddress), context) { } public CallbackContextMessageProperty(Uri listenAddress, IDictionary context) : this(new EndpointAddress(listenAddress), context) { } public CallbackContextMessageProperty(EndpointAddress listenAddress, IDictionary 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 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 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 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(); } } }