File: System\ServiceModel\Description\OperationDescription.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.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
 
namespace System.ServiceModel.Description
{
    [DebuggerDisplay("Name={XmlName}, IsInitiating={IsInitiating}, IsTerminating={IsTerminating}")]
    public class OperationDescription
    {
        internal const string SessionOpenedAction = "http://schemas.microsoft.com/2011/02/session/onopen"; // Copied from WebSocketTransportSettings.ConnectionOpenedAction;
        private bool _isSessionOpenNotificationEnabled;
        private ContractDescription _declaringContract;
        private MethodInfo _taskMethod;
        private bool _hasNoDisposableParameters;
 
        public OperationDescription(string name, ContractDescription declaringContract)
        {
            if (name == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(name));
            }
            if (name.Length == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException(nameof(name), SRP.SFxOperationDescriptionNameCannotBeEmpty));
            }
            XmlName = new XmlName(name, true /*isEncoded*/);
            _declaringContract = declaringContract ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(declaringContract));
            IsInitiating = true;
            IsTerminating = false;
            Faults = new FaultDescriptionCollection();
            Messages = new MessageDescriptionCollection();
            Behaviors = new KeyedByTypeCollection<IOperationBehavior>();
            KnownTypes = new Collection<Type>();
        }
 
        internal OperationDescription(string name, ContractDescription declaringContract, bool validateRpcWrapperName)
            : this(name, declaringContract)
        {
            IsValidateRpcWrapperName = validateRpcWrapperName;
        }
 
        public KeyedCollection<Type, IOperationBehavior> OperationBehaviors
        {
            get { return Behaviors; }
        }
 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public KeyedByTypeCollection<IOperationBehavior> Behaviors { get; }
 
        // Not serializable on purpose, metadata import/export cannot
        // produce it, only available when binding to runtime
        public MethodInfo TaskMethod
        {
            get { return _taskMethod; }
            set { _taskMethod = value; }
        }
 
        // Not serializable on purpose, metadata import/export cannot
        // produce it, only available when binding to runtime
        public MethodInfo SyncMethod { get; set; }
 
        // Not serializable on purpose, metadata import/export cannot
        // produce it, only available when binding to runtime
        public MethodInfo BeginMethod { get; set; }
 
        internal MethodInfo OperationMethod
        {
            get
            {
                if (SyncMethod == null)
                {
                    return TaskMethod ?? BeginMethod;
                }
                else
                {
                    return SyncMethod;
                }
            }
        }
 
 
        internal bool HasNoDisposableParameters
        {
            get { return _hasNoDisposableParameters; }
            set { _hasNoDisposableParameters = value; }
        }
 
        // Not serializable on purpose, metadata import/export cannot
        // produce it, only available when binding to runtime
        public MethodInfo EndMethod { get; set; }
 
        public ContractDescription DeclaringContract
        {
            get { return _declaringContract; }
            set
            {
                if (value == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(DeclaringContract));
                }
                else
                {
                    _declaringContract = value;
                }
            }
        }
 
        public FaultDescriptionCollection Faults { get; }
 
        public bool IsOneWay
        {
            get { return Messages.Count == 1; }
        }
 
        public bool IsInitiating { get; set; }
 
        internal bool IsServerInitiated()
        {
            EnsureInvariants();
            return Messages[0].Direction == MessageDirection.Output;
        }
 
        public bool IsTerminating { get; set; }
 
        public Collection<Type> KnownTypes { get; }
 
        // Messages[0] is the 'request' (first of MEP), and for non-oneway MEPs, Messages[1] is the 'response' (second of MEP)
        public MessageDescriptionCollection Messages { get; }
 
        internal XmlName XmlName { get; }
 
        internal string CodeName
        {
            get { return XmlName.DecodedName; }
        }
 
        public string Name
        {
            get { return XmlName.EncodedName; }
        }
 
        internal bool IsValidateRpcWrapperName { get; } = true;
 
        internal Type TaskTResult
        {
            get;
            set;
        }
 
        internal bool HasOutputParameters
        {
            get
            {
                // For non-oneway operations, Messages[1] is the 'response'
                return (Messages.Count > 1) &&
                    (Messages[1].Body.Parts.Count > 0);
            }
        }
 
        internal bool IsSessionOpenNotificationEnabled
        {
            get { return _isSessionOpenNotificationEnabled; }
            set { _isSessionOpenNotificationEnabled = value; }
        }
 
        internal void EnsureInvariants()
        {
            if (Messages.Count != 1 && Messages.Count != 2)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRP.Format(SRP.SFxOperationMustHaveOneOrTwoMessages, Name)));
            }
        }
    }
}