File: FrameworkFork\System.ServiceModel\System\ServiceModel\Channels\TransactionFlowBindingElement.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// 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.
 
namespace System.ServiceModel.Channels
{
    using System;
    using System.ServiceModel.Description;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Security;
    using System.ComponentModel;
    //using System.ServiceModel.Transactions;
    using Microsoft.Xml;
 
    public sealed class TransactionFlowBindingElement : BindingElement
    {
        private bool _transactions;
        private TransactionFlowOption _issuedTokens;
        private TransactionProtocol _transactionProtocol;
 
        public TransactionFlowBindingElement()
            : this(true, TransactionFlowDefaults.TransactionProtocol)
        {
        }
 
        public TransactionFlowBindingElement(TransactionProtocol transactionProtocol)
            : this(true, transactionProtocol)
        {
        }
 
        internal TransactionFlowBindingElement(bool transactions)
            : this(transactions, TransactionFlowDefaults.TransactionProtocol)
        {
        }
 
        internal TransactionFlowBindingElement(bool transactions, TransactionProtocol transactionProtocol)
        {
            _transactions = transactions;
            _issuedTokens = transactions ? TransactionFlowOption.Allowed : TransactionFlowOption.NotAllowed;
 
            if (!TransactionProtocol.IsDefined(transactionProtocol))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(string.Format(SRServiceModel.ConfigInvalidTransactionFlowProtocolValue, transactionProtocol.ToString()));
            }
 
            _transactionProtocol = transactionProtocol;
        }
 
        private TransactionFlowBindingElement(TransactionFlowBindingElement elementToBeCloned)
            : base(elementToBeCloned)
        {
            _transactions = elementToBeCloned._transactions;
            _issuedTokens = elementToBeCloned._issuedTokens;
 
            if (!TransactionProtocol.IsDefined(elementToBeCloned._transactionProtocol))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(string.Format(SRServiceModel.ConfigInvalidTransactionFlowProtocolValue, elementToBeCloned._transactionProtocol.ToString()));
            }
 
            _transactionProtocol = elementToBeCloned._transactionProtocol;
            this.AllowWildcardAction = elementToBeCloned.AllowWildcardAction;
        }
 
        internal bool Transactions
        {
            get
            {
                return _transactions;
            }
            set
            {
                _transactions = value;
                _issuedTokens = value ? TransactionFlowOption.Allowed : TransactionFlowOption.NotAllowed;
            }
        }
 
        internal TransactionFlowOption IssuedTokens
        {
            get
            {
                return _issuedTokens;
            }
            set
            {
                ValidateOption(value);
                _issuedTokens = value;
            }
        }
 
        public override BindingElement Clone()
        {
            return new TransactionFlowBindingElement(this);
        }
 
        private bool IsFlowEnabled(Dictionary<DirectionalAction, TransactionFlowOption> dictionary)
        {
            if (_issuedTokens != TransactionFlowOption.NotAllowed)
            {
                return true;
            }
 
            if (!_transactions)
            {
                return false;
            }
 
            foreach (TransactionFlowOption option in dictionary.Values)
            {
                if (option != TransactionFlowOption.NotAllowed)
                {
                    return true;
                }
            }
 
            return false;
        }
 
        internal bool IsFlowEnabled(ContractDescription contract)
        {
            if (_issuedTokens != TransactionFlowOption.NotAllowed)
            {
                return true;
            }
 
            if (!_transactions)
            {
                return false;
            }
 
            foreach (OperationDescription operation in contract.Operations)
            {
                TransactionFlowAttribute parameter = operation.Behaviors.Find<TransactionFlowAttribute>();
                if (parameter != null)
                {
                    if (parameter.Transactions != TransactionFlowOption.NotAllowed)
                    {
                        return true;
                    }
                }
            }
 
            return false;
        }
 
        public TransactionProtocol TransactionProtocol
        {
            get
            {
                return _transactionProtocol;
            }
            set
            {
                if (!TransactionProtocol.IsDefined(value))
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                _transactionProtocol = value;
            }
        }
 
        [DefaultValue(false)]
        public bool AllowWildcardAction
        {
            get;
            set;
        }
 
        internal static void ValidateOption(TransactionFlowOption opt)
        {
            if (!TransactionFlowOptionHelper.IsDefined(opt))
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(string.Format(SRServiceModel.TransactionFlowBadOption)));
        }
 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeTransactionProtocol()
        {
            return this.TransactionProtocol != TransactionProtocol.Default;
        }
 
        public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
        {
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("context"));
            }
 
            if (typeof(TChannel) == typeof(IOutputChannel)
                || typeof(TChannel) == typeof(IDuplexChannel)
                || typeof(TChannel) == typeof(IRequestChannel)
                || typeof(TChannel) == typeof(IOutputSessionChannel)
                || typeof(TChannel) == typeof(IRequestSessionChannel)
                || typeof(TChannel) == typeof(IDuplexSessionChannel))
            {
                return context.CanBuildInnerChannelFactory<TChannel>();
            }
 
            return false;
        }
 
        private Dictionary<DirectionalAction, TransactionFlowOption> GetDictionary(BindingContext context)
        {
            Dictionary<DirectionalAction, TransactionFlowOption> dictionary =
                context.BindingParameters.Find<Dictionary<DirectionalAction, TransactionFlowOption>>();
            if (dictionary == null)
                dictionary = new Dictionary<DirectionalAction, TransactionFlowOption>();
            return dictionary;
        }
 
        internal static MessagePartSpecification GetIssuedTokenHeaderSpecification(SecurityStandardsManager standardsManager)
        {
            MessagePartSpecification result;
 
            if (standardsManager.TrustDriver.IsIssuedTokensSupported)
                result = new MessagePartSpecification(new XmlQualifiedName(standardsManager.TrustDriver.IssuedTokensHeaderName, standardsManager.TrustDriver.IssuedTokensHeaderNamespace));
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(SRServiceModel.TrustDriverVersionDoesNotSupportIssuedTokens)));
            }
 
            return result;
        }
 
        public override T GetProperty<T>(BindingContext context)
        {
            if (typeof(T) == typeof(ChannelProtectionRequirements))
            {
                ChannelProtectionRequirements myRequirements = this.GetProtectionRequirements();
                if (myRequirements != null)
                {
                    myRequirements.Add(context.GetInnerProperty<ChannelProtectionRequirements>() ?? new ChannelProtectionRequirements());
                    return (T)(object)myRequirements;
                }
                else
                {
                    return (T)(object)context.GetInnerProperty<ChannelProtectionRequirements>();
                }
            }
            else
            {
                return context.GetInnerProperty<T>();
            }
        }
 
        private ChannelProtectionRequirements GetProtectionRequirements()
        {
            if (this.Transactions || (this.IssuedTokens != TransactionFlowOption.NotAllowed))
            {
                ChannelProtectionRequirements requirements = new ChannelProtectionRequirements();
                if (this.Transactions)
                {
                    MessagePartSpecification p = new MessagePartSpecification(
                        new XmlQualifiedName(CoordinationExternalStrings.CoordinationContext, CoordinationExternal10Strings.Namespace),
                        new XmlQualifiedName(CoordinationExternalStrings.CoordinationContext, CoordinationExternal11Strings.Namespace),
                        new XmlQualifiedName(OleTxTransactionExternalStrings.OleTxTransaction, OleTxTransactionExternalStrings.Namespace));
                    p.MakeReadOnly();
                    requirements.IncomingSignatureParts.AddParts(p);
                    requirements.OutgoingSignatureParts.AddParts(p);
                    requirements.IncomingEncryptionParts.AddParts(p);
                    requirements.OutgoingEncryptionParts.AddParts(p);
                }
                if (this.IssuedTokens != TransactionFlowOption.NotAllowed)
                {
                    MessagePartSpecification trustParts = GetIssuedTokenHeaderSpecification(SecurityStandardsManager.DefaultInstance);
                    trustParts.MakeReadOnly();
                    requirements.IncomingSignatureParts.AddParts(trustParts);
                    requirements.IncomingEncryptionParts.AddParts(trustParts);
                    requirements.OutgoingSignatureParts.AddParts(trustParts);
                    requirements.OutgoingEncryptionParts.AddParts(trustParts);
                }
 
                MessagePartSpecification body = new MessagePartSpecification(true);
                body.MakeReadOnly();
                requirements.OutgoingSignatureParts.AddParts(body, FaultCodeConstants.Actions.Transactions);
                requirements.OutgoingEncryptionParts.AddParts(body, FaultCodeConstants.Actions.Transactions);
                return requirements;
            }
            else
            {
                return null;
            }
        }
 
        private XmlElement GetAssertion(XmlDocument doc, TransactionFlowOption option, string prefix, string name, string ns, string policyNs)
        {
            if (doc == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("doc");
 
            XmlElement result = null;
            switch (option)
            {
                case TransactionFlowOption.NotAllowed:
                    // Don't generate an assertion
                    break;
 
                case TransactionFlowOption.Allowed:
                    result = doc.CreateElement(prefix, name, ns);
 
                    // Always insert the real wsp:Optional attribute
                    XmlAttribute attr = doc.CreateAttribute(TransactionPolicyStrings.OptionalPrefix11,
                        TransactionPolicyStrings.OptionalLocal, policyNs);
                    attr.Value = TransactionPolicyStrings.TrueValue;
                    result.Attributes.Append(attr);
 
                    // For legacy protocols, also insert the legacy attribute for backward compat
                    if (_transactionProtocol == TransactionProtocol.OleTransactions ||
                        _transactionProtocol == TransactionProtocol.WSAtomicTransactionOctober2004)
                    {
                        XmlAttribute attrLegacy = doc.CreateAttribute(TransactionPolicyStrings.OptionalPrefix10,
                            TransactionPolicyStrings.OptionalLocal, TransactionPolicyStrings.OptionalNamespaceLegacy);
                        attrLegacy.Value = TransactionPolicyStrings.TrueValue;
                        result.Attributes.Append(attrLegacy);
                    }
                    break;
 
                case TransactionFlowOption.Mandatory:
                    result = doc.CreateElement(prefix, name, ns);
                    break;
            }
            return result;
        }
 
        internal override bool IsMatch(BindingElement b)
        {
            if (b == null)
                return false;
            TransactionFlowBindingElement txFlow = b as TransactionFlowBindingElement;
            if (txFlow == null)
                return false;
            if (_transactions != txFlow._transactions)
                return false;
            if (_issuedTokens != txFlow._issuedTokens)
                return false;
            if (_transactionProtocol != txFlow._transactionProtocol)
                return false;
 
            return true;
        }
    }
}