File: System\ServiceModel\DeliveryRequirementsAttribute.cs
Web Access
Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
 
namespace System.ServiceModel
{
    // This attribute specifies what the service implementation 
    // requires from the binding that dispatches messages.
    [AttributeUsage(ServiceModelAttributeTargets.ContractBehavior, AllowMultiple = true)]
    public sealed class DeliveryRequirementsAttribute : Attribute, IContractBehavior
    {
        private QueuedDeliveryRequirementsMode queuedDeliveryRequirements = QueuedDeliveryRequirementsMode.Allowed;
 
        // RequireQueuedDelivery: Validates that any binding associated
        // with the service/channel supports Queued
        // delivery.
        //
        // DisallowQueuedDelivery: Validates that no binding associated
        // with the service/channel supports Queued     
        // delivery.
        //
        // Ignore: Agnostic
        public QueuedDeliveryRequirementsMode QueuedDeliveryRequirements
        {
            get { return queuedDeliveryRequirements; }
            set
            {
                if (QueuedDeliveryRequirementsModeHelper.IsDefined(value))
                {
                    queuedDeliveryRequirements = value;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(value)));
                }
            }
        }
 
        // True: Validates that any binding associated
        // with the service/channel supports Ordered 
        // delivery. 
        //
        // False: Does no validation.
        public bool RequireOrderedDelivery { get; set; } = false;
 
        void IContractBehavior.Validate(ContractDescription description, ServiceEndpoint endpoint)
        {
            if (description == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(description));
            if (endpoint == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(endpoint));
 
            ValidateEndpoint(endpoint);
        }
 
        void IContractBehavior.AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, BindingParameterCollection parameters)
        {
        }
 
        void IContractBehavior.ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, ClientRuntime proxy)
        {
        }
 
        void IContractBehavior.ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime dispatch)
        {
        }
 
        private void ValidateEndpoint(ServiceEndpoint endpoint)
        {
            string name = endpoint.Contract.ContractType.Name;
            EnsureQueuedDeliveryRequirements(name, endpoint.Binding);
            EnsureOrderedDeliveryRequirements(name, endpoint.Binding);
        }
 
        private void EnsureQueuedDeliveryRequirements(string name, Binding binding)
        {
            if (QueuedDeliveryRequirements == QueuedDeliveryRequirementsMode.Required
                || QueuedDeliveryRequirements == QueuedDeliveryRequirementsMode.NotAllowed)
            {
                IBindingDeliveryCapabilities caps = binding.GetProperty<IBindingDeliveryCapabilities>(new BindingParameterCollection());
                if (caps == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                        SRP.Format(SRP.SinceTheBindingForDoesnTSupportIBindingCapabilities2_1, name)));
                }
                else
                {
                    bool queuedTransport = caps.QueuedDelivery;
                    if (QueuedDeliveryRequirements == QueuedDeliveryRequirementsMode.Required && !queuedTransport)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SRP.Format(SRP.BindingRequirementsAttributeRequiresQueuedDelivery1, name)));
                    }
                    else if (QueuedDeliveryRequirements == QueuedDeliveryRequirementsMode.NotAllowed && queuedTransport)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SRP.Format(SRP.BindingRequirementsAttributeDisallowsQueuedDelivery1, name)));
                    }
                }
            }
        }
 
        private void EnsureOrderedDeliveryRequirements(string name, Binding binding)
        {
            if (RequireOrderedDelivery)
            {
                IBindingDeliveryCapabilities caps = binding.GetProperty<IBindingDeliveryCapabilities>(new BindingParameterCollection());
                if (caps == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                        SRP.Format(SRP.SinceTheBindingForDoesnTSupportIBindingCapabilities1_1, name)));
                }
                else
                {
                    if (!caps.AssuresOrderedDelivery)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SRP.Format(SRP.TheBindingForDoesnTSupportOrderedDelivery1, name)));
                    }
                }
            }
        }
    }
}