File: System\ServiceModel\Security\ScopedMessagePartSpecification.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.Xml;
 
namespace System.ServiceModel.Security
{
    public class ScopedMessagePartSpecification
    {
        private Dictionary<string, MessagePartSpecification> _actionParts;
        private Dictionary<string, MessagePartSpecification> _readOnlyNormalizedActionParts;
 
        public ScopedMessagePartSpecification()
        {
            ChannelParts = new MessagePartSpecification();
            _actionParts = new Dictionary<string, MessagePartSpecification>();
        }
 
        public ICollection<string> Actions
        {
            get
            {
                return _actionParts.Keys;
            }
        }
 
        public MessagePartSpecification ChannelParts { get; }
 
        public bool IsReadOnly { get; private set; }
 
        public ScopedMessagePartSpecification(ScopedMessagePartSpecification other)
            : this()
        {
            if (other == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(other)));
            }
 
            ChannelParts.Union(other.ChannelParts);
            if (other._actionParts != null)
            {
                foreach (string action in other._actionParts.Keys)
                {
                    MessagePartSpecification p = new MessagePartSpecification();
                    p.Union(other._actionParts[action]);
                    _actionParts[action] = p;
                }
            }
        }
 
        internal ScopedMessagePartSpecification(ScopedMessagePartSpecification other, bool newIncludeBody)
            : this(other)
        {
            ChannelParts.IsBodyIncluded = newIncludeBody;
            foreach (string action in _actionParts.Keys)
            {
                _actionParts[action].IsBodyIncluded = newIncludeBody;
            }
        }
 
        public void AddParts(MessagePartSpecification parts)
        {
            if (parts == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(parts)));
            }
 
            ThrowIfReadOnly();
 
            ChannelParts.Union(parts);
        }
 
        public void AddParts(MessagePartSpecification parts, string action)
        {
            if (action == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(action)));
            }
 
            if (parts == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(parts)));
            }
 
            ThrowIfReadOnly();
 
            if (!_actionParts.ContainsKey(action))
            {
                _actionParts[action] = new MessagePartSpecification();
            }
 
            _actionParts[action].Union(parts);
        }
 
        internal void AddParts(MessagePartSpecification parts, XmlDictionaryString action)
        {
            if (action == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(action)));
            }
 
            AddParts(parts, action.Value);
        }
 
        internal bool IsEmpty()
        {
            bool result;
            if (!ChannelParts.IsEmpty())
            {
                result = false;
            }
            else
            {
                result = true;
                foreach (string action in Actions)
                {
                    MessagePartSpecification parts;
                    if (TryGetParts(action, true, out parts))
                    {
                        if (!parts.IsEmpty())
                        {
                            result = false;
                            break;
                        }
                    }
                }
            }
 
            return result;
        }
 
        public bool TryGetParts(string action, bool excludeChannelScope, out MessagePartSpecification parts)
        {
            if (action == null)
            {
                action = MessageHeaders.WildcardAction;
            }
 
            parts = null;
 
            if (IsReadOnly)
            {
                if (_readOnlyNormalizedActionParts.ContainsKey(action))
                {
                    if (excludeChannelScope)
                    {
                        parts = _actionParts[action];
                    }
                    else
                    {
                        parts = _readOnlyNormalizedActionParts[action];
                    }
                }
            }
            else if (_actionParts.ContainsKey(action))
            {
                MessagePartSpecification p = new MessagePartSpecification();
                p.Union(_actionParts[action]);
                if (!excludeChannelScope)
                {
                    p.Union(ChannelParts);
                }
 
                parts = p;
            }
 
            return parts != null;
        }
 
        internal void CopyTo(ScopedMessagePartSpecification target)
        {
            if (target == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(target));
            }
            target.ChannelParts.IsBodyIncluded = ChannelParts.IsBodyIncluded;
            foreach (XmlQualifiedName headerType in ChannelParts.HeaderTypes)
            {
                if (!target.ChannelParts.IsHeaderIncluded(headerType.Name, headerType.Namespace))
                {
                    target.ChannelParts.HeaderTypes.Add(headerType);
                }
            }
            foreach (string action in _actionParts.Keys)
            {
                target.AddParts(_actionParts[action], action);
            }
        }
 
        public bool TryGetParts(string action, out MessagePartSpecification parts)
        {
            return TryGetParts(action, false, out parts);
        }
 
        public void MakeReadOnly()
        {
            if (!IsReadOnly)
            {
                _readOnlyNormalizedActionParts = new Dictionary<string, MessagePartSpecification>();
                foreach (string action in _actionParts.Keys)
                {
                    MessagePartSpecification p = new MessagePartSpecification();
                    p.Union(_actionParts[action]);
                    p.Union(ChannelParts);
                    p.MakeReadOnly();
                    _readOnlyNormalizedActionParts[action] = p;
                }
                IsReadOnly = true;
            }
        }
 
        private void ThrowIfReadOnly()
        {
            if (IsReadOnly)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRP.ObjectIsReadOnly));
            }
        }
    }
}