//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ #pragma warning disable 1634, 1691 namespace System.Workflow.Activities { using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Globalization; using System.Reflection; using System.Runtime; using System.ServiceModel; using System.ServiceModel.Channels; using System.Workflow.ComponentModel; using System.Workflow.ComponentModel.Compiler; using System.Workflow.ComponentModel.Design; using System.Workflow.Runtime.Hosting; [SR2Description(SR2DescriptionAttribute.SendActivityDescription)] [SR2Category(SR2CategoryAttribute.Standard)] [DesignerAttribute(typeof(SendActivityDesigner), typeof(IDesigner))] [ToolboxBitmap(typeof(SendActivity), "Design.Resources.SendActivity.png")] [ActivityValidator(typeof(SendActivityValidator))] [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] public sealed class SendActivity : Activity { [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly DependencyProperty AfterResponseEvent = DependencyProperty.Register("AfterResponse", typeof(EventHandler), typeof(SendActivity)); [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly DependencyProperty BeforeSendEvent = DependencyProperty.Register("BeforeSend", typeof(EventHandler), typeof(SendActivity)); [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly DependencyProperty CustomAddressProperty = DependencyProperty.Register("CustomAddress", typeof(string), typeof(SendActivity), new PropertyMetadata(null)); public const string ReturnValuePropertyName = "(ReturnValue)"; [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] internal static readonly DependencyProperty ChannelTokenProperty = DependencyProperty.Register("ChannelToken", typeof(ChannelToken), typeof(SendActivity), new PropertyMetadata(null, DependencyPropertyOptions.Metadata)); [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] internal static readonly DependencyProperty ParameterBindingsProperty = DependencyProperty.Register("ParameterBindings", typeof(WorkflowParameterBindingCollection), typeof(SendActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata | DependencyPropertyOptions.ReadOnly)); [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] internal static readonly DependencyProperty ServiceOperationInfoProperty = DependencyProperty.Register("ServiceOperationInfo", typeof(TypedOperationInfo), typeof(SendActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata)); [NonSerialized] private SendOperationInfoHelper operationHelper; public SendActivity() { base.SetReadOnlyPropertyValue(SendActivity.ParameterBindingsProperty, new WorkflowParameterBindingCollection(this)); } public SendActivity(String name) : base(name) { base.SetReadOnlyPropertyValue(SendActivity.ParameterBindingsProperty, new WorkflowParameterBindingCollection(this)); } [SuppressMessage("Microsoft.Naming", "CA1713:EventsShouldNotHaveBeforeOrAfterPrefix")] [Browsable(true)] [SR2Category(SR2CategoryAttribute.Handlers)] [SR2Description(SR2DescriptionAttribute.Send_AfterResponse_Description)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public event EventHandler AfterResponse { add { base.AddHandler(SendActivity.AfterResponseEvent, value); } remove { base.RemoveHandler(SendActivity.AfterResponseEvent, value); } } [SuppressMessage("Microsoft.Naming", "CA1713:EventsShouldNotHaveBeforeOrAfterPrefix")] [Browsable(true)] [SR2Category(SR2CategoryAttribute.Handlers)] [SR2Description(SR2DescriptionAttribute.Send_BeforeSend_Description)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public event EventHandler BeforeSend { add { base.AddHandler(SendActivity.BeforeSendEvent, value); } remove { base.RemoveHandler(SendActivity.BeforeSendEvent, value); } } [DefaultValue(null)] [MergableProperty(false)] [RefreshProperties(RefreshProperties.All)] [SR2Category(SR2CategoryAttribute.Activity)] [SR2Description(SR2DescriptionAttribute.Send_ChannelToken_Description)] public ChannelToken ChannelToken { get { return (ChannelToken) this.GetValue(SendActivity.ChannelTokenProperty); } set { this.SetValue(SendActivity.ChannelTokenProperty, value); } } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public IDictionary Context { get { if (this.ServiceOperationInfo == null) { #pragma warning suppress 56503 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_ServiceOperationInfoNotSpecified, this.Name))); } return SendActivity.GetContext(this, this.ChannelToken, this.ServiceOperationInfo.ContractType); } set { if (this.ServiceOperationInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_ServiceOperationInfoNotSpecified, this.Name))); } SendActivity.SetContext(this, this.ChannelToken, this.ServiceOperationInfo.ContractType, value); } } [DefaultValue(null)] [SR2Category(SR2CategoryAttribute.Activity)] [SR2Description(SR2DescriptionAttribute.Send_CustomAddress_Description)] public string CustomAddress { get { return (string) GetValue(CustomAddressProperty); } set { SetValue(CustomAddressProperty, value); } } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public WorkflowParameterBindingCollection ParameterBindings { get { return ((WorkflowParameterBindingCollection)(base.GetValue(SendActivity.ParameterBindingsProperty))); } } [Browsable(true)] [SR2Category(SR2CategoryAttribute.Activity)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [SR2Description(SR2DescriptionAttribute.Send_OperationInfo_Description)] public TypedOperationInfo ServiceOperationInfo { get { return ((TypedOperationInfo)(base.GetValue(SendActivity.ServiceOperationInfoProperty))); } set { OperationInfoBase currentValue = ((OperationInfoBase)(base.GetValue(SendActivity.ServiceOperationInfoProperty))); if (value != null && currentValue != value) { DependencyProperty ParentDependencyObjectProperty = DependencyProperty.FromName("ParentDependencyObject", typeof(DependencyObject)); Activity currentParent = value.GetValue(ParentDependencyObjectProperty) as Activity; if (currentParent != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument( "value", SR2.GetString(SR2.Error_OperationIsAlreadyAssociatedWithActivity, value, currentParent.QualifiedName)); } if (currentValue != null) { currentValue.SetValue(ParentDependencyObjectProperty, null); } value.SetValue(ParentDependencyObjectProperty, this); } if (this.DesignMode) { Activity rootActivity = this.RootActivity; rootActivity.RemoveProperty(DynamicContractTypeBuilder.DynamicContractTypesProperty); } base.SetValue(SendActivity.ServiceOperationInfoProperty, value); } } SendOperationInfoHelper OperationHelper { get { if (this.operationHelper == null) { if (this.UserData.Contains(typeof(SendOperationInfoHelper))) { this.operationHelper = this.UserData[typeof(SendOperationInfoHelper)] as SendOperationInfoHelper; } } if (this.operationHelper == null) { this.operationHelper = new SendOperationInfoHelper(this.Site, this); this.UserData[typeof(SendOperationInfoHelper)] = this.operationHelper; } return this.operationHelper; } } public static IDictionary GetContext(Activity activity, ChannelToken endpoint, Type contractType) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } if (endpoint == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint"); } if (contractType == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contractType"); } return GetContext(activity, endpoint.Name, endpoint.OwnerActivityName, contractType); } public static IDictionary GetContext(Activity activity, string endpointName, string ownerActivityName, Type contractType) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } if (string.IsNullOrEmpty(endpointName)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("endpointName", SR2.GetString(SR2.Error_ArgumentValueNullOrEmptyString)); } if (contractType == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contractType"); } LogicalChannel logicalChannel = ChannelToken.GetLogicalChannel(activity, endpointName, ownerActivityName, contractType); if (logicalChannel != null) { return logicalChannel.Context; } return null; } public static void SetContext(Activity activity, ChannelToken endpoint, Type contractType, IDictionary context) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } if (endpoint == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint"); } if (contractType == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contractType"); } SetContext(activity, endpoint.Name, endpoint.OwnerActivityName, contractType, context); } public static void SetContext(Activity activity, string endpointName, string ownerActivityName, Type contractType, IDictionary context) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } if (string.IsNullOrEmpty(endpointName)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("endpointName", SR2.GetString(SR2.Error_ArgumentValueNullOrEmptyString)); } if (contractType == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contractType"); } LogicalChannel logicalChannel = ChannelToken.GetLogicalChannel(activity, endpointName, ownerActivityName, contractType); if (logicalChannel != null) { if (context != null) { logicalChannel.Context = context; } else { logicalChannel.Context = ContextMessageProperty.Empty.Context; } } } protected internal override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { TypedOperationInfo serviceOperationInfo = this.ServiceOperationInfo; if (serviceOperationInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_ServiceOperationInfoNotSpecified, this.Name))); } MethodInfo methodInfo = serviceOperationInfo.GetMethodInfo(executionContext); if (methodInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_MethodInfoNotAvailable, this.Name))); } ChannelToken channelToken = this.ChannelToken; LogicalChannel logicalChannel = ChannelToken.Register(this, channelToken, serviceOperationInfo.ContractType); if (!logicalChannel.Initialized) { logicalChannel.Initialize(channelToken.EndpointName, this.CustomAddress); } using (ChannelManagerService.ChannelTicket leasedChannel = ChannelManagerService.Take(executionContext, this.WorkflowInstanceId, logicalChannel)) { using (OperationContextScope scope = new OperationContextScope((IContextChannel) leasedChannel.Channel)) { EventHandler[] invocationList = this.GetInvocationList>(SendActivity.BeforeSendEvent); if (invocationList != null && invocationList.Length > 0) { base.RaiseGenericEvent(SendActivity.BeforeSendEvent, this, new SendActivityEventArgs(this)); } SendOperationInfoHelper helper = this.OperationHelper; WorkflowParameterBindingCollection bindings = this.ParameterBindings; object[] parameters = helper.GetInputs(this, bindings); object returnValue = null; bool isSessionless = ChannelManagerHelpers.IsSessionlessContract(logicalChannel.ContractType); bool hasContext = (logicalChannel.Context != null && logicalChannel.Context.Count > 0); bool fatalException = false; if (!isSessionless && hasContext) { ChannelManagerService.ApplyLogicalChannelContext(logicalChannel); } try { returnValue = this.InvokeOperation(methodInfo, leasedChannel.Channel, parameters); } catch (Exception exception) { if (Fx.IsFatal(exception)) { fatalException = true; } throw; } finally { if (!fatalException && !hasContext && !isSessionless && !helper.IsOneWay) { ChannelManagerService.UpdateLogicalChannelContext(logicalChannel); } } helper.PopulateOutputs(this, bindings, parameters, returnValue); invocationList = this.GetInvocationList>(SendActivity.AfterResponseEvent); if (invocationList != null && invocationList.Length > 0) { base.RaiseGenericEvent(SendActivity.AfterResponseEvent, this, new SendActivityEventArgs(this)); } } } return ActivityExecutionStatus.Closed; } internal void GetParameterPropertyDescriptors(IDictionary properties) { if (properties == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties"); } if (((IComponent) this).Site == null) { return; } TypedOperationInfo serviceOperationInfo = this.ServiceOperationInfo; if (serviceOperationInfo != null) { MethodInfo methodInfo = serviceOperationInfo.GetMethodInfo(((IComponent) this).Site); if (methodInfo != null) { ArrayList paramInfo = new ArrayList(methodInfo.GetParameters()); if (!(methodInfo.ReturnType == typeof(void))) { paramInfo.Add(methodInfo.ReturnParameter); } foreach (ParameterInfo param in paramInfo) { if (param.ParameterType != null) { PropertyDescriptor prop = new ParameterInfoBasedPropertyDescriptor(typeof(ReceiveActivity), param, true, DesignOnlyAttribute.Yes); properties[prop.Name] = prop; } } } } } protected override void InitializeProperties() { TypedOperationInfo serviceOperationInfo = this.ServiceOperationInfo; if (serviceOperationInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_ServiceOperationInfoNotSpecified, this.Name))); } OperationParameterInfoCollection parameters = null; Activity definitionRoot = base.RootActivity.GetValue(Activity.WorkflowDefinitionProperty) as Activity; if (definitionRoot != null) { SendActivity definition = definitionRoot.GetActivityByName(this.QualifiedName, true) as SendActivity; if ((definition != null) && definition.UserData.Contains(typeof(OperationParameterInfoCollection))) { parameters = definition.UserData[typeof(OperationParameterInfoCollection)] as OperationParameterInfoCollection; } } if (parameters == null) { parameters = serviceOperationInfo.GetParameters(this.Site); this.UserData[typeof(OperationParameterInfoCollection)] = parameters; } WorkflowParameterBindingCollection parameterBindings = this.ParameterBindings; foreach (OperationParameterInfo parameterInfo in parameters) { if (!parameterBindings.Contains(parameterInfo.Name)) { parameterBindings.Add(new WorkflowParameterBinding(parameterInfo.Name)); } } base.InitializeProperties(); } object InvokeOperation(MethodInfo operation, IChannel channel, object[] parameters) { Guid workflowInstanceId = this.WorkflowInstanceId; string qualifiedName = this.QualifiedName; System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Verbose, 0, "Workflow Instance {0}, send activity {1} - invoking operation", workflowInstanceId, qualifiedName); try { object retVal = operation.ReflectedType.InvokeMember(operation.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, channel, parameters, CultureInfo.InvariantCulture); System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Verbose, 0, "Workflow Instance {0}, send activity {1} - operation invoke succeeded", workflowInstanceId, qualifiedName); return retVal; } catch (TargetInvocationException e) { if (e.InnerException != null) { System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Error, 0, "Workflow Instance {0}, send activity {1} - operation invoke failed with error: {2}", workflowInstanceId, qualifiedName, e.InnerException.Message); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.InnerException); } else { System.Workflow.Runtime.WorkflowTrace.Runtime.TraceEvent(TraceEventType.Error, 0, "Workflow Instance {0}, send activity {1} - operation invoke failed with error: {2}", workflowInstanceId, qualifiedName, e.Message); throw; } } } [Serializable] class SendOperationInfoHelper { bool hasReturnValue = false; IList> inputParameters; bool isOneWay = false; string operationName; IList> outputParameters; int parameterCount = 0; public SendOperationInfoHelper(IServiceProvider serviceProvider, SendActivity activity) { outputParameters = new List>(); inputParameters = new List>(); hasReturnValue = false; if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } OperationInfoBase serviceOperationInfo = activity.ServiceOperationInfo; if (serviceOperationInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_ServiceOperationInfoNotSpecified, activity.Name))); } MethodInfo methodInfo = serviceOperationInfo.GetMethodInfo(serviceProvider); if (methodInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_MethodInfoNotAvailable, activity.Name))); } if (methodInfo.ReturnType != null && methodInfo.ReturnType != typeof(void)) { hasReturnValue = true; } foreach (ParameterInfo parameter in methodInfo.GetParameters()) { if (parameter.ParameterType.IsByRef || parameter.IsOut || (parameter.IsIn && parameter.IsOut)) { outputParameters.Add(new KeyValuePair(parameter.Position, parameter.Name)); } if (!parameter.IsOut || (parameter.IsIn && parameter.IsOut)) { inputParameters.Add(new KeyValuePair(parameter.Position, parameter.Name)); } } this.parameterCount = methodInfo.GetParameters().Length; this.operationName = serviceOperationInfo.Name; object[] operationContractAttribs = methodInfo.GetCustomAttributes(typeof(OperationContractAttribute), true); if (operationContractAttribs != null && operationContractAttribs.Length > 0) { if (operationContractAttribs[0] is OperationContractAttribute) { this.isOneWay = ((OperationContractAttribute) operationContractAttribs[0]).IsOneWay; } } } public bool IsOneWay { get { return this.isOneWay; } } public object[] GetInputs(SendActivity activity, WorkflowParameterBindingCollection bindings) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } object[] inputs = new object[this.parameterCount]; if (inputParameters.Count > 0) { for (int index = 0; index < inputParameters.Count; index++) { KeyValuePair parameterInfo = inputParameters[index]; if (bindings.Contains(parameterInfo.Value)) { inputs[parameterInfo.Key] = bindings[parameterInfo.Value].Value; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_ParameterBindingMissing, parameterInfo.Value, this.operationName, activity.Name))); } } } return inputs; } public void PopulateOutputs(SendActivity activity, WorkflowParameterBindingCollection bindings, object[] outputs, object returnValue) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } if (outputs == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("outputs"); } if (this.outputParameters.Count > 0 && outputs.Length > 0) { for (int index = 0; index < outputParameters.Count; ++index) { KeyValuePair parameterInfo = outputParameters[index]; if (bindings.Contains(parameterInfo.Value)) { bindings[parameterInfo.Value].Value = outputs[parameterInfo.Key]; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_ParameterBindingMissing, parameterInfo.Value, this.operationName, activity.Name))); } } } if (hasReturnValue) { if (bindings.Contains(SendActivity.ReturnValuePropertyName)) { bindings[SendActivity.ReturnValuePropertyName].Value = returnValue; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.Error_ParameterBindingMissing, SendActivity.ReturnValuePropertyName, this.operationName, activity.Name))); } } } } } }