Until CRM 4
there were Workflows that could be used for asynchronous processing of business
logic, generally used for setting up automated actions and defining sales
process in Dynamics CRM.
Since CRM
2011, the workflows became a category under Processes and there was another
category Dialogs introduced. Dialogs provided for execution of Dialog scripts
to set up process flows for the Salesforce. These could be used to guide the
sales people through the sales process using a question/answer format. The
Dialog included execution of automated steps like the workflows.
With CRM
2013, the Processes have been extended to now include Business Process Flow and
Actions in addition to the categories from the previous versions. In our
earlier blog we have discussed the concept of Business Process Flow. This article will concentrate on Actions.
What are
Actions?
Actions are
messages that can defined for an entity. Existing examples messages include
Create, Update, Set State, Assign etc. With Actions, the CRM platform has
enabled the creation of custom actions for entities to extend the XRM platform.
Where to
use Actions?
An example
of a custom action could be “Approve”. Often times we have to design an
approval process for Dynamics CRM. Once the item is approved, certain actions
need to be performed. In previous versions it would either be implemented as a
Workflow that is manually executed from the Workflows Dialog or it involved
added of a custom attribute that when checked would imply the item is approved
and then the workflow would capture the update of this field to process any
automated actions defined.
How to
setup an Action?
Let us take
an example of an approval process. When an item is “Approved”, we want to send
email notifying the concerned parties of the approval.
Here is an
action created for “Approve”
It accepts
an input parameter for the ApprovedBy User. You can specify parameters of any
of the following data types
In the
workflow actions, it sends a mail from the ApprovedBy user to the Owner of the
Order notifying them of the order being approved. You can also call custom
workflow assemblies here.
Note the
schema name generated “new_Approve”. This is the name of the new message that
will not be available for the Order entity.
These
actions are available for further implementation of custom business logic
through the use of plugins. In some scenarios, say we need to validate certain
conditions are met before the item can be approved. In this case we can
register a plugin in the Pre-Stage of the Approve Message. The plugin could
validate the conditions and throw an exception to abort the processing of the
Approve Message.
How to use Actions?
Since
Actions are implemented as custom messages/requests, they can be implemented
similar to any other OOB messages like Create or Update.
Using C#
code, you can
invoke the Approve request using the following code
//get current user details
WhoAmIRequest userReq = new WhoAmIRequest();
WhoAmIResponse resp = (WhoAmIResponse) proxy.Execute(userReq);
OrganizationRequest req = new
OrganizationRequest("new_Approve");
req["ApprovedBy"] = new EntityReference("systemuser",
resp.UserId);
req["Target"] = new EntityReference("salesorder",orderid);
//execute the request
OrganizationResponse response = proxy.Execute(req);
Through jscript it can be invoked as follows.
if (typeof (SDK) == "undefined")
{ SDK = { __namespace: true }; }
{ SDK = { __namespace: true }; }
SDK.Action = {
_getClientUrl: function () {
var ServicePath = "/XRMServices/2011/Organization.svc/web";
var clientUrl
= "";
if (typeof
GetGlobalContext == "function") {
var context = GetGlobalContext();
clientUrl = context.getClientUrl();
}
else {
if (typeof
Xrm.Page.context == "object") {
clientUrl =
Xrm.Page.context.getClientUrl();
}
else
{ throw new
Error("Unable to access the server URL");
}
}
if (clientUrl.match(/\/$/))
{
clientUrl = clientUrl.substring(0, clientUrl.length - 1);
}
return clientUrl
+ ServicePath;
},
ApproveRequest : function (salesOrderId, approvedById) {
var requestMain = ""
requestMain +=
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
requestMain +=
" <s:Body>";
requestMain +=
" <Execute
xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\"
xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
requestMain +=
" <request
xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">";
requestMain +=
" <a:Parameters
xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
requestMain +=
"
<a:KeyValuePairOfstringanyType>";
requestMain +=
"
<b:key>Target</b:key>";
requestMain +=
"
<b:value i:type=\"a:EntityReference\">";
requestMain +=
"
<a:Id>" + salesOrderId + "</a:Id>";
requestMain +=
"
<a:LogicalName>salesorder</a:LogicalName>";
requestMain +=
"
<a:Name i:nil=\"true\" />";
requestMain +=
"
</b:value>";
requestMain +=
"
</a:KeyValuePairOfstringanyType>";
requestMain +=
"
<a:KeyValuePairOfstringanyType>";
requestMain +=
"
<b:key>ApprovedBy</b:key>";
requestMain +=
"
<b:value i:type=\"a:EntityReference\">";
requestMain +=
"
<a:Id>" + approvedById + "</a:Id>";
requestMain +=
"
<a:LogicalName>systemuser</a:LogicalName>";
requestMain +=
"
<a:Name i:nil=\"true\" />";
requestMain +=
"
</b:value>";
requestMain +=
"
</a:KeyValuePairOfstringanyType>";
requestMain +=
" </a:Parameters>";
requestMain +=
" <a:RequestId
i:nil=\"true\" />";
requestMain +=
" <a:RequestName>new_Approve</a:RequestName>";
requestMain +=
" </request>";
requestMain +=
" </Execute>";
requestMain +=
" </s:Body>";
requestMain +=
"</s:Envelope>";
var req = new
XMLHttpRequest();
req.open("POST", SDK.Action._getClientUrl(), false)
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type",
"text/xml; charset=utf-8");
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
req.send(requestMain);
//work with the response here
//var strResponse = req.responseXML.xml;
},
__namespace: true
};
Here in
this above script RequestName indicates the Unique Name of Action
and Parameters contains collection of key value pairs that can be passed to
Action. In above script We can use below function using below syntax.
SDK.Action.ApproveRequest(salesOrderId,
approvedById);
You can register
plugin on the Approve message. The input parameters of the Approve message
will receive the input parameters as defined in the Approve Action.
The plugin
registration tool will start showing this message for the Order entity to
register plugin against.
Once the plugin is registered, in the code you can access the input parameters just like you do for other messages as shown below
To get
access to the image of the Order record
EntityReference
entityRef = localContext.PluginExecutionContext.InputParameters["Target"]
as EntityReference;
To read the
ApprovedBy input parameter
EntityReference
approvedBy =
localContext.PluginExecutionContext.InputParameters["ApprovedBy"] as
EntityReference;
In the
pre-stage, you can throw an InvalidPluginExecution error to abort the Approve
operation.
Conclusion:
Actions is
a powerful tool in the hands of the developer to truly extend the CRM platform
for XRM implementations.