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

[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
[Input(“Company ID”)]
public InArgument<string> ContactCompanyID { get; set; }

// Output Parameter – Matched Account will be passed back TO Workflow
[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);
// 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);
// 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);

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.


Step 2: Create Dynamics Workflow Process:

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


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


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


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


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


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


  • 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’


  • Activate the workflow


Test the flow:

  • Create a new ‘Contact’


  • 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.


  • 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


  • 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.


  1. c
    December 10, 2022 at 6:05 PM

    Did you make the screenshots with possible lowest resolution so nobody can see what`s on the screen ?

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: