Archive

Posts Tagged ‘Custom Workflow’

[Code Snippet] Custom Workflow Activity with Input and Output Params

Of late , I was getting questions around the usage of custom workflow activity and troubleshooting.

In this article, I am going to cover creation and the usage of custom workflow activity with both Input and Output arguemnts.

To simplify the understanding, lets take a simple scenario:

  • ‘Contact’ and ‘Account’ entities have 2 custom attributes (Company ID, Company Name)
  • Whenever a new ‘Contact’ gets created, check if there is an existing ‘Account’ with the ‘Contact.Company ID’
    • If no existing Account, create a new Account with Contact’s data.
    • If there is an existing Account, update Account with Contact’s data.

To achieve this,I am going create a new Custom workflow activity with below design:

  • Create a new ‘Custom Workflow Activity’ with the filter logic to check whether there is an existing ‘Account’ with ‘Company ID’ and returns the existing Account.
  • In Dynamics, Create a new Workflow on ‘Contact’ creation and trigger the newly created custom workflow activity by passing ‘Company Code’.

Lets go step by step.

Step 1: Create a new Custom Workflow Activity:

  • Open a new Class Library project in Visual Studio and download dynamics core library from Nuget .
  • The workflow will have 3 Arguments
    • Input Arguments
      • ContactCompanyID – ‘Company ID’ of Created Contact. Value will be passed from Dynamics Workflow.
    • Output Arguments
      • ExistingAccount – Entity reference of matching Account by ‘Company ID’. Value.
      • IsAccountExists – Boolean.
  • Complete Code:

using System;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Workflow;

public class CreateOrUpdateAccountActivity : CodeActivity{

// Input Parameter – Contact’s Company will be passed to this Parameter FROM Workflow
[RequiredArgument]
[Input(“Company ID”)]
public InArgument<string> ContactCompanyID { get; set; }

// Output Parameter – Matched Account will be passed back TO Workflow
[ReferenceTarget(“account”)]
[Output(“Existing Account”)]
public OutArgument<EntityReference> ExistingAccount { get; set; }

// Output Parameter – Boolean flag will be passed TO Workflow
[Output(“Account Exists?”)]
public OutArgument<bool> IsAccountExists { get; set; }

protected override void Execute(CodeActivityContext executionContext){
var tracingService = executionContext.GetExtension<ITracingService>();
var context = executionContext.GetExtension<IWorkflowContext>();
var serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
var service = serviceFactory.CreateOrganizationService(context.UserId);
try{
// Read the ‘Company ID’ from Workflow Input variable
var contactCompanyName = this.ContactCompanyID.Get<string>(executionContext);

// Check if Account exists already with the Contact’s Company ID
var matchedAccount = GetAccountByCompanyID(contactCompanyName, service);

if (matchedAccount == null){
// Set the boolean output param to false, as No matched Account
this.IsAccountExists.Set(executionContext, false);
}
else{
// Set the matched Account to Workflow Output param.
this.ExistingAccount.Set(executionContext, new EntityReference(matchedAccount.LogicalName, matchedAccount.Id));
// Set the boolean output param to true, as matched Account found
this.IsAccountExists.Set(executionContext, true);
}
}
catch (Exception ex){
tracingService.Trace(“Error in CreateOrUpdateAccountActivity – ” + ex.Message);
throw;
}
}

private static Entity GetAccountByCompanyID(string companyID, IOrganizationService service){
var queryAccounts = new QueryExpression(“account”){
ColumnSet = new ColumnSet(new string[] { “accountid” })
};
var filterAccount = new FilterExpression(LogicalOperator.And);
filterAccount.AddCondition(“new_companyid”, ConditionOperator.Equal, companyID);

queryAccounts.Criteria = filterAccount;
var contacts = service.RetrieveMultiple(queryAccounts);
if (contacts != null && contacts.Entities != null && contacts.Entities.Count > 0){
return contacts[0];
}

return null;
}
}

  • Sign the Assembly and build the code
  • Register the ‘Custom Workflow Activity’ using Plug-in Registration Tool.

WF_1

Step 2: Create Dynamics Workflow Process:

  • Create a new Workflow Process on ‘Contact’ creation.

WF_2

  • Under the Workflow steps, as a first step trigger the Custom Workflow Activity

WF_3

  • Click on ‘Set Properties’ and set the ‘Company ID’ argument with ‘Contact.Company ID’

WF_12

  • Next, add a ‘Check Condition’ step to check the ‘IsAccountExists’ value returned by custom workflow activity.

WF_5

  • Set the condition, If ‘Account Exists?’ (This is the display name of Input argument we set in custom workflow) is ‘False’

WF_14

  • As a child step of ‘Check Condition’, add a ‘Create Record’ step to create a new ‘Account’

WF_15

  • Next, add another ‘Check Condition’ step, to handle the ‘Else’ condition and update the ‘Existing Account’
  • Under the Else ‘Check Condition’, add an ‘Update Record’ step to update the ‘Account’ returned by ‘Custom Workflow Activity’

WF_16

  • Activate the workflow

WF_13

Test the flow:

  • Create a new ‘Contact’

WF_17

  • Check the workflow execution by clicking on ‘Process Sessions’ tab from the workflow. This helps us to troubleshoot, in case of any issues in our workflow steps.

WF_10

  • Since all the steps in above screen are Success, now Go to ‘Accounts’ and you should see a new ‘Account’ as there was no existing Account already.WF_11

Notes:

  • Compare to writing the whole logic server side, this approach gives us the flexibility to map the desired fields from ‘Contact’ to ‘Account’ as its a Workflow.

🙂