Archive
[Code Snippet] Set Business process flow (BPF) stage using C#
Assume you have a BPF with 3 Stages on an Entity ‘Employer’. When you create a new ‘Employer’ record, by default ‘Stage-1’ gets set.
What if you have to create the ‘Employer’ record with a different stage.
Lets see how to create a record and set the desired BPF stage with an example entity ‘Employer’.
I’ve an ‘Employer’ entity and a BPF name ‘Employer flow’ with 3 stages named ‘Basic Details’, ‘Address’ and ‘Experience’.

Key point to notice is, when ever you create a BPF a new entity gets created with the given BPF name.

Following are the steps to create a ‘Employer’ record and set the BPF stage to ‘Experience’.
- Query ‘Workflow’ entity to get the ‘BPF ID’ by passing the BPF entity schema name (i.e., crf10_employerflow).
var queryEmployerBPF = new QueryExpression
{
EntityName = "workflow",
ColumnSet = new ColumnSet(true),
Criteria = new FilterExpression
{
Conditions =
{
new ConditionExpression
{
AttributeName = "uniquename",
Operator = ConditionOperator.Equal,
Values = { "crf10_employerflow" }
}
}
}
};
var retrievedBPF = ConnectionManager.CrmService.RetrieveMultiple(queryEmployerBPF).Entities[0];
var _bpfId = retrievedBPF.Id;
- Query Process Stage by passing ‘BPF ID’ fetched in previous step.
var queryPS = new QueryExpression{
EntityName = "processstage",
ColumnSet = new ColumnSet(true),
Criteria = new FilterExpression{
Conditions ={
new ConditionExpression{
AttributeName = "processid",
Operator = ConditionOperator.Equal,
Values={ _bpfId }
}
}
}
};
- Copy the ‘Stage’ GUID’s which will be used in next steps.
- Create the ‘Employer’ record, which also creates record in ‘BPF entity’ (i.e., Employer Flow).
Entity entEmployer = new Entity("crf10_employer");
entEmployer["crf10_name"] = "BPF Test";
//entEmployer["processid"] = Guid.Empty;
var violationID = ConnectionManager.CrmService.Create(entEmployer);
- Fetch the ‘BPF entity’ (i.e., Employer Flow) record, which auto created in previous step, using ‘RetrieveProcessInstancesRequest’ request.
var procOpp2Req = new RetrieveProcessInstancesRequest
{
EntityId = violationID,
EntityLogicalName = "crf10_employer"
};
var procOpp2Resp = (RetrieveProcessInstancesResponse)ConnectionManager.CrmService.Execute(procOpp2Req);
- Update ‘activestageid’ field of the ‘BPF entity’ (i.e., Employer Flow) record fetched in previous step, with the desired stage GUID captured in Step #2.

// Declare variables to store values returned in response
int processCount = procOpp2Resp.Processes.Entities.Count;
var activeProcessInstance = procOpp2Resp.Processes.Entities[0]; // First record is the active process instance
var _processOpp2Id = activeProcessInstance.Id; // Id of the active process instance, which will be used
// Retrieve the process instance record to update its active stage
ColumnSet cols1 = new ColumnSet();
cols1.AddColumn("activestageid");
Entity retrievedProcessInstance = ConnectionManager.CrmService.Retrieve("crf10_employerflow", _processOpp2Id, cols1);
// Update the stage to 'Experience' by passing GUID (i.e.,"05aeaf03-e135-40ac-8ae7-cafc7d746a02")
retrievedProcessInstance["activestageid"] = new EntityReference("processstage", new Guid("05aeaf03-e135-40ac-8ae7-cafc7d746a02"));
ConnectionManager.CrmService.Update(retrievedProcessInstance);
- Open the record from the App and the stage should set to ‘Experience’.

- Check the BPF records and you should see ‘Active Stage’ got set to ‘Experience’ (This is optional step and for your learning).

- Below is the complete snippet.
var queryEmployerBPF = new QueryExpression
{
EntityName = "workflow",
ColumnSet = new ColumnSet(true),
Criteria = new FilterExpression
{
Conditions =
{
new ConditionExpression
{
AttributeName = "uniquename",
Operator = ConditionOperator.Equal,
Values = { "crf10_employerflow" }
}
}
}
};
var retrievedBPF = ConnectionManager.CrmService.RetrieveMultiple(queryEmployerBPF).Entities[0];
var _bpfId = retrievedBPF.Id;
var queryPS = new QueryExpression
{
EntityName = "processstage",
ColumnSet = new ColumnSet(true),
Criteria = new FilterExpression
{
Conditions =
{
new ConditionExpression
{
AttributeName = "processid",
Operator = ConditionOperator.Equal,
Values={ _bpfId }
}
}
}
};
var retrievedPS = ConnectionManager.CrmService.RetrieveMultiple(queryPS);
// Copy the Stage GUID's using below loop.
foreach (var stage in retrievedPS.Entities)
{
Console.WriteLine($"Stage Name : {stage["stagename"]}");
Console.WriteLine($"Stage ID : {stage["processstageid"]}");
}
//Create 'Employer' record
var entEmployer = new Entity("crf10_employer");
entEmployer["crf10_name"] = "BPF Test";
//entEmployer["processid"] = Guid.Empty;
var violationID = ConnectionManager.CrmService.Create(entEmployer);
var procOpp2Req = new RetrieveProcessInstancesRequest
{
EntityId = violationID,
EntityLogicalName = "crf10_employer"
};
var procOpp2Resp = (RetrieveProcessInstancesResponse)ConnectionManager.CrmService.Execute(procOpp2Req);
// Declare variables to store values returned in response
int processCount = procOpp2Resp.Processes.Entities.Count;
var activeProcessInstance = procOpp2Resp.Processes.Entities[0]; // First record is the active process instance
var _processOpp2Id = activeProcessInstance.Id; // Id of the active process instance, which will be used
// Retrieve the process instance record to update its active stage
var cols1 = new ColumnSet();
cols1.AddColumn("activestageid");
var retrievedProcessInstance = ConnectionManager.CrmService.Retrieve("crf10_employerflow", _processOpp2Id, cols1);
// Update the stage to 'Experience' by passing GUID (i.e.,"05aeaf03-e135-40ac-8ae7-cafc7d746a02")
retrievedProcessInstance["activestageid"] = new EntityReference("processstage", new Guid("05aeaf03-e135-40ac-8ae7-cafc7d746a02"));
ConnectionManager.CrmService.Update(retrievedProcessInstance);
đ
Plug-in on related entities during âCascade Allâ actions
Assume the relationship behavior between âContactâ and âAppointmentâ is âCascade Allâ on âAssignâ action.
By virtue of that, if a Contact has 2 Appointments, if I change the owner of âContactâ the related 2 Appointment owner also changes.
In one of the requirement, we have to restrict the Cascade operation based on business logic on child record (i.e., Â Appointment)
So I registered a Plugin on âAssignâ of âAppointmentâ and want to handle the Cascade operation, but the Plugin never get executed.
Reason & Solution
- CRM treats Cascade Assign operation on Child records as an Update.
- Register the Plug-in on âUpdateâ instead of âAssignâ message.
- In the Update plug-in, the Target entity only contain âOwnerâ field
đ
UserId & InitiatingUserId properties in Plugin of CRM
In CRM plugin, âIExecutionContextâ contains 2 properties
- UserId
- Gets the GUID of the user for whom the plug-in invokes âon behalf ofâ.
- InitiatingUserId
- Gets the GUID of the user under which the current pipeline is executing.
Consider a scenario
- You have a user âRAJâ with âSales Personâ role with only âUser Levelâ âReadâ privilege on âContactâ
- You have a plugin on Post Deletion of âContactâ with name âPostContactDeleteâ
- Assume in one particular scenario user âRAJâ should be able to delete a âContactâ
- So you can run the âPostContactDeleteâ plugin in the user with âSystemAdministratorâ role
- (i.e., Set âRun in Userâs Contextâ to User with admin role; In sample screen shot below I chosen my admin user whose name is  âCRM WaSu1)
- When User âRAJâ logs in and try to delete âContactâ the plug-in âPostContactDeleteâ fires. When you debug
- IExecutionContext.UserId = GUID of  SystemAdministrator (i.e., OnBehalfOf User ‘RAJ’)
- IExecutionContext. InitiatingUserId =GUID of  RAJ  (i.e., Actual User)
đ
Creating a plug-in on SavedQuery entity using CRM developer toolkit
In one of my requirement I have to create a plugin on âSavedQueryâ entity to filter the views
I was using CRM developer toolkit and when I open the âCRM Explorerâ I did not find âSavedQueryâ entity
Later I came to know that âCRM Explorerâ show entities by âDisplay Nameâ and there was entity with name âViewâ for âSavedQueryâ
Thought of sharing this though its simple observation
đ