e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
281 lines
8.9 KiB
C#
281 lines
8.9 KiB
C#
//------------------------------------------------------------
|
|
// 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<IOperationBehavior> behaviors;
|
|
Collection<Type> 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<IOperationBehavior>();
|
|
this.knownTypes = new Collection<Type>();
|
|
}
|
|
|
|
internal OperationDescription(string name, ContractDescription declaringContract, bool validateRpcWrapperName)
|
|
: this(name, declaringContract)
|
|
{
|
|
this.validateRpcWrapperName = validateRpcWrapperName;
|
|
}
|
|
|
|
public KeyedCollection<Type, IOperationBehavior> OperationBehaviors
|
|
{
|
|
get { return this.Behaviors; }
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public KeyedByTypeCollection<IOperationBehavior> 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<Type> 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;
|
|
}
|
|
}
|
|
}
|