Dynamically Invoking SharePoint Designer Workflow

Hi,

Is it possible to provide workflow type forInvokeWorkflowActivity dynamically?

i.e., I'd like to use theInvokeWorkflowActivity in other workflow, but exact type of workflow is not known in design time.

Thanks,

Mark

[286 byte] By [MarkGoldstein] at [2007-12-24]
# 1

There is no way to do this with the out of the box InvokeWorkflowActivity.The TargetWorkflow property is a metadata property. Metadata properties must be set at design time and can’t be updated at runtime.However, you can create your own custom activity like the following which should get you started:

using System;

using System.ComponentModel;

using System.Workflow.ComponentModel;

using System.Workflow.ComponentModel.Design;

using System.Workflow.ComponentModel.Compiler;

using System.Drawing.Design;

using System.Collections.Generic;

namespace ActivityLibrary1

{

public partial class CustomInvokeWorkflowActivity : Activity, ITypeFilterProvider

{

public static readonly DependencyProperty TargetWorkflowProperty = DependencyProperty.Register("TargetWorkflow", typeof(Type), typeof(CustomInvokeWorkflowActivity), new PropertyMetadata(null));

public static readonly DependencyProperty ParameterBindingsProperty = DependencyProperty.Register("ParameterBindings", typeof(WorkflowParameterBindingCollection), typeof(CustomInvokeWorkflowActivity), new PropertyMetadata(DependencyPropertyOptions.ReadOnly, new Attribute[] { new BrowsableAttribute(false), new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content) }));

public CustomInvokeWorkflowActivity()

{

base.SetReadOnlyPropertyValue(ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));

InitializeComponent();

}

#region Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

//

// CustomInvokeWorkflowActivity

//

this.Name = "CustomInvokeWorkflowActivity";

}

#endregion

[Category("Activity")]

[Description("Type of workflow to invoke")]

[Editor(typeof(TypeBrowserEditor), typeof(UITypeEditor))]

[DefaultValue(null)]

public Type TargetWorkflow

{

get

{

return base.GetValue(TargetWorkflowProperty) as Type;

}

set

{

base.SetValue(TargetWorkflowProperty, value);

}

}

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]

[Browsable(false)]

public WorkflowParameterBindingCollection ParameterBindings

{

get

{

return base.GetValue(ParameterBindingsProperty) as WorkflowParameterBindingCollection;

}

}

#region ITypeFilterProvider Members

bool ITypeFilterProvider.CanFilterType(Type type, bool throwOnError)

{

bool canFilterType = TypeProvider.IsAssignable(typeof(Activity), type) && type != typeof(Activity) && !type.IsAbstract;

if (throwOnError && !canFilterType)

throw new Exception("Type does not derive from Activity");

return canFilterType;

}

string ITypeFilterProvider.FilterDescription

{

get

{

return "Select a Type that derives from Activity.";

}

}

#endregion

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)

{

if (this.TargetWorkflow == null)

{

throw new InvalidOperationException("TargetWorkflow property must be set to a valid Type that derives from Activity.");

}

Dictionary<string, object> parameters = new Dictionary<string, object>();

foreach (WorkflowParameterBinding parameterBinding in this.ParameterBindings)

parameters.Add(parameterBinding.ParameterName, parameterBinding.Value);

(executionContext.GetService(typeof(IStartWorkflow)) as IStartWorkflow).StartWorkflow(this.TargetWorkflow, parameters);

return ActivityExecutionStatus.Closed;

}

}

}

TomLake at 2007-8-31 > top of Msdn Tech,Software Development for Windows Vista,Windows Workflow Foundation...
# 2

Hi,

I created custom invokeworkflow activity by using the above code. It is working fine.

but i want to get the created instance id (for child workflow) back to the parent workflow from the custom invokeWorkflow. For that i created a dependency property to get the instanceid and accessed from parentworkflow. I am not getting the original created instanceid but getting 0000000000000000(zeros).

Please give me suggestion.

hari

Kila at 2007-8-31 > top of Msdn Tech,Software Development for Windows Vista,Windows Workflow Foundation...
# 3

IStartWorkflow.StartWorkflow returns the InstanceId for the invoked workflow.In the example I ignore the return value but you could make the following changes.

Add the following property:

public static readonly DependencyProperty InstanceIdProperty = DependencyProperty.Register("InstanceId", typeof(Guid), typeof(CustomInvokeWorkflowActivity));

[Category("Activity")]

[Description("InstanceId of workflow that is invoked")]

public Guid InstanceId

{

get

{

return (Guid)base.GetValue(InstanceIdProperty);

}

set

{

base.SetValue(InstanceIdProperty, value);

}

}

Update the StartWorkflow line in the Execute method to:

base.SetValue(InstanceIdProperty, (executionContext.GetService(typeof(IStartWorkflow)) as IStartWorkflow).StartWorkflow(this.TargetWorkflow, parameters));

Now you can bind the property to a variable and you are able to use the InstanceId later in the workflow if you need to.

TomLake at 2007-8-31 > top of Msdn Tech,Software Development for Windows Vista,Windows Workflow Foundation...
# 4
How do you get at this DependencyProperty value from outside the workflow in another piece of code? I have a WorkflowInstance object from the WorkflowRuntime, but I don't know where to go from there. Thanks.

Mike

miguelito928 at 2007-8-31 > top of Msdn Tech,Software Development for Windows Vista,Windows Workflow Foundation...
# 5
You can't directly access the value. What you have to do is use tracking or a CallExternalMethodActivity.
TomLake at 2007-8-31 > top of Msdn Tech,Software Development for Windows Vista,Windows Workflow Foundation...
# 6

Hi Mark,

To provide some additional information, you can use WorkflowChanges to insert an InvokeWorkflowActivity dynamically, and specify the type at the time that you make this change, like this:

private void AddApproval(object sender, EventArgs e)
{
InvokeWorkflowActivity invokeNewStepWorkflow = new InvokeWorkflowActivity();
// use WorkflowChanges class to author dynamic change
WorkflowChanges changes = new WorkflowChanges(this);
// setup to invoke NewStepWorkflow type
Type type = typeof(DynamicUpdateInWorkflow.Workflow2);
invokeNewStepWorkflow.Name = "Workflow2";
invokeNewStepWorkflow.TargetWorkflow = type;
// insert invokeNewStepWorkflow in ifElseApproval
// transient activity collection
CompositeActivity ifElse = changes.TransientWorkflow.Activities["ifElseActivity1"] as CompositeActivity;
CompositeActivity branch1 = ifElse.Activities["ifElseBranchActivity1"] as CompositeActivity;
branch1.Activities.Add(invokeNewStepWorkflow);
// Add a HandleExternalEvent after this InvokeWorkflow
HandleExternalEventActivity hev = new HandleExternalEventActivity();
hev.InterfaceType = typeof(DynamicUpdateInWorkflow.ILocalService);
hev.EventName = "InvokedWorkflowComplete";
branch1.Activities.Add(hev);
// apply transient changes to instance
this.ApplyWorkflowChanges(changes);
Console.WriteLine("\tAdded a new step from within workflow");
}

Steve Danielson [Microsoft]
This posting is provided "AS IS" with no warranties, and confers no rights.
Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm


SteveDanielson at 2007-8-31 > top of Msdn Tech,Software Development for Windows Vista,Windows Workflow Foundation...
# 7
Steve is correct that you can use dynamic update to change the running workflow. Dynamic update does however have a performance cost that you would not have to pay if you use the custom activity.
TomLake at 2007-8-31 > top of Msdn Tech,Software Development for Windows Vista,Windows Workflow Foundation...
# 8

Steve,

Thanks you for such an idea.

Speaking about the design I was checking and thinking about:

  • I did want to pass the name (in a qualified form, of course :) of the workflow to run to the "workflows gateway" (which is a workflow by itself)
  • I'd like to run it asynchronously as well (the secondary workflow)
  • I'd like to deploy the "gateway" as a service

Any ideas/caveats to avoid?

Thanks

MarkGoldstein at 2007-8-31 > top of Msdn Tech,Software Development for Windows Vista,Windows Workflow Foundation...
# 9
Is it possible to use the InvokeWorkflowActivity in a custom Workflow to invoke a Workflow created by SharePoint Designer? I can't figure out how to get the System.Type of the Workflow that SharePoint Designer creates.
RobinH.Sanner at 2007-8-31 > top of Msdn Tech,Software Development for Windows Vista,Windows Workflow Foundation...

Software Development for Windows Vista

Site Classified