|
using System;
using System.Reflection;
using System.Drawing;
using System.Drawing.Design;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Runtime.Remoting.Messaging;
using System.Diagnostics;
using System.Workflow.Activities.Common;
namespace System.Workflow.Activities
{
[SRDescription(SR.WebServiceResponseActivityDescription)]
[SRCategory(SR.Standard)]
[ToolboxBitmap(typeof(WebServiceOutputActivity), "Resources.WebServiceOut.png")]
[Designer(typeof(WebServiceResponseDesigner), typeof(IDesigner))]
[ActivityValidator(typeof(WebServiceResponseValidator))]
[DefaultEvent("SendingOutput")]
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
public sealed class WebServiceOutputActivity : Activity, IPropertyValueProvider, IDynamicPropertyTypeProvider
{
//metadata properties
public static readonly DependencyProperty InputActivityNameProperty = DependencyProperty.Register("InputActivityName", typeof(string), typeof(WebServiceOutputActivity), new PropertyMetadata("", DependencyPropertyOptions.Metadata));
//instance properties
public static readonly DependencyProperty ParameterBindingsProperty = DependencyProperty.Register("ParameterBindings", typeof(WorkflowParameterBindingCollection), typeof(WebServiceOutputActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata | DependencyPropertyOptions.ReadOnly, new Attribute[] { new BrowsableAttribute(false), new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content) }));
//event
public static readonly DependencyProperty SendingOutputEvent = DependencyProperty.Register("SendingOutput", typeof(EventHandler), typeof(WebServiceOutputActivity));
#region Constructors
public WebServiceOutputActivity()
{
//
base.SetReadOnlyPropertyValue(ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));
}
public WebServiceOutputActivity(string name)
: base(name)
{
//
base.SetReadOnlyPropertyValue(ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));
}
#endregion
[SRCategory(SR.Activity)]
[SRDescription(SR.ReceiveActivityNameDescription)]
[TypeConverter(typeof(PropertyValueProviderTypeConverter))]
[RefreshProperties(RefreshProperties.All)]
[MergablePropertyAttribute(false)]
[DefaultValue("")]
public string InputActivityName
{
get
{
return base.GetValue(InputActivityNameProperty) as string;
}
set
{
base.SetValue(InputActivityNameProperty, value);
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Browsable(false)]
public WorkflowParameterBindingCollection ParameterBindings
{
get
{
return base.GetValue(ParameterBindingsProperty) as WorkflowParameterBindingCollection;
}
}
[SRDescription(SR.OnBeforeResponseDescr)]
[SRCategory(SR.Handlers)]
[MergableProperty(false)]
public event EventHandler SendingOutput
{
add
{
base.AddHandler(SendingOutputEvent, value);
}
remove
{
base.RemoveHandler(SendingOutputEvent, value);
}
}
ICollection IPropertyValueProvider.GetPropertyValues(ITypeDescriptorContext context)
{
StringCollection names = new StringCollection();
if (context.PropertyDescriptor.Name == "InputActivityName")
{
foreach (Activity activity in WebServiceActivityHelpers.GetPreceedingActivities(this))
{
if (activity is WebServiceInputActivity)
{
names.Add(activity.QualifiedName);
}
}
}
return names;
}
protected override void Initialize(IServiceProvider provider)
{
if (this.Parent == null)
throw new InvalidOperationException(SR.GetString(SR.Error_MustHaveParent));
base.Initialize(provider);
}
#region Execute
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
if (executionContext == null)
throw new ArgumentNullException("executionContext");
WorkflowQueuingService queueService = executionContext.GetService<WorkflowQueuingService>();
// fire event
this.RaiseEvent(WebServiceOutputActivity.SendingOutputEvent, this, EventArgs.Empty);
WebServiceInputActivity webservicereceive = this.GetActivityByName(this.InputActivityName) as WebServiceInputActivity;
if (webservicereceive == null)
{
Activity parent = this.Parent;
while (parent != null)
{
//typically if defined inside a custom activity
string qualifiedName = parent.QualifiedName + "." + this.InputActivityName;
webservicereceive = this.GetActivityByName(qualifiedName) as WebServiceInputActivity;
if (webservicereceive != null)
break;
parent = this.Parent;
}
}
if (webservicereceive == null)
throw new InvalidOperationException(SR.GetString(SR.Error_CannotResolveWebServiceInput, this.QualifiedName, this.InputActivityName));
IComparable queueId = new EventQueueName(webservicereceive.InterfaceType, webservicereceive.MethodName, webservicereceive.QualifiedName);
MethodInfo mInfo = webservicereceive.InterfaceType.GetMethod(webservicereceive.MethodName);
if (!queueService.Exists(queueId))
{
// determine if no response is required,
// compiler did not catch it, do the runtime check and return
if (mInfo.ReturnType == typeof(void))
{
return ActivityExecutionStatus.Closed;
}
bool isresponseRequired = false;
foreach (ParameterInfo formalParameter in mInfo.GetParameters())
{
if (formalParameter.ParameterType.IsByRef || (formalParameter.IsIn && formalParameter.IsOut))
{
isresponseRequired = true;
}
}
if (isresponseRequired)
{
return ActivityExecutionStatus.Closed;
}
}
if (!queueService.Exists(queueId))
throw new InvalidOperationException(SR.GetString(SR.Error_WebServiceInputNotProcessed, webservicereceive.QualifiedName));
IMethodResponseMessage responseMessage = null;
WorkflowQueue queue = queueService.GetWorkflowQueue(queueId);
if (queue.Count != 0)
responseMessage = queue.Dequeue() as IMethodResponseMessage;
IMethodMessage message = responseMessage as IMethodMessage;
WorkflowParameterBindingCollection parameterBindings = this.ParameterBindings;
ArrayList outArgs = new ArrayList();
// populate result
if (this.ParameterBindings.Contains("(ReturnValue)"))
{
WorkflowParameterBinding retBind = this.ParameterBindings["(ReturnValue)"];
if (retBind != null)
{
outArgs.Add(retBind.Value);
}
}
foreach (ParameterInfo formalParameter in mInfo.GetParameters())
{
// update out and byref values
if (formalParameter.ParameterType.IsByRef || (formalParameter.IsIn && formalParameter.IsOut))
{
WorkflowParameterBinding binding = parameterBindings[formalParameter.Name];
outArgs.Add(binding.Value);
}
}
// reset the waiting thread
responseMessage.SendResponse(outArgs);
return ActivityExecutionStatus.Closed;
}
#endregion
#region IDynamicPropertyTypeProvider
Type IDynamicPropertyTypeProvider.GetPropertyType(IServiceProvider serviceProvider, string propertyName)
{
if (propertyName == null)
throw new ArgumentNullException("propertyName");
Dictionary<string, object> parameters = new Dictionary<string, object>();
this.GetParameterPropertyDescriptors(parameters);
if (parameters.ContainsKey(propertyName))
{
ParameterInfoBasedPropertyDescriptor descriptor = parameters[propertyName] as ParameterInfoBasedPropertyDescriptor;
if (descriptor != null)
return descriptor.ParameterType;
}
return null;
}
AccessTypes IDynamicPropertyTypeProvider.GetAccessType(IServiceProvider serviceProvider, string propertyName)
{
if (propertyName == null)
throw new ArgumentNullException("propertyName");
return AccessTypes.Read;
}
internal void GetParameterPropertyDescriptors(IDictionary properties)
{
if (((IComponent)this).Site == null)
return;
ITypeProvider typeProvider = (ITypeProvider)((IComponent)this).Site.GetService(typeof(ITypeProvider));
if (typeProvider == null)
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
if (this.InputActivityName != null && !String.IsNullOrEmpty(this.InputActivityName.Trim()))
{
WebServiceInputActivity webServiceReceive = Helpers.ParseActivity(Helpers.GetRootActivity(this), this.InputActivityName) as WebServiceInputActivity;
if (webServiceReceive != null)
{
Type type = null;
if (webServiceReceive.InterfaceType != null)
type = typeProvider.GetType(webServiceReceive.InterfaceType.AssemblyQualifiedName);
if (type != null)
{
MethodInfo method = Helpers.GetInterfaceMethod(type, webServiceReceive.MethodName);
if (method != null && WebServiceActivityHelpers.ValidateParameterTypes(method).Count == 0)
{
List<ParameterInfo> inputParameters, outParameters;
WebServiceActivityHelpers.GetParameterInfo(method, out inputParameters, out outParameters);
foreach (ParameterInfo paramInfo in outParameters)
{
PropertyDescriptor prop = null;
if (paramInfo.Position == -1)
prop = new ParameterInfoBasedPropertyDescriptor(typeof(WebServiceOutputActivity), paramInfo, false, DesignOnlyAttribute.Yes);
else
prop = new ParameterInfoBasedPropertyDescriptor(typeof(WebServiceOutputActivity), paramInfo, true, DesignOnlyAttribute.Yes);
if (prop != null)
properties[prop.Name] = prop;
}
}
}
}
}
}
#endregion
}
internal sealed class WebServiceResponseValidator : ActivityValidator
{
public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
{
ValidationErrorCollection validationErrors = base.Validate(manager, obj);
WebServiceOutputActivity webServiceResponse = obj as WebServiceOutputActivity;
if (webServiceResponse == null)
throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(WebServiceOutputActivity).FullName), "obj");
if (Helpers.IsActivityLocked(webServiceResponse))
{
return validationErrors;
}
WebServiceInputActivity webServiceReceive = null;
if (String.IsNullOrEmpty(webServiceResponse.InputActivityName))
validationErrors.Add(ValidationError.GetNotSetValidationError("InputActivityName"));
else
{
ITypeProvider typeProvider = (ITypeProvider)manager.GetService(typeof(ITypeProvider));
if (typeProvider == null)
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
bool foundMatchingReceive = false;
foreach (Activity activity in WebServiceActivityHelpers.GetPreceedingActivities(webServiceResponse))
{
if ((activity is WebServiceOutputActivity && String.Compare(((WebServiceOutputActivity)activity).InputActivityName, webServiceResponse.InputActivityName, StringComparison.Ordinal) == 0) ||
(activity is WebServiceFaultActivity && String.Compare(((WebServiceFaultActivity)activity).InputActivityName, webServiceResponse.InputActivityName, StringComparison.Ordinal) == 0))
{
if (activity is WebServiceOutputActivity)
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_DuplicateWebServiceResponseFound, activity.QualifiedName, webServiceResponse.InputActivityName), ErrorNumbers.Error_DuplicateWebServiceResponseFound));
else
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_DuplicateWebServiceFaultFound, activity.QualifiedName, webServiceResponse.InputActivityName), ErrorNumbers.Error_DuplicateWebServiceFaultFound));
return validationErrors;
}
}
foreach (Activity activity in WebServiceActivityHelpers.GetPreceedingActivities(webServiceResponse))
{
if (String.Compare(activity.QualifiedName, webServiceResponse.InputActivityName, StringComparison.Ordinal) == 0)
{
if (activity is WebServiceInputActivity)
{
webServiceReceive = activity as WebServiceInputActivity;
foundMatchingReceive = true;
}
else
{
foundMatchingReceive = false;
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_WebServiceReceiveNotValid, webServiceResponse.InputActivityName), ErrorNumbers.Error_WebServiceReceiveNotValid));
return validationErrors;
}
break;
}
}
if (!foundMatchingReceive)
{
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_WebServiceReceiveNotFound, webServiceResponse.InputActivityName), ErrorNumbers.Error_WebServiceReceiveNotFound));
return validationErrors;
}
else
{
Type interfaceType = null;
if (webServiceReceive.InterfaceType != null)
interfaceType = typeProvider.GetType(webServiceReceive.InterfaceType.AssemblyQualifiedName);
if (interfaceType == null)
{
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_WebServiceReceiveNotConfigured, webServiceReceive.Name), ErrorNumbers.Error_WebServiceReceiveNotConfigured));
}
else
{
// Validate method
if (String.IsNullOrEmpty(webServiceReceive.MethodName))
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_WebServiceReceiveNotConfigured, webServiceReceive.Name), ErrorNumbers.Error_WebServiceReceiveNotConfigured));
else
{
MethodInfo methodInfo = Helpers.GetInterfaceMethod(interfaceType, webServiceReceive.MethodName);
if (methodInfo == null)
{
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_WebServiceReceiveNotConfigured, webServiceReceive.Name), ErrorNumbers.Error_WebServiceReceiveNotConfigured));
}
else
{
ValidationErrorCollection parameterTypeErrors = WebServiceActivityHelpers.ValidateParameterTypes(methodInfo);
if (parameterTypeErrors.Count > 0)
{
foreach (ValidationError parameterTypeError in parameterTypeErrors)
{
parameterTypeError.PropertyName = "InputActivityName";
}
validationErrors.AddRange(parameterTypeErrors);
}
else
{
List<ParameterInfo> inputParameters, outParameters;
WebServiceActivityHelpers.GetParameterInfo(methodInfo, out inputParameters, out outParameters);
if (outParameters.Count == 0)
{
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_WebServiceResponseNotNeeded), ErrorNumbers.Error_WebServiceResponseNotNeeded));
}
else
{
// Check to see if all output parameters have a valid bindings.
foreach (ParameterInfo paramInfo in outParameters)
{
string paramName = paramInfo.Name;
Type paramType = paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() : paramInfo.ParameterType;
if (paramInfo.Position == -1)
paramName = "(ReturnValue)";
object paramValue = null;
if (webServiceResponse.ParameterBindings.Contains(paramName))
{
if (webServiceResponse.ParameterBindings[paramName].IsBindingSet(WorkflowParameterBinding.ValueProperty))
paramValue = webServiceResponse.ParameterBindings[paramName].GetBinding(WorkflowParameterBinding.ValueProperty);
else
paramValue = webServiceResponse.ParameterBindings[paramName].GetValue(WorkflowParameterBinding.ValueProperty);
}
if (!paramType.IsPublic || !paramType.IsSerializable)
{
ValidationError validationError = new ValidationError(SR.GetString(SR.Error_TypeNotPublicSerializable, paramName, paramType.FullName), ErrorNumbers.Error_TypeNotPublicSerializable);
validationError.PropertyName = (String.Compare(paramName, "(ReturnValue)", StringComparison.Ordinal) == 0) ? paramName : ParameterInfoBasedPropertyDescriptor.GetParameterPropertyName(webServiceReceive.GetType(), paramName);
validationErrors.Add(validationError);
}
else if (!webServiceResponse.ParameterBindings.Contains(paramName) || paramValue == null)
{
ValidationError validationError = ValidationError.GetNotSetValidationError(paramName);
validationError.PropertyName = (String.Compare(paramName, "(ReturnValue)", StringComparison.Ordinal) == 0) ? paramName : ParameterInfoBasedPropertyDescriptor.GetParameterPropertyName(webServiceReceive.GetType(), paramName);
validationErrors.Add(validationError);
}
else
{
AccessTypes access = AccessTypes.Read;
if (paramInfo.IsOut || paramInfo.IsRetval || paramInfo.Position == -1)
access = AccessTypes.Write;
ValidationErrorCollection variableErrors = ValidationHelpers.ValidateProperty(manager, webServiceResponse, paramValue,
new PropertyValidationContext(webServiceResponse.ParameterBindings[paramName], null, paramName), new BindValidationContext(paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() : paramInfo.ParameterType, access));
foreach (ValidationError variableError in variableErrors)
{
if (String.Compare(paramName, "(ReturnValue)", StringComparison.Ordinal) != 0)
variableError.PropertyName = ParameterInfoBasedPropertyDescriptor.GetParameterPropertyName(webServiceReceive.GetType(), paramName);
}
validationErrors.AddRange(variableErrors);
}
}
if (webServiceResponse.ParameterBindings.Count > outParameters.Count)
validationErrors.Add(new ValidationError(SR.GetString(SR.Warning_AdditionalBindingsFound), ErrorNumbers.Warning_AdditionalBindingsFound, true));
}
}
}
}
}
}
}
return validationErrors;
}
}
internal static class WebServiceActivityHelpers
{
private static IEnumerable GetContainedActivities(CompositeActivity activity)
{
if (!activity.Enabled)
yield break;
foreach (Activity containedActivity in activity.Activities)
{
if (containedActivity is CompositeActivity && !Helpers.IsCustomActivity((CompositeActivity)containedActivity))
{
foreach (Activity nestedActivity in WebServiceActivityHelpers.GetContainedActivities((CompositeActivity)containedActivity))
{
if (nestedActivity.Enabled)
yield return nestedActivity;
}
}
else
{
if (containedActivity.Enabled)
yield return containedActivity;
}
}
yield break;
}
internal static IEnumerable GetPreceedingActivities(Activity startActivity)
{
return GetPreceedingActivities(startActivity, false);
}
internal static IEnumerable GetPreceedingActivities(Activity startActivity, bool crossOverLoop)
{
Activity currentActivity = null;
Stack<Activity> activityStack = new Stack<Activity>();
activityStack.Push(startActivity);
while ((currentActivity = activityStack.Pop()) != null)
{
if (currentActivity is CompositeActivity && Helpers.IsCustomActivity((CompositeActivity)currentActivity))
break;
if (currentActivity.Parent != null)
{
foreach (Activity siblingActivity in currentActivity.Parent.Activities)
{
//
if (siblingActivity == currentActivity && ((currentActivity.Parent is ParallelActivity && !Helpers.IsFrameworkActivity(currentActivity)) || (currentActivity.Parent is StateActivity && !Helpers.IsFrameworkActivity(currentActivity))))
continue;
//
if (currentActivity.Parent is IfElseActivity && !Helpers.IsFrameworkActivity(currentActivity))
continue;
//For Listen Case.
if (currentActivity.Parent is ListenActivity && !Helpers.IsFrameworkActivity(currentActivity))
continue;
// State Machine logic:
// If startActivity was in the InitialState, then
// there are no preceeding activities.
// Otherwise, we just return the parent state as
// the preceeding activity.
StateActivity currentState = currentActivity.Parent as StateActivity;
if (currentState != null)
{
StateActivity enclosingState = StateMachineHelpers.FindEnclosingState(startActivity);
//If we are at Initial State there is no preceeding above us.
if (StateMachineHelpers.IsInitialState(enclosingState))
yield break;
else
yield return currentState;
}
if (siblingActivity == currentActivity)
break;
if (siblingActivity.Enabled)
{
if (siblingActivity is CompositeActivity && !Helpers.IsCustomActivity((CompositeActivity)siblingActivity) && (crossOverLoop || !IsLoopActivity(siblingActivity)))
{
foreach (Activity containedActivity in WebServiceActivityHelpers.GetContainedActivities((CompositeActivity)siblingActivity))
yield return containedActivity;
}
else
{
yield return siblingActivity;
}
}
}
}
if (!crossOverLoop && IsLoopActivity(currentActivity.Parent))
break;
else
activityStack.Push(currentActivity.Parent);
}
yield break;
}
internal static bool IsLoopActivity(Activity activity)
{
//
if (activity is WhileActivity || activity is ReplicatorActivity || activity is ConditionedActivityGroup)
return true;
return false;
}
internal static bool IsInsideLoop(Activity webServiceActivity, Activity searchBoundary)
{
IEnumerable<String> searchBoundaryPath = GetActivityPath(searchBoundary);
IEnumerable<String> currentActivityPath = GetActivityPath(webServiceActivity);
String leastCommonParent = FindLeastCommonParent(searchBoundaryPath, currentActivityPath);
Activity currentActivity = webServiceActivity;
while (currentActivity.Parent != null && currentActivity.Parent.QualifiedName != leastCommonParent)
{
if (IsLoopActivity(currentActivity))
return true;
currentActivity = currentActivity.Parent;
}
return false;
}
static IEnumerable<String> GetActivityPath(Activity activity)
{
if (activity != null)
{
foreach (String path in GetActivityPath(activity.Parent))
yield return path;
yield return activity.QualifiedName;
}
}
static String FindLeastCommonParent(IEnumerable<String> source, IEnumerable<String> dest)
{
IEnumerator srcEnum = source.GetEnumerator();
IEnumerator destEnum = dest.GetEnumerator();
String leastCommonParent = null;
while (srcEnum.MoveNext() && destEnum.MoveNext())
{
if (srcEnum.Current.Equals(destEnum.Current))
leastCommonParent = (String)srcEnum.Current;
else
return leastCommonParent;
}
return leastCommonParent;
}
internal static IEnumerable GetSucceedingActivities(Activity startActivity)
{
Activity currentActivity = null;
Stack<Activity> activityStack = new Stack<Activity>();
activityStack.Push(startActivity);
while ((currentActivity = activityStack.Pop()) != null)
{
if (currentActivity is CompositeActivity && Helpers.IsCustomActivity((CompositeActivity)currentActivity))
break;
if (currentActivity.Parent != null)
{
bool pastCurrentActivity = false;
foreach (Activity siblingActivity in currentActivity.Parent.Activities)
{
if (siblingActivity == currentActivity)
{
pastCurrentActivity = true;
continue;
}
if (!pastCurrentActivity)
continue;
if (siblingActivity.Enabled)
{
if (siblingActivity is CompositeActivity && !Helpers.IsCustomActivity((CompositeActivity)siblingActivity))
{
foreach (Activity containedActivity in WebServiceActivityHelpers.GetContainedActivities((CompositeActivity)siblingActivity))
yield return containedActivity;
}
else
{
yield return siblingActivity;
}
}
}
}
activityStack.Push(currentActivity.Parent);
}
yield break;
}
internal static void GetParameterInfo(MethodInfo methodInfo, out List<ParameterInfo> inParameters, out List<ParameterInfo> outParameters)
{
inParameters = new List<ParameterInfo>(); outParameters = new List<ParameterInfo>();
foreach (ParameterInfo paramInfo in methodInfo.GetParameters())
{
if (paramInfo.IsOut || paramInfo.IsRetval || paramInfo.ParameterType.IsByRef)
outParameters.Add(paramInfo);
if (!paramInfo.IsOut && !paramInfo.IsRetval)
inParameters.Add(paramInfo);
}
if (methodInfo.ReturnType != typeof(void))
outParameters.Add(methodInfo.ReturnParameter);
return;
}
internal static ValidationErrorCollection ValidateParameterTypes(MethodInfo methodInfo)
{
ValidationErrorCollection validationErrors = new ValidationErrorCollection();
if (methodInfo == null)
return validationErrors;
foreach (ParameterInfo paramInfo in methodInfo.GetParameters())
{
if (paramInfo.ParameterType == null)
{
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_ParameterTypeNotFound, methodInfo.Name, paramInfo.Name), ErrorNumbers.Error_ParameterTypeNotFound));
}
}
if (methodInfo.ReturnType != typeof(void) && methodInfo.ReturnParameter.ParameterType == null)
{
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_ReturnTypeNotFound, methodInfo.Name), ErrorNumbers.Error_ReturnTypeNotFound));
}
return validationErrors;
}
}
}
|