Sunday, September 23, 2018

Closer look into Custom Actions - CodedActivity or Plugin Step ?

Hello Complicated World,

Actions, which was introduced in 2013 now have been around for a very long time. Action is definitely a process that allows a non developer user to create and add some logic (child steps) same as Workflows. Yet in the hand of a CRM developer Actions can do magics ;) .

To list down the differences, 
  1. Actions can only be called or triggered by a custom code, a client side (JavaScript call) or a server side code (inside C# plugin or custom workflow) call. 
  2. Actions can support for Global entity, meaning that Actions can stay unbound to any specific entity and serve it's purpose at any time it get's called. 
  3. When calling the action, we can pass input parameters to the actions and retrieve output parameters on the successcallback.

Now the important questions, what does Custom Actions mean?

When it comes to  CRM customization, we mainly consider Custom Plugins inherited from IPlugin and Custom Workflows inherited from System.Activities.CodeActivity, where both comes with custom C# dlls to register.

Custom Actions don't have such code implementations. Custom Actions means simply creating new Actions in CRM in-addition to OOB Actions provided by default.

Yet there are two ways to extend Actions beyond CRM by triggering custom C# code. The selection is either to, 
  • Use Custom Action name as a SDK Message to trigger a Plugin step
  • Add custom workflow as a step inside Custom Action

Use Custom Action name as a SDK Message to trigger a Plugin step

Simple steps to follow are,

1. Create a new Action Process with input/output parameters and Activate the action



2. Create a new plugin dll project and write a plugin step handler for the action. I am using SDK plugin class implemented by inheriting IPlugin here. You can directly use IPlugin and use execute method.
public class testActionHandler : Plugin { public testActionHandler() : base(typeof(testActionHandler)) { base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)PipelineStage.PostOperation, "tst_testAction", "", new Action<LocalPluginContext>(ExecuteAction))); } private void ExecuteAction(LocalPluginContext obj) { var pluginExecutionContext = localContext.PluginExecutionContext; var inputparam = (string)localContext.PluginExecutionContext.InputParameters["inputarg"]; //your custom code pluginExecutionContext.OutputParameters["outputarg"] = true; } }
3. Register the plugin step inside the custom plugin dll assembly and use Action name as the message name (it should come in the dropdown ;)). 



Now you are good to go and you can call this action from both JavaScript and other plugins and workflows. So the execution order would be,
Action call --> Custom Action Trigger --> Plugin step trigger


Add custom workflow as a step inside Custom Action

This is almost similar to calling custom workflows inside OOB workflow. 

1. Write a CodedActivity class and configure it's input parameters. 
public class testActionHandler : CodeActivity { [Input("inputarg")] public InArgument<string> inputarg { get; set; } [Output("outputarg")] public OutArgument<Boolean> outputarg { get; set; } protected override void Execute(CodeActivityContext executionContext) { ITracingService tracingService = executionContext.GetExtension<ITracingService>(); IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>(); IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>(); IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); var inputarg = context.InputParameters["inputarg"]; // your code here var output = true; outputarg.Set(executionContext, output); } }
2. Add a step inside the action and call the registered custom workflow


And now you are done. :)

Okay now the important question, what's best way?


According to my view, best way to extend an Action with C# is to use plugin steps. Reasons behind are, 
  • The Action is independent from the plugin steps we create using it. We can delete the plugin steps without affecting the Action. But when you add a custom workflow (CodedActivity) as a step inside Action, you cannot delete the custom workflow without removing it from the Action first.
  • It's easy to manage input parameters with plugins, rather than with custom workflows. With custom workflows, sometime resetting input parameters become a hazard as it doesn't get update in CRM UI immediately. 

Adding custom workflow as a step make-sense when you want to re-use an existing workflow. Otherwise you are just increasing dependencies.

Let me know your thoughts on this. :)