Things I’ve been learning about debugging custom workflows

I have finally jumped into the world of FIM 2010 custom workflow activites, since the release of a good walkthrough document. Of course I decided it would be much easier to convert it all to VB.NET … which then gave me ample opportunities for troubleshooting. Thanks to Anthony Ho and Paolo Tedesco for all the hand-holding!

Object Browser

The first mistake I made was to get the Type Name wrong in the Activity Information Configuration (AIC) object. This turned out to be because VB.NET handles the default namespace differently to VC# and my WebUI part ended up with a completely different name than I’d expected. By using the Object Browser (opened from the View menu in Visual Studio) I could immediately see what the Type Name should have been.

Here’s a picture of what my project currently looks like:

So when configuring my AIC for the RequestLoggingActvity I set Activity Name = “FIM.CustomWorkflowActivitiesLibrary.Activities.RequestLoggingActivity” and Type Name = “FIM.CustomWorkflowActivitiesLibrary.Activities.WebUIs.RequestLoggingActivitySettingsPart”.

And when configuring an AIC for the PowershellActivity I set Activity Name = “FIM.CustomWorkflowActivitiesLibrary.Activities.PowershellActivity” and Type Name = “FIM.CustomWorkflowActivitiesLibrary.Activities.WebUIs.PowershellActivitySettingsPart”.

Enable Portal Trace Logging

I knew how to enable trace logging for the FIM Service, but until Anthony told me how, I had no idea you could get a different service trace from the Portal. Have a look at this thread on the FIM forum where he tells me how to enable it by editing the web.config file.

Attach the VS Debugger

There is an official document called Debugging Custom Activities but it misses out one crucial step. I compiled my code with full Debug selected, but I kept getting “No symbols have been loaded”. The missing step is covered in this blog post: You Don’t Need to Copy PDB Files to Debug in the GAC!

The document tells you to attach to Microsoft.ResourceManagement.Service.exe to debug the activity execution part, and to w3wp.exe to troubleshoot the UI part, but doesn’t mention that there might be a number of instances of w3wp.exe and you need to get the right one. Just attach to them in turn until your breakpoints are hittable.

Also note, if you’re getting an Access Denied message when trying to attach the debugger you need to make sure you select Managed code. This is mentioned in the documentation, but easy to miss.

I also had a problem with the compile options being set to “optimized” by default. When I attached the debugger all the variables appeared to be “Nothing” and loops were skipped straight through. After wasting several days on this I figured out that I had to go into Properties -> Compile -> Advanced Compile Options and remove the tick next to “Enable optimizations”.

Write messages into the Event Log

This is just something I like to do because it’s easy to create events and it’s a good way to track errors, or indeed as a confirmation that your code has actually run. This function can be used to create events, though note you may have to make a reg change for the CreateEventSource method to work, o you could just use powershell to create the new event log source manually.

Make a simple console application that you can run directly

It is more complicated to debug your code with Sharepoint and FIM in the mix so it can help to copy your code into a simpler form that you can run directly.

For the Activity code you could try copying it to a simple Console application, using hard-coded constants in place of the values that should come from the workflow activity definition in the Portal. Depending on the nature of your activity you may be able to run and test the code standalone before encorportaing it into your FIM activity.

It’s harder to test the WebUI part of the code on it’s own (at least, I don’t know how to) but you can call the WebUI part of your dll direct from a Console appliaction and run it in Visual Studio. While it doesn’t do anything it will at least show you directly any error messages.

In the following Console app there are two arguments to Activator.CreateInstance. The first is the Assembly Name string from the AIC, and the second is the Type Name string.

Module Module1

    Sub Main()
        Activator.CreateInstance("Microsoft.IdentityManagement.Activities, Version=4.0.2592.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", "Microsoft.IdentityManagement.WebUI.Controls.PWResetActivitySettingsPart")
    End Sub

End Module