I have just spent a very frustrating day trying to figure out how to get access to the resource found by the EnumerateResourcesActivity, not helped even slightly by the usual machine-generated “documentation“. I’m still not very happy with it, and can’t for the life of me understand why it can’t give me a straight object collection as output, but at least I’ve got the data I need from it now.
The EnumerateResourcesActivity is the recommended way to search for objects using an XPath filter. But, quite bizarrely, the only readily accessible data you get back from it is how many objects it found – not the actual objects! This is despite the fact that one of the input parameters is a list of attributes you want back. I feel cheated!!
The only time I’d used this activity before was for checking uniqueness, and all I needed then was an object count. But today I needed to write a custom Notification Activity and (as there’s no way I know of to add an Identity Picker to a custom workflow UI)Â I wanted to be able to specify the email template by it’s name.
Clearly this was going to involve an object lookup as I need to specify the template’s ResourceID going in to the EmailNotificationActivity. In this example the “searchEmailTemplate” activity is the EnumerateResourcesActivity, and I only expect it to return one object.
This is where all the pain started, and if it hadn’t been for the following blog posts I never would have worked this out:
http://c–shark.blogspot.com.au/2009/04/how-to-use-enumerateresourcesactivity.html#comment-form (including comments as it was Luka who had the crucial bit of advice that you need to set all the properties on the EnumerateResourcesActivity going in).
http://bennettadelson.wordpress.com/2012/02/20/fim-2010-user-rcdc-to-add-user-to-groups/
http://blog.clauskonrad.net/2011/11/fim-2010-how-to-use-std.html
http://www.fimspecialist.com/fim-portal/custom-workflow-examples/custom-workflow-example-enumerate-resources-activity/
So thank you very much lovely bloggers for sharing your experiences on this!
The Code
The first totally weird thing you have to do is hack the Designer code for your custom workflow. I’m using VB.NET so mine is called <ActivityName>.Designer.vb. I found I had to click “Show All Files” to see it:
We have to completely ignore the message that says we shouldn’t edit this code and do the following:
- Add a declaration for codeActivity1 at the end of the class, and
- Add the lines as shown before “Me.CanModifyActivities = False” inside the InitializeComponent Sub.
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _ Partial Class AlternateEmailNotification 'NOTE: The following procedure is required by the Workflow Designer 'It can be modified using the Workflow Designer. 'Do not modify it using the code editor. <System.Diagnostics.DebuggerNonUserCode()> _ <System.CodeDom.Compiler.GeneratedCode("", "")> _ Private Sub InitializeComponent() ... (pre-existing code) ... ' ' Manually added code for the EnumerateResourcesActivity ' Me.codeActivity1 = New System.Workflow.Activities.CodeActivity() Me.codeActivity1.Name = "codeActivity1" AddHandler Me.codeActivity1.ExecuteCode, AddressOf Me.GetEmailTemplate_ExecuteCode 'Make the codeActivity the child of the EnumerateResourcesActivity Me.searchEmailTemplate.Activities.Add(Me.codeActivity1) Me.CanModifyActivities = False End Sub ... (pre-existing declarations) ... 'Manually added code activity that allows access to objects returned by EnumerateResourcesActivity Private codeActivity1 As CodeActivity End Class
In the code for the activity itself (AlternateEmailNotification.vb in the picture above) I add the following code which is being called by that handler we added above. This does actually manage to get you the first object returned by the enumeration. (I still don’t know how to get at all the objects found but don’t need to for this activity – leaving that for another day.)
Private Sub GetEmailTemplate_ExecuteCode(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim currentItem As ResourceType = TryCast(EnumerateResourcesActivity.GetCurrentIterationItem(DirectCast(sender, CodeActivity)), ResourceType)
If currentItem Is Nothing Then
Throw New WorkflowTerminatedException("Unable to find email template " & Me.Template)
End If
'TemplateID is a System.Guid declared globally
TemplateID = currentItem.ObjectID.GetGuid
End Sub
Now back on more familiar ground, here’s the code activity that runs just before the EnumerateResourcesActivity to set the scene. Remember as I’ve mentioned you have to set all the properties. If you don’t you wind up with “Nothing” instead of a resource.
Private Sub initSearch_ExecuteCode(ByVal sender As System.Object, ByVal e As System.EventArgs) searchEmailTemplate_ActorId1 = New Guid(FIMADMIN_GUID) Dim filter As String = "/EmailTemplate[DisplayName ='" & Me.Template & "']" searchEmailTemplate_XPathFilter1 = filter searchEmailTemplate_Selection1 = New String() {"DisplayName"} searchEmailTemplate_PageSize1 = 100 searchEmailTemplate_SortingAttributes1 = Nothing searchEmailTemplate_TotalResultsCount1 = 0 End Sub
Finally now I set up my EmailNotificationActivity, which was at least as simple as advertised.
Private Sub initNotification_ExecuteCode(ByVal sender As System.Object, ByVal e As System.EventArgs) emailNotificationActivity_To1 = EmailOther emailNotificationActivity_EmailTemplate1 = TemplateID End Sub
Hi Carol – thank you for the awesomely clear write-up for this issue. It’s been sending me nuts for days, and your explanation and solution got me working. Much appreciated.
That’s an obscure one isn’t it. Glad I could help!