Nintex Custom Actions – Error Handling


A while ago now, I wrote a blog post about Nintex Custom Actions. This was written for SharePoint 2010. I have recently worked on a project where I’ve got a chance to use Nintex again. My own blog post came in very handy, and I have updated it so it now explains what you need to do for SharePoint 2013. To be honest there isn’t much difference. Mainly location of Nintex dll’s, and remembering to put /_layouts/15 when pointing to layout files.

Some of the out of the box Custom actions has an error handling section when configuring.

There are 3 parts to error handling.

  1. Capture Errors – If there is an error should the custom action capture it (Yes/No)
  2. Store error occurrence in – This stores if an error occurred or not. (Yes/No)
  3. Store error text in – This stores the actual error message returned if there is one (Single line of text)

This blog post will show you which files you will need to update and what code is requried, to make your custom action have Error handling section. Please ensure you know how to create a Custom Action from reading my previous blog post, as I won’t be going over old ground. I have added custom error handling to my previous project “Retrieve from Property Bag.” If the property doesn’t exist in the property bag then it will throw an error, this will allow my workflow to take a different path.

ReadFromPropertyBagActivity.cs

First we will need to add public static DependencyProperties for the 3 fields within Error Handling, add these below the previous Dependency properties.

#region Error Handling
//Determines if error handling has been switched on for this activity by the workflow designer.
public static DependencyProperty CaptureErrorsProperty = DependencyProperty.Register("CaptureErrors", typeof(bool), typeof(ReadFromPropertyBagActivity));

//Stores whether or not an error occured.
public static DependencyProperty ErrorOccurredOutputProperty = DependencyProperty.Register("ErrorOccurredOutput", typeof(bool), typeof(ReadFromPropertyBagActivity));

//Stores the details of an error if one occurred.
public static DependencyProperty ErrorMessageOutputProperty = DependencyProperty.Register("ErrorMessageOutput", typeof(string), typeof(ReadFromPropertyBagActivity));
#endregion

Then each of these Dependency Properties will have its own public property.

#region Error Dependency Properties
public bool CaptureErrors
{
    set { base.SetValue(CaptureErrorsProperty, value); }
    get { return (bool)base.GetValue(CaptureErrorsProperty); }
}

public bool ErrorOccurredOutput
{
    set { base.SetValue(ErrorOccurredOutputProperty, value); }
    get { return (bool)base.GetValue(ErrorOccurredOutputProperty); }
}

public string ErrorMessageOutput
{
    set { base.SetValue(ErrorMessageOutputProperty, value); }
    get { return (string)base.GetValue(ErrorMessageOutputProperty); }
}
#endregion

Still within the ReadFromPropertyBagActivity.cs file, the Execute method will needs to be updated. Below I have put the original Execute method and highlighted the extra code required for Error Handling.

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
    //Standard Nintex code to obtain context.
    ActivityActivationReference.IsAllowed(this, __Context.Web);
    NWWorkflowContext ctx = NWWorkflowContext.GetContext(
       this.__Context,
       new Guid(this.__ListId),
       this.__ListItem.Id,
       this.WorkflowInstanceId,
       this);
    base.LogProgressStart(ctx);
 
   //Get the property value.
   string resolvedProperty = ctx.AddContextDataToString(this.Property);

   var result = "";

   //Using the context get the property if it exists.
   if (ctx.Web.AllProperties.ContainsKey(resolvedProperty))
   {
       result = ctx.Web.AllProperties[resolvedProperty].ToString();

       if(CaptureErrors)
            ErrorOccurredOutput = false;

        //store the result.
        this.ResultOutput = result;
    }
    else
    {
        if (CaptureErrors)
        {
            ErrorOccurredOutput = true;
            ErrorMessageOutput = String.Format("Unable to find property bag key:{0}", resolvedProperty);
        }
    }

    //End Execution.
    base.LogProgressEnd(ctx, executionContext);
    return ActivityExecutionStatus.Closed;
}

What is happening here is that if the web site contains the property, then if the user sets the custom action to capture errors then set the ErrorOccurredOutput to false. If the property doesn’t exist, and the user has set the custom action to capture errors then will need to set the ErrorOccurredOutput to true and set the error message in the ErrorMessageOutput property.

ReadFromPropertyBagAdapter.cs

In this file there are only two methods that require code change to include the Error Handing. These methods are AddActivityToWorkflow and GetConfig.

Within the AddActivityToWorkflow, after setting the activity.SetBinding but before the ActivityFlags add the following piece of code.

if (context.Config.ErrorHandling != null)
{
    context.Config.ErrorHandling.AssignTo(activity,
        ReadFromPropertyBagActivity.CaptureErrorsProperty,
        ReadFromPropertyBagActivity.ErrorOccurredOutputProperty,
        ReadFromPropertyBagActivity.ErrorMessageOutputProperty,
        context);
}

Within the GetConfig method, add the error handling code just before we return the NWActionConfig.

config.ErrorHandling = ErrorHandling.BuildFrom(context.Activity,
                ReadFromPropertyBagActivity.CaptureErrorsProperty,
                ReadFromPropertyBagActivity.ErrorOccurredOutputProperty,
                ReadFromPropertyBagActivity.ErrorMessageOutputProperty,
                context.Variables);

ReadFromPropertyBagDialog.cs

This is the final piece of the puzzle. This is the configuration screen when you edit the custom action. There is two javaScript functions (TPARetrieveConfig and TPAWriteConfig) that needs updating, then lastly we will need to update the HTML to display, that uses a registered control.

Add the register control.

<%@ Register TagPrefix="Nintex" TagName="ErrorHandlingConfig" Src="~/_layouts/15/NintexWorkflow/ErrorHandlingConfig.ascx" %>

Nintex has already written the JavaScript to make the error handling work, therefore we just need to call it.

TPARetrieveConfig – This loads and displays previous saved values.

function TPARetrieveConfig() {
            setRTEValue('<%=propertyProperty.ClientID%>', configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='Property']/PrimitiveValue/@Value").text);
            document.getElementById('<%=resultOutput.ClientID%>').value = configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='ResultOutput']/Variable/@Name").text;
 
            LoadErrorHandlingSection();
}

TPAWriteConfig – This saves properties back to the custom action.

function TPAWriteConfig() {
            configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='Property']/PrimitiveValue/@Value").text = getRTEValue('<%=propertyProperty.ClientID%>');

            var resultOuputCtrl = document.getElementById('<%=resultOutput.ClientID%>');

            if (resultOuputCtrl.value.length > 0) {
                configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='ResultOutput']/Variable/@Name").text = resultOuputCtrl.value;
            }

            SaveErrorHandlingSection();

            return true;
        }

Finally we need to add the HTML to the page. This is within the content place holder ID PlaceHolderMain. This is added just before the closing </TemplateRowsArea>.

<Nintex:ConfigurationPropertySection runat="server" Id="MainControls1">
              <TemplateRowsArea>
               <Nintex:ConfigurationProperty runat="server" FieldTitle="Property Bag Property" RequiredField="True">
                   <TemplateControlArea>
                        <Nintex:SingleLineInput clearFieldOnInsert="true" filter="number" runat="server" id="propertyProperty"></Nintex:SingleLineInput>
                  </TemplateControlArea>
                </Nintex:ConfigurationProperty>

                <Nintex:ConfigurationProperty runat="server" FieldTitle="Result Output" RequiredField="False">
                  <TemplateControlArea>
                    <Nintex:VariableSelector id="resultOutput" runat="server" IncludeTextVars="True"></Nintex:VariableSelector>
                  </TemplateControlArea>
                </Nintex:ConfigurationProperty>

                <Nintex:ErrorHandlingConfig runat="server" id="errorHandlingConfig1"></Nintex:ErrorHandlingConfig>
              </TemplateRowsArea>
            </Nintex:ConfigurationPropertySection>

  <Nintex:DialogBody runat="server" id="DialogBody">
  </Nintex:DialogBody>

After I have deployed this custom action to SharePoint (All explained how in previous Nintex blog) my custom action when configured now shows the Error Handling section. I have already configured my custom action in the below screenshot.

You will need to create two workflow variables. I have created ErrorOccurred (Yes/No) and ErrorMessage (Single line of text).

Then in my workflow I have a “Set a condition” workflow action, that is configured to equal to true if ErrorOccured equals Yes. If no error occurs then I set my field value as I did previously before I include error handling, however if there is an error I log this error in the history list.

When running the workflow I have looked for a property bag key called NotThere. This has caused the workflow to error when retrieving the property from the property bag.

And below is the error in the history list.

You can download my updated SharePoint 2013 version of my ReadFromPropertyBag custom action with Error Handling from my OneDrive.

Advertisements