When people ask me to describe the differences between custom workflow activities and custom actions, I always use the following definitions:
- Custom workflow activities. A functional blackbox created by the developers to be consumed by the business
- Custom activity. A functional blackbox created by the business to be consumed by the developers
There is more to the story, of course. As a developer, I always wanted to have the ability to extend server-side of CRM with custom API that I could call from all places code: javascript, custom utilities, plugins. For business users: nothing to see here, move along. Custom actions are the perfect mechanism to add this extensibility to CRM organization.
- Create custom action in CRM for the entity of your choice.
- Don’t add any steps, simply activate the action.
- You now have a custom message. Don’t believe me? Open [your_org_url]/api/data/v8.1/$metadata and search for your action name. Hint: use Chrome and stock up some patience.
<Action Name="georged_NormalizeCustomer" IsBound="true"> <Parameter Name="entity" Type="mscrm.contact" Nullable="false"/> </Action>
- Create a plugin using your action name as a message, entity contact, synchronous pre-operation.
- Write some wicked code in plugin (I chose to swap first and last names without telling the business):
var orgSvc = localContext.OrganizationService; var contactId = localContext.PluginExecutionContext .PrimaryEntityId; var contact = orgSvc.Retrieve( "contact", contactId, new ColumnSet("firstname", "lastname")); var temp = contact["firstname"]; contact["firstname"] = contact["lastname"]; contact["lastname"] = temp; orgSvc.Update(contact);
- You now have a custom API that you can call wrap up and call like this:
public static class Extensions { public static void NormalizeCustomer( this IOrganizationService service, Guid contactid) { var request = new OrganizationRequest ("georged_NormalizeCustomer"); request.Parameters.Add("Target", new EntityReference("contact", contactid)); var response = service.Execute(request); } } ... IOrganizationService svc = getityourself; Guid contactid = whatever; // call our "API" svc.NormalizeCustomer(contactid);
Why is it better than simple client-side code? Because I can call this API from various places using various languages and then change the implementation on the backend (e.g. swap first and middle names instead) and I wouldn’t have to change anything on the caller side.