//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Channels { using System.Collections.Generic; using System.Net.Security; using System.Runtime; using System.ServiceModel; using System.ServiceModel.Description; using System.Xml; public abstract class MsmqBindingElementBase : TransportBindingElement, ITransactedBindingElement, IWsdlExportExtension, IPolicyExportExtension, ITransportPolicyImport { Uri customDeadLetterQueue; DeadLetterQueue deadLetterQueue; bool durable; bool exactlyOnce; int maxRetryCycles; ReceiveErrorHandling receiveErrorHandling; int receiveRetryCount; TimeSpan retryCycleDelay; TimeSpan timeToLive; MsmqTransportSecurity msmqTransportSecurity; bool useMsmqTracing; bool useSourceJournal; bool receiveContextEnabled; internal MsmqBindingElementBase() { this.customDeadLetterQueue = MsmqDefaults.CustomDeadLetterQueue; this.deadLetterQueue = MsmqDefaults.DeadLetterQueue; this.durable = MsmqDefaults.Durable; this.exactlyOnce = MsmqDefaults.ExactlyOnce; this.maxRetryCycles = MsmqDefaults.MaxRetryCycles; this.receiveContextEnabled = MsmqDefaults.ReceiveContextEnabled; this.receiveErrorHandling = MsmqDefaults.ReceiveErrorHandling; this.receiveRetryCount = MsmqDefaults.ReceiveRetryCount; this.retryCycleDelay = MsmqDefaults.RetryCycleDelay; this.timeToLive = MsmqDefaults.TimeToLive; this.msmqTransportSecurity = new MsmqTransportSecurity(); this.useMsmqTracing = MsmqDefaults.UseMsmqTracing; this.useSourceJournal = MsmqDefaults.UseSourceJournal; this.ReceiveContextSettings = new MsmqReceiveContextSettings(); } internal MsmqBindingElementBase(MsmqBindingElementBase elementToBeCloned) : base(elementToBeCloned) { this.customDeadLetterQueue = elementToBeCloned.customDeadLetterQueue; this.deadLetterQueue = elementToBeCloned.deadLetterQueue; this.durable = elementToBeCloned.durable; this.exactlyOnce = elementToBeCloned.exactlyOnce; this.maxRetryCycles = elementToBeCloned.maxRetryCycles; this.msmqTransportSecurity = new MsmqTransportSecurity(elementToBeCloned.MsmqTransportSecurity); this.receiveContextEnabled = elementToBeCloned.ReceiveContextEnabled; this.receiveErrorHandling = elementToBeCloned.receiveErrorHandling; this.receiveRetryCount = elementToBeCloned.receiveRetryCount; this.retryCycleDelay = elementToBeCloned.retryCycleDelay; this.timeToLive = elementToBeCloned.timeToLive; this.useMsmqTracing = elementToBeCloned.useMsmqTracing; this.useSourceJournal = elementToBeCloned.useSourceJournal; // this.ReceiveContextSettings = elementToBeCloned.ReceiveContextSettings; } internal IReceiveContextSettings ReceiveContextSettings { get; set; } internal abstract MsmqUri.IAddressTranslator AddressTranslator { get; } // applicable on: client public Uri CustomDeadLetterQueue { get { return this.customDeadLetterQueue; } set { this.customDeadLetterQueue = value; } } // applicable on: client public DeadLetterQueue DeadLetterQueue { get { return this.deadLetterQueue; } set { if (! DeadLetterQueueHelper.IsDefined(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value")); } this.deadLetterQueue = value; } } // applicable on: client public bool Durable { get { return this.durable; } set { this.durable = value; } } public bool TransactedReceiveEnabled { get { return this.exactlyOnce; } } // applicable on: client, server public bool ExactlyOnce { get { return this.exactlyOnce; } set { this.exactlyOnce = value; } } // applicable on: server public int ReceiveRetryCount { get { return this.receiveRetryCount; } set { if (value < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentOutOfRangeException("value", value, SR.GetString(SR.MsmqNonNegativeArgumentExpected))); } this.receiveRetryCount = value; } } // applicable on: server public int MaxRetryCycles { get { return this.maxRetryCycles; } set { if (value < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentOutOfRangeException("value", value, SR.GetString(SR.MsmqNonNegativeArgumentExpected))); } this.maxRetryCycles = value; } } // applicable on: client, server public MsmqTransportSecurity MsmqTransportSecurity { get { return this.msmqTransportSecurity; } internal set { this.msmqTransportSecurity = value; } } // applicable on: server public bool ReceiveContextEnabled { get { return this.receiveContextEnabled; } set { this.receiveContextEnabled = value; } } // applicable on: server public ReceiveErrorHandling ReceiveErrorHandling { get { return this.receiveErrorHandling; } set { if (! ReceiveErrorHandlingHelper.IsDefined(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value")); } this.receiveErrorHandling = value; } } // applicable on: server public TimeSpan RetryCycleDelay { get { return this.retryCycleDelay; } set { if (value < TimeSpan.Zero) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString(SR.SFxTimeoutOutOfRange0))); } if (TimeoutHelper.IsTooLarge(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString(SR.SFxTimeoutOutOfRangeTooBig))); } this.retryCycleDelay = value; } } // applicable on: client public TimeSpan TimeToLive { get { return this.timeToLive; } set { if (value < TimeSpan.Zero) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString(SR.SFxTimeoutOutOfRange0))); } if (TimeoutHelper.IsTooLarge(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString(SR.SFxTimeoutOutOfRangeTooBig))); } this.timeToLive = value; } } public bool UseMsmqTracing { get { return this.useMsmqTracing; } set { this.useMsmqTracing = value; } } public bool UseSourceJournal { get { return this.useSourceJournal; } set { this.useSourceJournal = value; } } public TimeSpan ValidityDuration { get { return this.ReceiveContextSettings.ValidityDuration; } set { if (value < TimeSpan.Zero) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString(SR.SFxTimeoutOutOfRange0))); } if (TimeoutHelper.IsTooLarge(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString(SR.SFxTimeoutOutOfRangeTooBig))); } ((MsmqReceiveContextSettings)this.ReceiveContextSettings).SetValidityDuration(value); } } public override T GetProperty(BindingContext context) { if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } if (typeof(T) == typeof(ISecurityCapabilities)) { return null; } else if (typeof(T) == typeof(IBindingDeliveryCapabilities)) { return (T)(object)new BindingDeliveryCapabilitiesHelper(); } else if (typeof(T) == typeof(IReceiveContextSettings)) { // receive context is not supported over a non-transactional queue if (this.ExactlyOnce && this.ReceiveContextEnabled) { return (T)(object)this.ReceiveContextSettings; } else { return null; } } else if (typeof(T) == typeof(ITransactedBindingElement)) { return (T)(object)this; } else { return base.GetProperty(context); } } static bool FindAssertion(ICollection assertions, string name) { return (PolicyConversionContext.FindAssertion(assertions, name, TransportPolicyConstants.MsmqTransportNamespace, true) != null); } void IPolicyExportExtension.ExportPolicy(MetadataExporter exporter, PolicyConversionContext context) { if (exporter == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("exporter"); } if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } XmlDocument document = new XmlDocument(); ICollection policyAssertions = context.GetBindingAssertions(); if (!this.Durable) { policyAssertions.Add(document.CreateElement( TransportPolicyConstants.MsmqTransportPrefix, TransportPolicyConstants.MsmqVolatile, TransportPolicyConstants.MsmqTransportNamespace)); } if (!this.ExactlyOnce) { policyAssertions.Add(document.CreateElement( TransportPolicyConstants.MsmqTransportPrefix, TransportPolicyConstants.MsmqBestEffort, TransportPolicyConstants.MsmqTransportNamespace)); } if (context.Contract.SessionMode == SessionMode.Required) { policyAssertions.Add(document.CreateElement( TransportPolicyConstants.MsmqTransportPrefix, TransportPolicyConstants.MsmqSession, TransportPolicyConstants.MsmqTransportNamespace)); } if (this.MsmqTransportSecurity.MsmqProtectionLevel != ProtectionLevel.None) { policyAssertions.Add(document.CreateElement( TransportPolicyConstants.MsmqTransportPrefix, TransportPolicyConstants.MsmqAuthenticated, TransportPolicyConstants.MsmqTransportNamespace)); if (this.MsmqTransportSecurity.MsmqAuthenticationMode == MsmqAuthenticationMode.WindowsDomain) { policyAssertions.Add(document.CreateElement( TransportPolicyConstants.MsmqTransportPrefix, TransportPolicyConstants.MsmqWindowsDomain, TransportPolicyConstants.MsmqTransportNamespace)); } } bool createdNew; MessageEncodingBindingElement encodingBindingElement = FindMessageEncodingBindingElement(context.BindingElements, out createdNew); if (createdNew && encodingBindingElement is IPolicyExportExtension) { ((IPolicyExportExtension)encodingBindingElement).ExportPolicy(exporter, context); } WsdlExporter.WSAddressingHelper.AddWSAddressingAssertion(exporter, context, encodingBindingElement.MessageVersion.Addressing); } void ITransportPolicyImport.ImportPolicy(MetadataImporter importer, PolicyConversionContext policyContext) { ICollection policyAssertions = policyContext.GetBindingAssertions(); if (FindAssertion(policyAssertions, TransportPolicyConstants.MsmqVolatile)) { this.Durable = false; } if (FindAssertion(policyAssertions, TransportPolicyConstants.MsmqBestEffort)) { this.ExactlyOnce = false; } if (FindAssertion(policyAssertions, TransportPolicyConstants.MsmqSession)) { policyContext.Contract.SessionMode = SessionMode.Required; } if (FindAssertion(policyAssertions, TransportPolicyConstants.MsmqAuthenticated)) { this.MsmqTransportSecurity.MsmqProtectionLevel = ProtectionLevel.Sign; if (FindAssertion(policyAssertions, TransportPolicyConstants.MsmqWindowsDomain)) this.MsmqTransportSecurity.MsmqAuthenticationMode = MsmqAuthenticationMode.WindowsDomain; else this.MsmqTransportSecurity.MsmqAuthenticationMode = MsmqAuthenticationMode.Certificate; } else { this.MsmqTransportSecurity.MsmqProtectionLevel = ProtectionLevel.None; this.MsmqTransportSecurity.MsmqAuthenticationMode = MsmqAuthenticationMode.None; } } void IWsdlExportExtension.ExportContract(WsdlExporter exporter, WsdlContractConversionContext context) { } internal virtual string WsdlTransportUri { get { return null; } } void IWsdlExportExtension.ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext endpointContext) { bool createdNew; MessageEncodingBindingElement encodingBindingElement = FindMessageEncodingBindingElement(endpointContext, out createdNew); TransportBindingElement.ExportWsdlEndpoint( exporter, endpointContext, this.WsdlTransportUri, encodingBindingElement.MessageVersion.Addressing); } MessageEncodingBindingElement FindMessageEncodingBindingElement(BindingElementCollection bindingElements, out bool createdNew) { createdNew = false; MessageEncodingBindingElement encodingBindingElement = bindingElements.Find(); if (encodingBindingElement == null) { createdNew = true; encodingBindingElement = new BinaryMessageEncodingBindingElement(); } return encodingBindingElement; } MessageEncodingBindingElement FindMessageEncodingBindingElement(WsdlEndpointConversionContext endpointContext, out bool createdNew) { BindingElementCollection bindingElements = endpointContext.Endpoint.Binding.CreateBindingElements(); return FindMessageEncodingBindingElement(bindingElements, out createdNew); } class BindingDeliveryCapabilitiesHelper : IBindingDeliveryCapabilities { internal BindingDeliveryCapabilitiesHelper() { } bool IBindingDeliveryCapabilities.AssuresOrderedDelivery { get { return false; } } bool IBindingDeliveryCapabilities.QueuedDelivery { get { return true; } } } } }