September 19, 2016

Quick notes on debugging code workflows in SharePoint

You have a custom workflow in SharePoint 2010 or 2013, where it reads some configuration keys from web.config then continue to do some business logic.

What's the issue?
So you added the 2 keys to your web application web.config on your WFE server. The workflow worked just fine a couple of time, and was able to read the config keys, then the next time it failed to read one or both of the keys! The occurrence is sporadic and its kind of hit or miss!
2 cases from ULS: first time it fails to find key1, then next time it fails to find key2!

Let's debug:
First things first! Workflows run by both w3wp & owstimer processes.
In SharePoint, workflow always start running by the World Wide Web Publishing service (w3wp.exe). If it goes to sleep (by a pause or delay activities or excessive load), then the 'SPTimerV4' SharePoint Foundation Workflow Timer service (owstimer.exe) will wake it up and run it.
SharePoint will automatically decide which Workflow Timer service will run the workflow. The operation can occur on any server running the "Microsoft SharePoint Foundation Workflow Timer Service" service.

To debug at run time, attach VS 2010 to the w3wp and owstimer process to detect which one it is.

After deploying new code the timer service must be restarted (iisreset will not suffice)
net stop sptimerv4
net start sptimerv4

To avoid wasting time figuring out why it didn't read the config keys, let's use a method to tell us the file name and machine name the code was trying to read the config key. Use it like this:

string KeyValue = getConfigKeyValue("MyKey");

Here is the nice method:

private string getConfigKeyValue(string keyName)
            string KeyVal = string.Empty;
            bool error = false;
                KeyVal = ConfigurationManager.AppSettings[keyName];
                if (KeyVal == null)
                    error = true;
            catch (Exception)
                error = true;

            if (error)
                KeyVal = string.Format("The key '{0}' was not found in file {1} in machine {2}",
                    keyName, AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, Environment.MachineName);
                throw new Exception(KeyVal);
            return KeyVal;

That way we can find and set the missing key easily.

Example 1:
System.Exception: The key 'key1' was not found in file D:\inetpub\WWWROOT\wss\VirtualDirectories\7001\web.config in machine DevServerWFE1

Example 2:
System.Exception: The key 'key1' was not found in file C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\BIN\OWSTIMER.EXE.Config in machine DevServerWFE1