This article gives a step by step guideline to add a custom Visual Studio workflow to the SharePoint designer. In here, I'm using VS 2010 and SharePoint 2010.
- Create a Empty Sequence Work Flow project.
Then, select .NET Framework 3.5 and select the Sequential Workflow Project.
In this sample, we are going to add custom string
functionality to the SharePoint designer. After creating the project, you will get a blank activity as follows:
Then delete that activity and add the Activity item to the project as above. I named that as subStringAfterText.cs.
After that, you will get a blank Sequence Activity.
Add References to the Project
After that, you need to add Microsoft.SharePoint.dll and Microsoft.SharePoint.WorkflowActions.dll to the project. Those DLLs can be found in the following paths:
- C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\Microsoft.SharePoint.dll
- C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\Microsoft.SharePoint.WorkflowActions.dll
Cording
My task to develop a simple string
function will return the text after the search text. This is so simple but you can use this method to develop any Custom SPD workflows.
1: using System;
2: using System.ComponentModel;
3: using System.ComponentModel.Design;
4: using System.Collections;
5: using System.Linq;
6: using System.Workflow.ComponentModel;
7: using System.Workflow.ComponentModel.Design;
8: using System.Workflow.ComponentModel.Compiler;
9: using System.Workflow.ComponentModel.Serialization;
10: using System.Workflow.Runtime;
11: using System.Workflow.Activities;
12: using System.Workflow.Activities.Rules;
13: using System.Diagnostics;
14: using Microsoft.SharePoint;
15: using Microsoft.SharePoint.WorkflowActions;
16: using Microsoft.SharePoint.Workflow;
17:
18: namespace getSubStringAfter
19: {
20: public partial class subStringAfterText : SequenceActivity
21: {
22:
23: private EventLog eventLog;
24:
25:
26:
27:
28: public static DependencyProperty SourceStringProperty =
System.Workflow.ComponentModel.DependencyProperty.Register
("SourceString", typeof(string), typeof(subStringAfterText));
29: public static DependencyProperty SearchStringProperty =
System.Workflow.ComponentModel.DependencyProperty.Register
("SearchString", typeof(string), typeof(subStringAfterText));
30: public static DependencyProperty FoundStringProperty =
System.Workflow.ComponentModel.DependencyProperty.Register
("FoundString", typeof(string), typeof(subStringAfterText));
31:
32: [Description("")]
33: [ValidationOption(ValidationOption.Required)]
34: [Browsable(true)]
35: [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
36: public string SourceString
37: {
38: get
39: {
40: return (string)base.GetValue(SourceStringProperty);
41: }
42: set
43: {
44: base.SetValue(SourceStringProperty, value);
45: }
46: }
47:
48: [Description("")]
49: [ValidationOption(ValidationOption.Required)]
50: [Browsable(true)]
51: [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
52: public string SearchString
53: {
54: get
55: {
56: return (string)base.GetValue(SearchStringProperty);
57: }
58: set
59: {
60: base.SetValue(SearchStringProperty, value);
61: }
62: }
63:
64: [Browsable(true)]
65: [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
66: public string FoundString
67: {
68: get
69: {
70: return (string)base.GetValue(FoundStringProperty);
71: }
72: set
73: {
74: base.SetValue(FoundStringProperty, value);
75: }
76: }
77:
78:
79: public static DependencyProperty
__ActivationPropertiesProperty = DependencyProperty.Register
("__ActivationProperties",
typeof(SPWorkflowActivationProperties), typeof(subStringAfterText));
80:
81:
82: public static DependencyProperty
WorkflowInstanceIdVariableProperty = DependencyProperty.Register
("WorkflowInstanceIdVariable", typeof(string), typeof(subStringAfterText));
83:
84:
85: public static DependencyProperty
__ContextProperty = DependencyProperty.Register
("__Context", typeof(WorkflowContext), typeof(subStringAfterText));
86:
87: [Description("The WorkflowInstanceId for the workflow.")]
88: [ValidationOption(ValidationOption.Required)]
89: public string WorkflowInstanceIdVariable
90: {
91: get { return (string)(base.GetValue(WorkflowInstanceIdVariableProperty)); }
92: set { base.SetValue(WorkflowInstanceIdVariableProperty, value); }
93: }
94:
95: [Description("The Workflow Properties")]
96: [ValidationOption(ValidationOption.Required)]
97: public SPWorkflowActivationProperties __ActivationProperties
98: {
99: get { return (SPWorkflowActivationProperties)
(base.GetValue(__ActivationPropertiesProperty)); }
100: set { base.SetValue(__ActivationPropertiesProperty, value); }
101: }
102:
103: [Description("The Workflow Context object")]
104: [ValidationOption(ValidationOption.Optional)]
105: [Browsable(false)]
106: [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
107: public WorkflowContext __Context
108: {
109: get
110: {
111: return (WorkflowContext)(base.GetValue(__ContextProperty));
112: }
113:
114: set
115: {
116: base.SetValue(__ContextProperty, value);
117: }
118: }
119:
120:
121: protected override ActivityExecutionStatus Execute
(ActivityExecutionContext executionContext)
122: {
123:
124: eventLog = new EventLog("Workflow");
125: eventLog.Source = "SharePoint Workflow";
126:
127: try
128: {
129:
130: getTheString();
131: }
132: finally
133: {
134:
135: eventLog.Dispose();
136: }
137:
138:
139: return ActivityExecutionStatus.Closed;
140: }
141:
142:
143: private void getTheString()
144: {
145: this.FoundString = SourceString.Substring
(SourceString.IndexOf(SearchString) + SearchString.Length -1);
146: }
147:
148: }
149: }
Code Explanation
Dependency properties are used to exchange data from workflow instance. Therefore, following properties are needed to exchange primary data.
This enables animation, styling, binding, etc.
public static DependencyProperty __ActivationPropertiesProperty =
DependencyProperty.Register("__ActivationProperties",
typeof(SPWorkflowActivationProperties), typeof(subStringAfterText));
public static DependencyProperty WorkflowInstanceIdVariableProperty =
DependencyProperty.Register("WorkflowInstanceIdVariable",
typeof(string), typeof(subStringAfterText));
public static DependencyProperty __ContextProperty =
DependencyProperty.Register("__Context",
typeof(WorkflowContext), typeof(subStringAfterText));
Ex :-
[Description("The WorkflowInstanceId for the workflow.")]
[ValidationOption(ValidationOption.Required)]
public string WorkflowInstanceIdVariable
{
get { return (string)(base.GetValue(WorkflowInstanceIdVariableProperty)); }
set { base.SetValue(WorkflowInstanceIdVariableProperty, value); }
}
public staticDependencyProperty SourceStringProperty =
System.Workflow.ComponentModel.DependencyProperty.Register
("SourceString",typeof(string),typeof(subStringAfterText));
public static DependencyPropertySearchStringProperty =
System.Workflow.ComponentModel.DependencyProperty.Register
("SearchString",typeof(string),typeof(subStringAfterText));
public static DependencyPropertyFoundStringProperty =
System.Workflow.ComponentModel.DependencyProperty.Register
("FoundString",typeof(string),typeof(subStringAfterText));
{
eventLog =new EventLog("Workflow");
eventLog.Source ="SharePoint Workflow";
try
{
getTheString();
}
finally
{
eventLog.Dispose();
}
returnActivityExecutionStatus.Closed;
}
Sign the application.
After that, you should sign the application using a strong key. Thus you can go to project properties and sign the application as follows:
Build your application and place the assembly to the GAC. In here, there are two GACs maintained with framework 4.0
- C:\Windows\Microsoft.NET\assembly
- C:\Windows\assembly
To work the assembly, this should be registered under “C:\Windows\assembly” if you use Target Framework as 4.0, then it will register the assembly in C:\Windows\Microsoft.NET\assembly. Therefore use target framework as 3.5
Register Assembly Under “C:\Windows\assembly”.
Make sure the target framework is 3.5 of the project. if so, it will get added to the location “C:\Windows\assembly”.
For that:
- Go to the Visual Studio Command Prompt as administrator
- Go to your bin/debug folder (place where the DLL is built)
- Type gacutil /i getSubStringAfter.dll
If you did it correctly, you can see your assembly in the GAC. to view the GAC you can type “C:\Windows\assembly” in the Run Window.
Creating workflow template actions file.
Then you need to create .ACTIONS file. This is the file that is used by the SPD to get the workflow information. Therefore, create a file named getSubStringAfter.ACTIONS
and put the following code there. You need to put correct public key token, namespace and class name.
1: ="1.0"="utf-8"
2: <WorkflowInfo Language="en-us" >
3: <Actions Sequential="then" Parallel="and">
4: <Action Name="get the substring after the text"
5: ClassName="getSubStringAfter.subStringAfterText"
6: Assembly="getSubStringAfter, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=d98a44afbf8ccb86"
7: AppliesTo="all"
8: Category="Custom String Actions">
9: <RuleDesigner Sentence="Search %1 from %2 and store in %3.">
10: <FieldBind Field="SearchString"
Text="this text" DesignerType="stringbuilder" Id="1"/>
11: <FieldBind Field="SourceString"
Text="this address" Id="2" DesignerType="
stringbuilder" />
12: <FieldBind Field="FoundString"
Text="variable" Id="3" DesignerType="ParameterNames" />
13: </RuleDesigner>
14: <Parameters>
15: <Parameter Name="SearchString" Type="System.String,
mscorlib" Direction="In" />
16: <Parameter Name="SourceString" Type="System.String,
mscorlib" Direction="In" />
17: <Parameter Name="FoundString" Type="System.String,
mscorlib" Direction="Out" />
18: </Parameters>
19: </Action>
20: </Actions>
21: </WorkflowInfo>
Then copy this file and put into the following SharePoint server location C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\1033\Workflow.
Modify the Web Config
Then, you need to modify the web.config of your site. You need to put SafeControl
and authorizedType
in here. Also, please make sure public key token, namespace, version and class is correct, otherwise it will not work for an example it may not show in the SPD, or it will not get added to the workflow step though it showed in the SPD.
<authorizedTypeAssembly="getSubStringAfter, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=d98a44afbf8ccb86"Namespace="getSubStringAfter"TypeName="subStringAfterText"
Authorized="True"/><SafeControlAssembly="getSubStringAfter, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=d98a44afbf8ccb86"Namespace="getSubStringAfter"
TypeName="*"Safe="True"/>
Finally ..
- Reset the IIS:
- Now open the SPD:
I took nearly one week to do figure this out. Anyway, finally I got a solution. :-)