316 lines
14 KiB
C#
316 lines
14 KiB
C#
|
namespace System.Workflow.Activities
|
||
|
{
|
||
|
#region Imports
|
||
|
|
||
|
using System;
|
||
|
using System.IO;
|
||
|
using System.Xml;
|
||
|
using System.Text;
|
||
|
using System.Reflection;
|
||
|
using System.Collections;
|
||
|
using System.ComponentModel;
|
||
|
using System.Drawing;
|
||
|
using System.Diagnostics;
|
||
|
using System.Drawing.Design;
|
||
|
using System.ComponentModel.Design;
|
||
|
using System.ComponentModel.Design.Serialization;
|
||
|
using System.CodeDom;
|
||
|
using System.Workflow.ComponentModel;
|
||
|
using System.Workflow.ComponentModel.Design;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Workflow.ComponentModel.Compiler;
|
||
|
using System.Workflow.Runtime;
|
||
|
using System.Workflow.Runtime.Hosting;
|
||
|
using System.Collections.Specialized;
|
||
|
using System.Workflow.Activities.Common;
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
// Note that the designer is associated dynamically through the type description provider
|
||
|
[SRDescription(SR.InvokeWorkflowActivityDescription)]
|
||
|
[ToolboxItem(typeof(ActivityToolboxItem))]
|
||
|
[ToolboxBitmap(typeof(InvokeWorkflowActivity), "Resources.Service.bmp")]
|
||
|
[ActivityValidator(typeof(InvokeWorkflowValidator))]
|
||
|
[DefaultEvent("Invoking")]
|
||
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
||
|
public sealed class InvokeWorkflowActivity : Activity, ITypeFilterProvider
|
||
|
{
|
||
|
public static readonly DependencyProperty TargetWorkflowProperty = DependencyProperty.Register("TargetWorkflow", typeof(Type), typeof(InvokeWorkflowActivity), new PropertyMetadata(null, DependencyPropertyOptions.Metadata));
|
||
|
public static readonly DependencyProperty ParameterBindingsProperty = DependencyProperty.Register("ParameterBindings", typeof(WorkflowParameterBindingCollection), typeof(InvokeWorkflowActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata | DependencyPropertyOptions.ReadOnly, new Attribute[] { new BrowsableAttribute(false), new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content) }));
|
||
|
|
||
|
public static readonly DependencyProperty InvokingEvent = DependencyProperty.Register("Invoking", typeof(EventHandler), typeof(InvokeWorkflowActivity));
|
||
|
|
||
|
public static readonly DependencyProperty InstanceIdProperty = DependencyProperty.Register("InstanceId", typeof(Guid), typeof(InvokeWorkflowActivity), new PropertyMetadata(Guid.Empty));
|
||
|
|
||
|
internal static readonly ArrayList ReservedParameterNames = new ArrayList(new string[] { "Name", "Enabled", "Description", "TargetWorkflow", "Invoking", "ParameterBindings" });
|
||
|
|
||
|
#region Constructors
|
||
|
|
||
|
public InvokeWorkflowActivity()
|
||
|
{
|
||
|
//
|
||
|
base.SetReadOnlyPropertyValue(ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));
|
||
|
}
|
||
|
|
||
|
public InvokeWorkflowActivity(string name)
|
||
|
: base(name)
|
||
|
{
|
||
|
//
|
||
|
base.SetReadOnlyPropertyValue(ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
[SRCategory(SR.Activity)]
|
||
|
[SRDescription(SR.TargetWorkflowDescr)]
|
||
|
[Editor(typeof(TypeBrowserEditor), typeof(UITypeEditor))]
|
||
|
[DefaultValue(null)]
|
||
|
public Type TargetWorkflow
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return base.GetValue(TargetWorkflowProperty) as Type;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
base.SetValue(TargetWorkflowProperty, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Browsable(false)]
|
||
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||
|
public Guid InstanceId
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return (Guid)base.GetValue(InstanceIdProperty);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void SetInstanceId(Guid value)
|
||
|
{
|
||
|
//
|
||
|
base.SetValue(InstanceIdProperty, value);
|
||
|
}
|
||
|
|
||
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
||
|
[Browsable(false)]
|
||
|
public WorkflowParameterBindingCollection ParameterBindings
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return base.GetValue(ParameterBindingsProperty) as WorkflowParameterBindingCollection;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[SRCategory(SR.Handlers)]
|
||
|
[SRDescription(SR.InitializeCaleeDescr)]
|
||
|
[MergableProperty(false)]
|
||
|
public event EventHandler Invoking
|
||
|
{
|
||
|
add
|
||
|
{
|
||
|
base.AddHandler(InvokingEvent, value);
|
||
|
}
|
||
|
remove
|
||
|
{
|
||
|
base.RemoveHandler(InvokingEvent, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#region ITypeFilterProvider Members
|
||
|
|
||
|
bool ITypeFilterProvider.CanFilterType(Type type, bool throwOnError)
|
||
|
{
|
||
|
if (type == null)
|
||
|
throw new ArgumentNullException("type");
|
||
|
|
||
|
bool canFilterType = TypeProvider.IsAssignable(typeof(Activity), type) && type != typeof(Activity) && !type.IsAbstract;
|
||
|
if (canFilterType)
|
||
|
{
|
||
|
//This means that the type is DesignTimeType
|
||
|
IDesignerHost designerHost = ((IComponent)this).Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
|
||
|
if (designerHost != null && String.Compare(designerHost.RootComponentClassName, type.FullName, StringComparison.Ordinal) == 0)
|
||
|
{
|
||
|
if (throwOnError)
|
||
|
throw new InvalidOperationException(SR.GetString(SR.Error_CantInvokeSelf));
|
||
|
else
|
||
|
canFilterType = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (throwOnError && !canFilterType)
|
||
|
throw new Exception(SR.GetString(SR.Error_TypeIsNotRootActivity, "TargetWorkflow"));
|
||
|
|
||
|
return canFilterType;
|
||
|
}
|
||
|
|
||
|
string ITypeFilterProvider.FilterDescription
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return SR.GetString(SR.FilterDescription_InvokeWorkflow);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Execute
|
||
|
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
|
||
|
{
|
||
|
if (executionContext == null)
|
||
|
throw new ArgumentNullException("executionContext");
|
||
|
|
||
|
// raise event
|
||
|
base.RaiseEvent(InvokeWorkflowActivity.InvokingEvent, this, EventArgs.Empty);
|
||
|
|
||
|
// collect the [in] parameters
|
||
|
Dictionary<string, object> namedArgumentValues = new Dictionary<string, object>();
|
||
|
foreach (WorkflowParameterBinding paramBinding in this.ParameterBindings)
|
||
|
namedArgumentValues.Add(paramBinding.ParameterName, paramBinding.Value);
|
||
|
|
||
|
IStartWorkflow workflowInvoker = executionContext.GetService(typeof(IStartWorkflow)) as IStartWorkflow;
|
||
|
if (workflowInvoker == null)
|
||
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IStartWorkflow).FullName));
|
||
|
|
||
|
Guid instanceId = workflowInvoker.StartWorkflow(this.TargetWorkflow, namedArgumentValues);
|
||
|
if (instanceId == Guid.Empty)
|
||
|
throw new InvalidOperationException(SR.GetString(SR.Error_FailedToStartTheWorkflow));
|
||
|
|
||
|
this.SetInstanceId(instanceId);
|
||
|
|
||
|
return ActivityExecutionStatus.Closed;
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
}
|
||
|
|
||
|
#region validator
|
||
|
internal sealed class InvokeWorkflowValidator : ActivityValidator
|
||
|
{
|
||
|
public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
|
||
|
{
|
||
|
ValidationErrorCollection validationErrors = base.Validate(manager, obj);
|
||
|
|
||
|
InvokeWorkflowActivity invokeWorkflow = obj as InvokeWorkflowActivity;
|
||
|
if (invokeWorkflow == null)
|
||
|
throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(InvokeWorkflowActivity).FullName), "obj");
|
||
|
|
||
|
if (invokeWorkflow.TargetWorkflow == null)
|
||
|
{
|
||
|
ValidationError error = new ValidationError(SR.GetString(SR.Error_TypePropertyInvalid, "TargetWorkflow"), ErrorNumbers.Error_PropertyNotSet);
|
||
|
error.PropertyName = "TargetWorkflow";
|
||
|
validationErrors.Add(error);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ITypeProvider typeProvider = (ITypeProvider)manager.GetService(typeof(ITypeProvider));
|
||
|
if (typeProvider == null)
|
||
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
|
||
|
|
||
|
Type targetWorkflowType = invokeWorkflow.TargetWorkflow;
|
||
|
if (targetWorkflowType.Assembly == null && typeProvider.LocalAssembly != null)
|
||
|
{
|
||
|
Type workflowType = typeProvider.LocalAssembly.GetType(targetWorkflowType.FullName);
|
||
|
if (workflowType != null)
|
||
|
targetWorkflowType = workflowType;
|
||
|
}
|
||
|
|
||
|
if (!TypeProvider.IsAssignable(typeof(Activity), targetWorkflowType))
|
||
|
{
|
||
|
ValidationError error = new ValidationError(SR.GetString(SR.Error_TypeIsNotRootActivity, "TargetWorkflow"), ErrorNumbers.Error_TypeIsNotRootActivity);
|
||
|
error.PropertyName = "TargetWorkflow";
|
||
|
validationErrors.Add(error);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Activity rootActivity = null;
|
||
|
try
|
||
|
{
|
||
|
rootActivity = Activator.CreateInstance(targetWorkflowType) as Activity;
|
||
|
}
|
||
|
catch (Exception)
|
||
|
{
|
||
|
//
|
||
|
}
|
||
|
|
||
|
if (rootActivity == null)
|
||
|
{
|
||
|
ValidationError error = new ValidationError(SR.GetString(SR.Error_GetCalleeWorkflow, invokeWorkflow.TargetWorkflow), ErrorNumbers.Error_GetCalleeWorkflow);
|
||
|
error.PropertyName = "TargetWorkflow";
|
||
|
validationErrors.Add(error);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Exec can't have activate receive.
|
||
|
Walker walker = new Walker();
|
||
|
walker.FoundActivity += delegate(Walker w, WalkerEventArgs args)
|
||
|
{
|
||
|
if ((args.CurrentActivity is WebServiceInputActivity && ((WebServiceInputActivity)args.CurrentActivity).IsActivating))
|
||
|
{
|
||
|
ValidationError validationError = new ValidationError(SR.GetString(SR.Error_ExecWithActivationReceive), ErrorNumbers.Error_ExecWithActivationReceive);
|
||
|
validationError.PropertyName = "Name";
|
||
|
validationErrors.Add(validationError);
|
||
|
|
||
|
args.Action = WalkerAction.Abort;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
walker.Walk((Activity)rootActivity);
|
||
|
|
||
|
bool inAtomicScope = false;
|
||
|
Activity parentScope = invokeWorkflow.Parent;
|
||
|
while (parentScope != null)
|
||
|
{
|
||
|
if (parentScope is CompensatableTransactionScopeActivity || parentScope is TransactionScopeActivity)
|
||
|
{
|
||
|
inAtomicScope = true;
|
||
|
break;
|
||
|
}
|
||
|
parentScope = parentScope.Parent;
|
||
|
}
|
||
|
|
||
|
// Validate that if the workflow is transactional or being exec'd then it is not enclosed in an atomic scope.
|
||
|
if (inAtomicScope)
|
||
|
{
|
||
|
ValidationError validationError = new ValidationError(SR.GetString(SR.Error_ExecInAtomicScope), ErrorNumbers.Error_ExecInAtomicScope);
|
||
|
validationErrors.Add(validationError);
|
||
|
}
|
||
|
|
||
|
foreach (WorkflowParameterBinding paramBinding in invokeWorkflow.ParameterBindings)
|
||
|
{
|
||
|
PropertyInfo propertyInfo = null;
|
||
|
|
||
|
propertyInfo = targetWorkflowType.GetProperty(paramBinding.ParameterName);
|
||
|
if (propertyInfo == null)
|
||
|
{
|
||
|
ValidationError validationError = new ValidationError(SR.GetString(SR.Error_ParameterNotFound, paramBinding.ParameterName), ErrorNumbers.Error_ParameterNotFound);
|
||
|
if (InvokeWorkflowActivity.ReservedParameterNames.Contains(paramBinding.ParameterName))
|
||
|
validationError.PropertyName = ParameterInfoBasedPropertyDescriptor.GetParameterPropertyName(invokeWorkflow.GetType(), paramBinding.ParameterName);
|
||
|
|
||
|
validationErrors.Add(validationError);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Type parameterType = propertyInfo.PropertyType;
|
||
|
if (paramBinding.GetBinding(WorkflowParameterBinding.ValueProperty) != null)
|
||
|
{
|
||
|
ValidationErrorCollection memberErrors = ValidationHelpers.ValidateProperty(manager, invokeWorkflow, paramBinding.GetBinding(WorkflowParameterBinding.ValueProperty), new PropertyValidationContext(paramBinding, null, paramBinding.ParameterName), new BindValidationContext(parameterType, AccessTypes.Read));
|
||
|
|
||
|
if (memberErrors.Count != 0)
|
||
|
{
|
||
|
validationErrors.AddRange(memberErrors);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return validationErrors;
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
}
|