//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Description { using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Net.Security; using System.Reflection; using System.ServiceModel.Security; [DebuggerDisplay("Name={name}, IsInitiating={isInitiating}, IsTerminating={isTerminating}")] public class OperationDescription { internal const string SessionOpenedAction = Channels.WebSocketTransportSettings.ConnectionOpenedAction; XmlName name; bool isInitiating; bool isTerminating; bool isSessionOpenNotificationEnabled; ContractDescription declaringContract; FaultDescriptionCollection faults; MessageDescriptionCollection messages; KeyedByTypeCollection behaviors; Collection knownTypes; MethodInfo beginMethod; MethodInfo endMethod; MethodInfo syncMethod; MethodInfo taskMethod; ProtectionLevel protectionLevel; bool hasProtectionLevel; bool validateRpcWrapperName = true; bool hasNoDisposableParameters; public OperationDescription(string name, ContractDescription declaringContract) { if (name == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("name"); } if (name.Length == 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentOutOfRangeException("name", SR.GetString(SR.SFxOperationDescriptionNameCannotBeEmpty))); } this.name = new XmlName(name, true /*isEncoded*/); if (declaringContract == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("declaringContract"); } this.declaringContract = declaringContract; this.isInitiating = true; this.isTerminating = false; this.faults = new FaultDescriptionCollection(); this.messages = new MessageDescriptionCollection(); this.behaviors = new KeyedByTypeCollection(); this.knownTypes = new Collection(); } internal OperationDescription(string name, ContractDescription declaringContract, bool validateRpcWrapperName) : this(name, declaringContract) { this.validateRpcWrapperName = validateRpcWrapperName; } public KeyedCollection OperationBehaviors { get { return this.Behaviors; } } [EditorBrowsable(EditorBrowsableState.Never)] public KeyedByTypeCollection Behaviors { get { return behaviors; } } // Not serializable on purpose, metadata import/export cannot // produce it, only available when binding to runtime public MethodInfo TaskMethod { get { return this.taskMethod; } set { this.taskMethod = value; } } // Not serializable on purpose, metadata import/export cannot // produce it, only available when binding to runtime public MethodInfo SyncMethod { get { return this.syncMethod; } set { this.syncMethod = value; } } // Not serializable on purpose, metadata import/export cannot // produce it, only available when binding to runtime public MethodInfo BeginMethod { get { return this.beginMethod; } set { this.beginMethod = value; } } internal MethodInfo OperationMethod { get { if (this.SyncMethod == null) { return this.TaskMethod ?? this.BeginMethod; } else { return this.SyncMethod; } } } public ProtectionLevel ProtectionLevel { get { return this.protectionLevel; } set { if (!ProtectionLevelHelper.IsDefined(value)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value")); this.protectionLevel = value; this.hasProtectionLevel = true; } } public bool ShouldSerializeProtectionLevel() { return this.HasProtectionLevel; } public bool HasProtectionLevel { get { return this.hasProtectionLevel; } } internal bool HasNoDisposableParameters { get { return this.hasNoDisposableParameters; } set { this.hasNoDisposableParameters = value; } } // Not serializable on purpose, metadata import/export cannot // produce it, only available when binding to runtime public MethodInfo EndMethod { get { return this.endMethod; } set { this.endMethod = value; } } public ContractDescription DeclaringContract { get { return this.declaringContract; } set { if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("DeclaringContract"); } else { this.declaringContract = value; } } } public FaultDescriptionCollection Faults { get { return faults; } } public bool IsOneWay { get { return this.Messages.Count == 1; } } [DefaultValue(false)] public bool IsInitiating { get { return this.isInitiating; } set { this.isInitiating = value; } } internal bool IsServerInitiated() { EnsureInvariants(); return Messages[0].Direction == MessageDirection.Output; } [DefaultValue(false)] public bool IsTerminating { get { return this.isTerminating; } set { this.isTerminating = value; } } public Collection KnownTypes { get { return this.knownTypes; } } // 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 { return messages; } } internal XmlName XmlName { get { return name; } } internal string CodeName { get { return name.DecodedName; } } public string Name { get { return name.EncodedName; } } internal bool IsValidateRpcWrapperName { get { return validateRpcWrapperName; } } //This property is set during contract inference in a hosted workflow scenario. This is required to handle correct //transactional invocation from the dispatcher in regards to scenarios involving the TransactedReceiveScope activity internal bool IsInsideTransactedReceiveScope { get; set; } //This property is set during contract inference in a hosted workflow scenario. This is required to handle correct //transactional invocation from the dispatcher in regards to scenarios involving the TransactedReceiveScope activity internal bool IsFirstReceiveOfTransactedReceiveScopeTree { get; set; } internal Type TaskTResult { get; set; } internal bool HasOutputParameters { get { // For non-oneway operations, Messages[1] is the 'response' return (this.Messages.Count > 1) && (this.Messages[1].Body.Parts.Count > 0); } } internal bool IsSessionOpenNotificationEnabled { get { return this.isSessionOpenNotificationEnabled; } set { this.isSessionOpenNotificationEnabled = value; } } internal void EnsureInvariants() { if (this.Messages.Count != 1 && this.Messages.Count != 2) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.InvalidOperationException(SR.GetString(SR.SFxOperationMustHaveOneOrTwoMessages, this.Name))); } } internal void ResetProtectionLevel() { this.protectionLevel = ProtectionLevel.None; this.hasProtectionLevel = false; } } }