You are viewing limited content. For full access, please sign in.

Question

Question

Token validation in custom Workflow activities

asked on April 24, 2019

We're building custom workflow activities with custom Edit Panels.  We want these activities to validate tokens exist in the workflow while publishing. Is there any way of validating the tokens exist in the proxy (like in the Validate_Property method) so we can add warnings while publishing (or when just using the "Validate Workflow..." action)?

1 0

Answer

SELECTED ANSWER
replied on May 10, 2019 Show version history

Michael,

It would appear that the proxy code itself exposes the methods that will allow you to do what you want. 

Here are some screen snips of the code in action;

Here is the code I used. 

First we need to call our new routine from the existing proxy token validation sub.  Any other validation subs from other tokens exposed in our activity will also need to call this same routine .

/// <summary>
/// Validates the 'MyToken' property by adding validation errors and/or warnings to the specified IValidationErrorCollection.
/// </summary>
protected virtual void ValidateProperty_MyToken(IValidationErrorCollection collection)
{
    // TODO: Add code for validating the MyToken property here. For example:
    // 
    // Ensure that MyToken is not null.  If it isnt null then call the routine to validate any tokens exposed...
    if ((string.IsNullOrEmpty(this.MyToken)))
        collection.AddError("This property must be specified.");
    else
        this.ValidateToken(collection, MyTokenPropertyName, this.MyToken);
}

The new sub is called 'ValidateToken'.  In that new sub we are going to get a list of tokens from other activities to parse.  The existing proxy method 'RetrieveTokenDataFromContextActivity' seems to provide only the tokens from other activities that are 'above' our activity in the workflow.  We are going to parse those tokens to make sure any tokens referenced in our activity are available.  If the tokens referenced in our activity are not found then add a warning to the proxy 'ValidationErrorCollection'.

/// <param name="collection">The iValidationErrorCollection.</param>
/// <param name="tokenPropertyName">The name of the token to validate</param>
/// <param name="tokenValue">The value of the token to validate.</param>
private void ValidateToken(IValidationErrorCollection collection, string tokenPropertyName, string tokenValue)
{

    // Step through each token string in the token value...
    foreach (Match tokenName in Regex.Matches(tokenValue, @"%\((.*?)\)"))
    {
        string unDelimitedTokenName = tokenName.Groups(1).ToString;
        bool tokenFound = false;

        // Step through each token in the token data...
        foreach (Token token in this.GetTokenService.RetrieveTokenDataFromContextActivity(this).GetAllTokens)
        {
            // If it matches then set the flag and exit the loop...
            if (token.FullName == unDelimitedTokenName)
            {
                tokenFound = true;
                break;
            }
        }

        // If the token was not found then add a warning...
        if ((!tokenFound))
            collection.AddWarning(string.Format("Token '%({0})' cannot be resolved in '{1}'.", unDelimitedTokenName, tokenPropertyName));
    }
}

Finally, the 'OnActivityMoved and 'OnActivityRemoved' stubs that were added when you check the checkboxes in the proxy generator can be modified by calling the existing 'RefreshValidation' method on the exposed workflow object;

/// <summary>
/// Occurs when an activity has been moved within a parent activity or moved to a different parent activity but stays in the same workflow.
/// </summary>
/// <param name="workflow">The workflow within which the activity was moved.</param>
/// <param name="activity">The activity that was moved.</param>
/// <param name="previousParent">The parent activity of the activity that was moved, before it was moved.</param>
/// <param name="previousIndex">The index (within the parent activity) of the activity, before it was moved.</param>
    public virtual void OnActivityMoved(IWorkflow workflow, IActivityProxyEx activity, ICompositeActivityProxyEx previousParent, int previousIndex)
    {
        workflow.RefreshValidation();
    }

///<summary>
///Occurs when an activity has been removed from a workflow.
///</summary>
///<param name="workflow">The workflow from which the activity was removed.</param>
///<param name="activity">The activity that was removed.</param>
///<param name="previousParent">The parent activity of the activity that was removed, before it was removed.</param>
///<param name="previousIndex">The index (within the parent activity) of the activity, before it was removed.</param>
    public virtual void OnActivityRemoved(IWorkflow workflow, IActivityProxyEx activity, ICompositeActivityProxyEx previousParent, int previousIndex)
    {
        workflow.RefreshValidation();
    }
1 0

Replies

replied on April 24, 2019

Andrew,

When you run the Activity Proxy Generator on your custom activity assembly it should create a validation subroutine for every property in your activity.  By default the subs are all commented out with some TODO comments on how to validate the properties. 

Let me know if you need actual code examples but the TODO comments in the subs are pretty self explanatory.

replied on May 2, 2019

Is someone able to assist on this?  We would really like to get this functionality added into our workflow activities.

0 0
replied on May 2, 2019

Michael,

Are you asking how to validate tokens within your custom activity or are you asking to validate tokens exposed by other activities from within your proxy code?

0 0
replied on May 2, 2019

We are trying to validate tokens exposed by other activities within our proxy.  For example, if the workflow has a "Generate Tokens" activity, and we use that token in our custom activity (with a custom Edit Panel control for the property), we want to be able to let users know if that token no longer exists if it is deleted from the Generate Tokens activity.  

0 0
replied on May 2, 2019

Have you played with the options on the Code Generation Options tab of the proxy generator?  Checking specific values will add event handlers to your proxy code that should allow you to trap and respond to the events you mention above.

1 0
replied on May 7, 2019

We did check this box when generating our proxy.  This does not, however, provide any way of ensuring the tokens are valid when validating the workflow.  If a user types in an invalid token or a token is otherwise invalid, I would like to let users know about this when validating/publishing the workflow.

0 0
SELECTED ANSWER
replied on May 10, 2019 Show version history

Michael,

It would appear that the proxy code itself exposes the methods that will allow you to do what you want. 

Here are some screen snips of the code in action;

Here is the code I used. 

First we need to call our new routine from the existing proxy token validation sub.  Any other validation subs from other tokens exposed in our activity will also need to call this same routine .

/// <summary>
/// Validates the 'MyToken' property by adding validation errors and/or warnings to the specified IValidationErrorCollection.
/// </summary>
protected virtual void ValidateProperty_MyToken(IValidationErrorCollection collection)
{
    // TODO: Add code for validating the MyToken property here. For example:
    // 
    // Ensure that MyToken is not null.  If it isnt null then call the routine to validate any tokens exposed...
    if ((string.IsNullOrEmpty(this.MyToken)))
        collection.AddError("This property must be specified.");
    else
        this.ValidateToken(collection, MyTokenPropertyName, this.MyToken);
}

The new sub is called 'ValidateToken'.  In that new sub we are going to get a list of tokens from other activities to parse.  The existing proxy method 'RetrieveTokenDataFromContextActivity' seems to provide only the tokens from other activities that are 'above' our activity in the workflow.  We are going to parse those tokens to make sure any tokens referenced in our activity are available.  If the tokens referenced in our activity are not found then add a warning to the proxy 'ValidationErrorCollection'.

/// <param name="collection">The iValidationErrorCollection.</param>
/// <param name="tokenPropertyName">The name of the token to validate</param>
/// <param name="tokenValue">The value of the token to validate.</param>
private void ValidateToken(IValidationErrorCollection collection, string tokenPropertyName, string tokenValue)
{

    // Step through each token string in the token value...
    foreach (Match tokenName in Regex.Matches(tokenValue, @"%\((.*?)\)"))
    {
        string unDelimitedTokenName = tokenName.Groups(1).ToString;
        bool tokenFound = false;

        // Step through each token in the token data...
        foreach (Token token in this.GetTokenService.RetrieveTokenDataFromContextActivity(this).GetAllTokens)
        {
            // If it matches then set the flag and exit the loop...
            if (token.FullName == unDelimitedTokenName)
            {
                tokenFound = true;
                break;
            }
        }

        // If the token was not found then add a warning...
        if ((!tokenFound))
            collection.AddWarning(string.Format("Token '%({0})' cannot be resolved in '{1}'.", unDelimitedTokenName, tokenPropertyName));
    }
}

Finally, the 'OnActivityMoved and 'OnActivityRemoved' stubs that were added when you check the checkboxes in the proxy generator can be modified by calling the existing 'RefreshValidation' method on the exposed workflow object;

/// <summary>
/// Occurs when an activity has been moved within a parent activity or moved to a different parent activity but stays in the same workflow.
/// </summary>
/// <param name="workflow">The workflow within which the activity was moved.</param>
/// <param name="activity">The activity that was moved.</param>
/// <param name="previousParent">The parent activity of the activity that was moved, before it was moved.</param>
/// <param name="previousIndex">The index (within the parent activity) of the activity, before it was moved.</param>
    public virtual void OnActivityMoved(IWorkflow workflow, IActivityProxyEx activity, ICompositeActivityProxyEx previousParent, int previousIndex)
    {
        workflow.RefreshValidation();
    }

///<summary>
///Occurs when an activity has been removed from a workflow.
///</summary>
///<param name="workflow">The workflow from which the activity was removed.</param>
///<param name="activity">The activity that was removed.</param>
///<param name="previousParent">The parent activity of the activity that was removed, before it was removed.</param>
///<param name="previousIndex">The index (within the parent activity) of the activity, before it was removed.</param>
    public virtual void OnActivityRemoved(IWorkflow workflow, IActivityProxyEx activity, ICompositeActivityProxyEx previousParent, int previousIndex)
    {
        workflow.RefreshValidation();
    }
1 0
replied on May 22, 2019

Thanks Cliff!!

My version of the token validation is very similar to yours BUT I had inadvertently removed IWorkflowNotifyTarget from the proxy, so it was not firing when I expected/wanted it to. 

I suggest adding another RegEx layer to make sure the tokens are still found properly in case there is formatting; this seems to do the trick:

var unformattedValue = Regex.Replace(unDelimitedTokenName, @"\#(.*?)\#", "");

 

1 0
You are not allowed to follow up in this post.

Sign in to reply to this post.