Introduction
Working as a design architect is a biggest challenge, especially when you have SharePoint 2010 bigmouth. We were working on a project with a few existing List with Software Product License and its expiry date. The administrator need to have alerts for all those Licenses which is going to be expired on the current date and the within the next 8 days. The best solution I thought is to write a workflow using SharePoint Designer 2010 and apply to the list. This workflow will find all the candidate items and send mail to the administrator.
Background SharePoint designer 2010 is the best friend of any SharePoint developer. Basically, there are some issues with a few of the actions and variable configuration. In particular when the requirement is to traverse and check for a field in all or multiple rows in the list. Any developer will immediately think of a loop especially a very handy For Each loop. But SharePoint designer 2010 does not support any kind of loop at all. Absence of loop lead me think of the best and quickest solution for this issue. I quickly jumped into the decision that I should write my custom activity which will track all the items in the list and update a filed. I will try to explain my design for the solution of this issue below.
I have added a field in the list, call it as “Processed”. This field can be helping us to know whether an Email is sent to administrator, if in case the item (License) is getting expired in 8 days. The default value for this field is “No” and we will set this value to “Yes”. This is fairly a simple most logic I am using for this solution as even the requirement is not too complicated!!!.
See the Conclusion and Links section at the end of this article for the code and more descriptions where you can download the solution.
Note We have to understand that we have a list which has records (items) with the License details and its expiry dates. The “Processed” field is the new field, which is hidden and used only for the purpose of our requirement.
The problem
The SharePoint Designer 2010 has no action/condition which can be used to traverse in the list to pick up all the items who are candidate for the condition of expiry.
The solution
Here are the quick steps to follow to write custom action for SharePoint Designer 2010 based workflow:
Step 1 : Working with Visual Studio and creating Solutions :
Quick steps : Open Visual Studio 2010 à New Project à SharePoint à 2010 à Empty SharePoint Project
Quick steps : Right click on Solution à Add New Project à Workflowà Workflow Activity library
Quick steps : Right click on Activity Library Project à Properties à Signingà Check “Sign the assembly” à Select “<New>” à Give a proper name for SNK key file. 4. Add References to Activity Library Project for Microsoft.SharePoint library and Microsoft.SharePoint.WorkflowActions library
Quick steps : Activity Library Project à Right Click on Referencesà Add Referenceà .NET Tabà Select “Microsoft.SharePoint” and “Microsoft.SharePoint.WorkflowActions” under “Components” 5. Click on the LicFinderActivityLib.cs and press F7. Or right click on the LicFinderActivityLib.cs and select “View Code” . (For your kind information, I have renamed the .cs file to LicFinderActivityLib.cs) Below is the snapshot of how the OWLicFinderActivytLib project looks like :
001.
using
System;
002.
System.ComponentModel;
003.
System.Workflow.ComponentModel.Compiler;
004.
System.Workflow.ComponentModel;
005.
System.Workflow.Activities;
006.
Microsoft.SharePoint;
007.
008.
namespace
OWLicFinderActivityLib
009.
{
010.
public
partial
class
LicFinderActivity : SequenceActivity
011.
012.
LicFinderActivity()
013.
014.
InitializeComponent();
015.
}
016.
/// <summary>
017.
/// Property Name : SiteUrl
018.
/// Usage : This will be used where you can set the Web URL address.
019.
/// </summary>
020.
static
DependencyProperty SiteUrlProperty = DependencyProperty.Register(
"SiteUrl"
,
021.
typeof
(
string
),
(LicFinderActivity),
new
PropertyMetadata(
""
));
022.
[DescriptionAttribute(
"Url of site where Licence List is saved"
)]
023.
[BrowsableAttribute(
true
024.
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
025.
[ValidationOption(ValidationOption.Optional)]
026.
SiteUrl
027.
028.
get
return
((
)(
base
.GetValue(LicFinderActivity.SiteUrlProperty))); }
029.
set
.SetValue(LicFinderActivity.SiteUrlProperty, value); }
030.
031.
032.
/// Property Name : LicenceListName
033.
/// Usage : The License List Name, on this list we are going to travarse.
034.
035.
DependencyProperty LicenceListNameProperty = DependencyProperty.Register(
"LicenseListName"
036.
037.
"Name for License list"
038.
039.
040.
041.
LicenceListName
042.
043.
044.
045.
.GetValue(LicFinderActivity.LicenceListNameProperty)));
046.
047.
048.
049.
.SetValue(LicFinderActivity.LicenceListNameProperty, value);
050.
051.
052.
053.
054.
/// This is the method is called within the workflow
055.
/// which will be calling the FOR EACH loop
056.
/// Notice on the "fx_FindAndSendMailsIfLicExp" method is
057.
/// getting called from Execute method.
058.
059.
/// <param name="executionContext"></param>
060.
/// <returns></returns>
061.
protected
override
ActivityExecutionStatus Execute(ActivityExecutionContext
062.
executionContext)
063.
064.
065.
fx_FindAndSendMailsIfLicExp();
066.
ActivityExecutionStatus.Closed;
067.
068.
069.
070.
/// Method called from "Execute" method (look the above code)
071.
072.
private
void
fx_FindAndSendMailsIfLicExp()
073.
074.
075.
// Site Url
076.
(SPSite oSPSite =
SPSite(SiteUrl))
077.
078.
// Get connected to the Web Application
079.
(SPWeb oSPWeb = oSPSite.RootWeb)
080.
081.
// Get the list the where we have all the licenses and its expiry dates.
082.
// No doubt we have Processed (hidden) field in the same list
083.
SPList oSPList = oSPWeb.Lists[
this
.LicenceListName];
084.
// Start the loop on all the items
085.
foreach
(SPListItem item
in
oSPList.Items)
086.
087.
// Default value of "Processed"
088.
item[
"Processed"
] =
"No"
;
089.
090.
// Get the Expire field. This field is a DateTime field
091.
DateTime dtExpire = (DateTime)item[
"Expire"
];
092.
093.
// Check if the Expire date is today!!
094.
if
(dtExpire == DateTime.Today)
095.
096.
"Yes"
// Set the processed field to YES
097.
098.
item.Update();
// Update the List Item
099.
100.
// Update the List
101.
oSPList.Update();
102.
// Update the Web
103.
oSPWeb.Update();
104.
105.
106.
107.
108.
3. To get the public key token, use SN.Exe with “–t” option. You can open Visual Studio Command prompt (preferably by running as Administrator). Go to the folder where you have the DLL file save, typically in Debug / Release folder of your project
Quick steps : Start MenuàAll Programs à Microsoft Visual Studio 2010à Visual Studio Tools à “Visual Studio Command Prompt” ( for running as Administrator, right click and select the option).
SN –T OWLicFinderActivity.dll
When the output gets printed on console select it using the following quick steps :
Quick steps : Click on System Menu of Visual Studio Command Promptà Select Edità Mark
The cursor can be used to select the public key token and after carefully selecting the full token hit Enter key. This will save the selection in clipboard. (Preferably save this token in notepad !)
Quick steps : Right Click on ProjectOWLicFinderActivityà Add Mapped Folder à Browse to Templateà 1033 à “Workflows”
Copy and paste below content into the .Actions file :
01.
<?
xml
version
=
"1.0"
encoding
"utf-8"
?>
02.
<
WorkflowInfo
>
03.
Actions
Sequential
"then"
Parallel
"and"
04.
Action
Name
"Check Licence List"
05.
ClassName
"OWLicFinderActivityLib.LicFinderActivity"
06.
Assembly
"OWLicFinderActivityLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=909ecdedcd7d8844"
07.
AppliesTo
"all"
08.
Category
"OW Activity"
09.
RuleDesigner
Sentence
"Licence List Name %1 to site %2."
10.
FieldBind
Field
"LicenceListName"
Text
"Licence List Name"
DesignerType
"TextArea"
Id
"1"
/>
11.
"Url of base site"
"2"
12.
</
13.
Parameters
14.
Parameter
Type
"System.String, mscorlib"
Direction
"In"
15.
16.
17.
18.
19.
The other stuff can be modified if required.
Quick steps : Double Click on Package.packageà Double click on Advanced à Click on Add à Add Existing Assemblyà select your assembly from the Debug / Release folder.
Step 2 : Updating the WEB.Config :
C:\inetpub\wwwroot\wss\VirtualDirectories\<yourport>\
SafeControl
Namespace
"OWLicFinderActivityLib"
TypeName
"*"
Safe
"True"
SafeAgainstScript
authorizedType
Authorized
Step 2 : Creating a SharePoint Designer 2010 Workflow with our activity
3. When the Workflow designer is opened I usually have two starting Log actions. This will help me understand the status of my Workflows, hence I have added 2 Log History actions one for Start and one for END.
Conclusion
The first workflow will do the job of finding all the items ( Software(s)) which are going to expire today by performing a FOR EACH kind of loop. Update the item if the software is getting expire by updating “Processed” field with the value “Yes”. This updating on item will trigger another workflow to send Email to relevant and concern administrator.
Maheshkumar S Tiwari edited Original. Comment: Added tags