Custom actions have been around for a while, but, somehow, I have not used them at all on my projects so far. I would always create a plugin or a custom workflow activity instead.. Still, I’ve been watching them for a while:) And what I think is missing is a set of recommendations and/or best practices around actions which would explain when and why we should be using them.
I can hear you saying “of course there are.. have you been in the trenches for the last few years?”
Technically, I probably have been, a little bit:) However, I’d like to explain myself.
What are the primary benefits of the custom actions?
In this 2014 article, PowerObjects are stating that “The most fundamental benefit of custom Actions in CRM is to allow non-programmers to build automated processes; in turn, developers can trigger this Action by using a single command, like “Approve” or “Schedule”, etc. Before custom Actions, this was only possible by making code update a field or save a record that would in turn trigger a workflow.”
In other words, non-developers can define a “workflow” which the developers can, then, trigger through the action. This is interesting and sort of makes sense. However, have you ever looked at all the custom actions included into the default Dynamics 365 solution (actually, it’s not necessarily the “default” solution. It’s what you get when you deploy Field Service, Project Service, etc)? There are lots of the out of the box custom actions, but, if you look at them, you’ll notice something unexpected about them:
NO STEPS HAVE BEEN ADDED. Here is another one:
This seems to be not that unusual at all for the out of the box custom actions.
Why is there a custom action, then, if there are no steps?
The answer comes in the form of the Sdk Message Processing Step:
See? There is a custom action, and there is a corresponding message processing step. This sort of turns the whole scenario on its head, though. It’s a custom action created by developers for everyone else – all the business logic is implemented in the plugin. As a non-developer, you can call this custom action from the workflow. As a developer, you can call it from a plugin/javascript. But you can’t even change the business logic since it’s all embedded into a plugin.
It’s probably safe to say, then, that Microsoft itself is not considering the ability “of non-programmers to build automated processes” as a primary benefit of using the custom actions.
Then.. why not to use a plugin/workflow instead of a custom action?
The way I see it, there are a few reasons why we may prefer custom actions:
1. They are business logic modules that do not have triggers – we can trigger them when we need to
A workflow will trigger in response to some event. A plugin will run in response to a message. A custom action has to be triggered either as a workflow step or from the web api/plugin using code. This is a somewhat different level of control, although, it’s arguable if it’s that much better than using a workflow/plugin.
2. We can pass input parameters to the actions and retrieve output parameters from the action
This is actually interesting. We can’t pass parameters to / from workflows or plugins. I am not sure why, at some point, the decision was made to introduce custom actions rather than to add this functionality to the workflows, for example. However, as it stands, we can only use custom actions when we actually need to pass parameters to our plugin, for instance. Or when we need to get output parameters from the plugin.
For example, what if we wanted to calculate some sort of total value? We might create a custom action which would calculate that value, and it could simply use input/output parameters to communicate with the calling process – it would not have to update any of the records and/or wait till any of the records are updated.
Or what if we wanted to find most recent case activity? We might create another custom action, and we might call it in a similar manner everywhere: in our javascripts, in the workflows, in the plugins.. That would be different from doing the same in a custom workflow activity which would require a workflow in the first place.
It seems we should be thinking of the custom actions as of the “functions”. Those functions can be defined as a mix of workflow steps and plugins – we can pass input parameters into the custom action and retrieve output parameters from the custom action. The reason we can call then “functions” is that, unlike with the workflow/plugins, we can, actually, call those functions from other places – we can call them from javascripts, we can call them from workflows, and we can call them from plugins. Still, I am wondering how often do we actually need that kind of functions – as I mentioned in the beginning of this post, I have not used them on my projects at all so far, though that probably simply means the time has not come, yet.. Still, I’d love to hear about the real-life scenarios(which, I hope, you can share in the comments) where the choice between using a plugin/a workflow/a custom action was clearly to use a custom action.
That said, does it seem like I have arrived at some kind of answer as to when and why we should be using the custom actions? It could be the case if this scenario was clearly described and documented in the SDK manuals/help files. But, as of right now, I still cannot find any indication of how to pass those parameters to/from the custom action in C# code, for example, when I am looking at the SDK files.
Here is what Andrii Butenko, a Dynamics MVP, wrote back in 2013:
Actions: usage of input/output arguments in plugins that handle Actions
This is great, and this allows us to process custom actions parameters in the plugins now; however, I am wondering if that’s even supported? De-facto, that’s how a lot of people have been using the actions now. However, it would be great to see an msdn link where this same process would be described by Microsoft – right now this is all we have on the custom actions:
https://msdn.microsoft.com/library/dn481600.aspx
Then where does it leave us? Custom actions is a feature in Dynamics that is offering some interesting usage scenarios. This feature lacks official documentation for developers, and it also lacks official recommendations on when and how to use it. The community has been trying to figure it out on its own and has offered various scenarios so far, but, if Microsoft could add a bit of packaging to this feature in the form of more detailed documentation and samples, I think this would be very useful.
Temp
I was surprised to read that there’s no documentation and the community is figuring it out still. Microsoft provides adequate documentation on custom actions (but none on the gotchas and caveats in using them). The community has figured out custom actions for a years now.
Custom actions are events (or “messages” in terms of plugin steps). Microsoft merely exposes it to allow users to create custom events (“messages”). Every out of the box event (create, update, delete, setstate, etc.) is a custom action and behaves the same way as custom actions. (Well, they have some extra “abilities” not exposed in custom actions, such as offline mode.) As such, custom actions are also “requests” (OrganizationRequest). Each OOB event has a corresponding request, e.g. CreateRequest for Create event, so do custom actions. This is also why plugins can register plugin steps on custom actions because they are in fact events (“messages”).
The Create event for example is a custom action with only one input parameter: Target, which is of type Entity in the custom action and not a specific type of Entity, and one output parameter of type guid. When a plugin is triggered on Create of a record (either through form or code), CRM calls the custom action Create and passes the created record as the Target input parameter. That’s why in the plugin execution context there is an input parameter called Target of type Entity (or EntityReference for Delete event).
In a plugin, the Create custom action is called through the IOrganizationService.Create(new Entity()) method, which is shorthand for IOrganizationService.Execute(new CreateRequest() { Target = new Entity() }), where CreateRequest is derived from OrganizationRequest, and the plugin triggered by invoking Create will similarly have a Target input parameter. The Create custom action has an output parameter called id, which is the id of the newly created record, hence .Create returns a guid!
As such, a custom action is used the exact same way:
OrganizationRequest request = new OrganizationRequest(“new_customaction”);
request.Paramaters.Add(“Param1”, 1);
request.Paramaters.Add(“Param2”, 2);
OrganizationReaponse response = Service.Execute(request);
var outParam1 = response[“outParam1”];
The plugin that is registered to trigger on new_action will similarly, like Create, contain two input parameters:
var inParam1 = context.InputParameters[“Param1”];
var inParam2 = context.InputParameters[“Param2”];
And if the custom action has any output parameters, they need to be set (in post operation – stage 40) before the plugin finishes:
context.OutputParameters[“outParam1”] = 1;
And the plugin, workflow, etc. that called it will have access to outParam1 in the OrganizationResponse, as seen above.
As you can see, Create is no different from custom actions, because they ARE custom actions! For all intents and purposes, you can assume custom actions behave just like built-in events (create, update, delete, etc.). Custom action = message = event = message = custom action. QED. All the above is documented and supported by CRM.
Some notes:
– the “Target” parameter name is reserved by CRM for some reason.
– custom actions allow plugins to be triggered on-demand just like workflows
– be careful with output parameters of type entity, entity reference, and picklist (dialogs cannot call custom actions with entity as output, so use entity reference, which works just the same). Might be fixed in 9.0.
– custom action is more powerful than custom workflow activity (but the extra power may not be liked by workflows…), such as returning entity collections, being called within code, etc.
– try to think of custom actions in terms of requests (functions) or events (messages), but no one says you can’t use it as something else. Be creative! There’s no “guide” or “restriction” for a reason!
Whenever I write server side code for CRM, I generally structure the code so that it can be triggered by CRM, by a custom action, or by a custom workflow activity. Makes the code versatile and highly reusable!
This is an awesome response, it`s probably worth a separate blog post, it shows that you know how to code for custom actions, and this type of reaction is exactly what I expected.
However, “how” was not a technical question in the context of this post – it was a conceptual question.
In the words of Microsoft, “The business logic of an action is implemented using a workflow”, so, strictly speaking, plugins are “extensions” to the custom actions, not part of them. But look at the examples in the post – most of the custom actions have no workflow steps at all.
As for the documentation, I was talking about the “official” documentation in my post. For everything else, we have msdn samples (custom workflow activities, plugins, web api, etc). For custom actions, most (if not all) of what you wrote in the comment above comes from various blog posts and from your own realizations rather than from the msdn web site. How come?
A workflow is a plugin and a plugin is a workflow, they are one and the same. Just as business rules are JavaScript and JavaScript are business rules. Business Rules generate client-side JavaScript and workflows generate server-side C# code. As always, the UI version (workflow/business rule) is less powerful. Because a custom action is a process, they all have the same UI and thus can be created by non-developers because all process types are in essence workflows with specialized features. That’s my understanding of the “business logic implemented by workflow”.
The first paragraph in the MSDN article you linked is key to understanding custom actions:
“You can extend the functionality of Microsoft Dynamics 365 by creating custom messages known as actions. These actions will have associated request/response classes and a Web API action will be generated. Actions are typically used to add new domain specific functionality to the organization web service or to combine multiple organization web service message requests into a single request. For example, in a support call center, you may want to combine the Create, Assign, and Setstate messages into a single new Escalate message.”
The words messages, request/response classes, organization web service, combining messages – they all tell you that custom actions are custom events, just like OOB events (create, update, delete, etc.). When you generate early-bound versions of custom actions, they look just like the subclasses of OrganizationRequest. When you create a custom action, it creates a sdkmessage record and a sdkmessagefilter record if the custom action is tied to a specific entity. So, we can infer that custom actions are events/messages that behave just like OOB events/messages.
Since custom actions are messages (request/response), we can use MSDN articles on those to understand how to use custom actions and how they work:
https://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.iorganizationservice.execute.aspx
https://msdn.microsoft.com/en-us/library/gg328075.aspx (this is important to understanding custom actions)
There are other code samples littered in places that you wouldn’t think to look. Also, MSDN has code samples for client-side calls to custom actions:
https://msdn.microsoft.com/en-us/library/mt607600.aspx
Since custom actions are messages, we can assume that the plugin execution context behaves the same for them as they do for OOB messages.
By the way, there are many internal messages that can be used that Microsoft doesn’t expose. Lately, I’ve been using the CreateFolderRequest and other SharePoint messages. Using these internal messages help make things a lot easier! If you have access to a CRM server, the .dll you want to look at is Microsoft.Crm.Sdk.Reserved.dll.
You are exaggerating from the beginning. Plugins and workflows are not one and the same – maybe on some level they are, but workflows are “code-free” customizations. Even technically, for example, you are not supposed to use pre/post images with workflows.. although you can.. but it’s in the “unsupported” domain.
As for inferring anything about the custom actions, that’s exactly my point. I have no desire to infer because whatever I infer can easily bite me(and, more importantly, my clients) later if it turns out I inferred incorrectly. That’s what documentation is for.
And, then, “The business logic of an action is implemented using a workflow”. Again, that’s what’s written there.
Of course there is a lot of “unexposed” functionality, but that’s a no go on any Dynamics project (won’t be arguing on this one because a) I know it’s much easier when you use it b) I know I won’t use it:) )
Perhaps “infer” was not best used here, but all you need to know about custom actions are documented.
What is a custom action? It is a (custom) message.
https://msdn.microsoft.com/en-us/library/dn481600.aspx
“You can extend the functionality of Microsoft Dynamics 365 by creating custom messages known as actions. These actions will have associated request/response classes and a Web API action will be generated.”
What are messages? A request/response service.
https://msdn.microsoft.com/en-us/library/gg328075.aspx
How do plugins interact with messages? By registering on the message and receiving the input params and delivering the output params via the plugin context.
https://msdn.microsoft.com/en-us/library/gg309673.aspx#bkmk_inputandoutput
“The InputParameters property contains the data that is in the request message currently being processed by the event execution pipeline.” It even uses the Create message as an example.
It is stated very clearly in the documentation. CRM Documentation is not perfect, but it is well fleshed out. It may not explicitly state every single detail on each page, but it tells you enough to know what it is and how to use it. I don’t know why you wish to argue this. I am not here to argue or win anything. I noticed some information that didn’t seem right, so I thought it would be helpful to shed some light.
As for the workflow = plugin thing. The underlying implementation (model and logic) is the same. Both context derive from IExecutionContext, which contain pre- and post-image properties. It is safe to assume that those properties are there 100%, because the interface is a contract that must be honored. Whether those properties get populated with actual image data, is another story. The StageName property in IWorkflowContext doesn’t even get populated…
They both run the exact same code underneath, with specific features that are only pertinent to each extension type. If these two aren’t the same, then Business Rules are not JavaScript, but they are. You can see the JS code that CRM generates when you create a business rule. The only difference (other than extension-specific features) is how they are composed.
Workflows are great in that non-technical people can create them and they are always up to date when new updates come in, whereas plugins are more flexible, faster, and more powerful, but they can only be done by technical people and have to be manually updated when the SDK changes.
Workflow images are there and can be used, but they may have their reasons to not document its use. A lot of times it boils down to inflexibility and support. The moment they document it, they have to support it and can’t change it willy nilly. You will often find MS employees, whether on their GitHub repo, on their blogs, or wherever, often state that they don’t wish to document it because it means they have to support it and can’t change it. I suspect the workflow images are not documented because you can only use them in custom workflow activities and they may wish to change it in the future.
PS: Microsoft also calls workflows plugins.
https://msdn.microsoft.com/en-us/library/gg327941.aspx#bkmk_Architecture
Appreciate all the comments. Again, the reason I’m sort of questioning the custom actions is that there is no clear documentation (it’s not that level of clarity we have for the plugins/workflows/odata/web api). Like you said, if it’s not stated somewhere, it can be nil and void any time, and I would include “intended use” there. On the technical level, you can probably explain how it works. However, you know just as well as I do that there are exceptions in Dynamics(not in the .NET sense.. I mean those where you can’t do something with a particular entity/attribute/form, for example.. that you can do with any other entity/attribute/form), and, so, you never know where you’ll run into them unless they are documented. Which brings me back to the question of what’s supported and what’s not.
See, even though you are saying you are not arguing, you actually are:) But it’s a good discussion – there is lots of information here now. Personally, I’ll probably agree to disagree for now, but, at least, whoever will be reading this will see both sides of this argument, so it’ll help everybody else.
I was surprised to see the biggest benefit of custom actions not discussed here: rollback! If you check the box “enable rollback” on a custom action, then the whole custom action is executed inside a transaction. If any step of the custom action fails, all steps are rolled back. Contrast this with a workflow, where an error in a step just causes the workflow to fail – it doesn’t rollback steps that happened before the failure. This is the biggest conceptual reason to use custom actions in my opinion!
How To calculate customer points by writing custom action ? can anyone help for this type of task.