Execute Action using JavaScript web resource in CRM 2013/15
To invoke an action from JavaScript, Microsoft has created a tool to generate SOAP based request and response libraries. Here is the link – Sdk.Soap.js Action Message Generator.
But here we’ll call Action using simple SOAP request.
Here I have created an Action to create a copy of an existing Account record. This Action is triggered from a custom ribbon button – Copy Account. The business logic has been implemented using custom workflow.
The purpose of this Action is to create a copy of an existing Account record using a custom button on Account Form. When button is clicked, a SOAP request is generated to invoke Action. Inside the Action a custom activity has been added as a step. Account Id is provided as an input argument to Custom Activity. After creating a copy, custom assembly returns the Id of the newly created record, new Account record is then opened in a popup window.
Steps:
Step 1- Create an Action
Step 2- Create Custom Workflow Activity to execute within Action
Step 3- Add step to call custom activity and Add Assign Value step to map action and custom activity’s output params:
Step 4- Call Action from JavaScript using SOAP request and Parse SAOP Response
Step 1- Create an Action
To create an Action, go to settings -> Processes -> New
Step 2- Create Custom Workflow Activity to execute within Action as step
public class CopyAccount : CodeActivity { [Input("Account Id")] [ReferenceTarget("account")] public InArgument<EntityReference> AccountId { get; set; } [Output("New Account Id")] public OutArgument<string> NewAccountId { get; set; } protected override void Execute(CodeActivityContext context) { var newAccountId = Guid.Empty; try { IWorkflowContext workflowContext = context.GetExtension<IWorkflowContext>(); IOrganizationServiceFactory serviceFactory = context.GetExtension<IOrganizationServiceFactory>(); IOrganizationService service = serviceFactory.CreateOrganizationService(workflowContext.UserId); EntityReference accountId = AccountId.Get<EntityReference>(context); var account = service.Retrieve(accountId.LogicalName, accountId.Id, new ColumnSet(true)); //Create new Account Entity newAccount = account; //Remove existing primary key - accountid account.Attributes.Remove("accountid"); //Assign new PK to new Account newAccount.Id = new Guid(); //Remove owner - logged in user will be the owner of the new record account.Attributes.Remove("ownerid"); //Create new account newAccountId = service.Create(newAccount); if (newAccountId != Guid.Empty) { // retun to Action NewAccountId.Set(context, newAccountId.ToString()); } } catch (Exception ex) { throw new Exception(ex.Message); } } }
Step 3- Add step to call custom activity and Add Assign Value step to map action and custom activity’s output params: Where business logic is implemented
Map Action Input Properties:
Map Action’s Output parameters with the value returned by custom activity:
Step 4- Call Action from JavaScript using SOAP request and Parse SAOP Response
function copyAccount() { var accountId = Xrm.Page.data != null ? Xrm.Page.data.entity.getId() : null; var accountLogicalName = "account"; var actionName = "new_CopyAccount"; 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>" + accountId + "</a:Id>"; requestMain += " <a:LogicalName>" + accountLogicalName + "</a:LogicalName>"; requestMain += " <a:Name i:nil=\"true\" />"; requestMain += " </b:value>"; requestMain += " </a:KeyValuePairOfstringanyType>"; requestMain += " <a:KeyValuePairOfstringanyType>"; requestMain += " <b:key>AccountId</b:key>"; requestMain += " <b:value i:type=\"a:EntityReference\">"; requestMain += " <a:Id>" + accountId + "</a:Id>"; requestMain += " <a:LogicalName>" + accountLogicalName + "</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>" + actionName + "</a:RequestName>"; requestMain += " </request>"; requestMain += " </Execute>"; requestMain += " </s:Body>"; requestMain += "</s:Envelope>"; var url = getClientUrl() + "XRMServices/2011/Organization.svc/web"; var xmlhttp = new XMLHttpRequest(); xmlhttp.open("POST", url, false); xmlhttp.setRequestHeader("Accept", "application/xml, text/xml, */*"); xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); xmlhttp.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute"); xmlhttp.onreadystatechange = function () { parseActionSOAPResponse(xmlhttp, successResponse, errorResponse); }; xmlhttp.send(requestMain); } function parseActionSOAPResponse(req, successCallback, errorCallback) { if (req.readyState == 4) { req.onreadystatechange = null; if (req.status == 200){ successCallback(req.responseXML); } else { errorCallback(req.responseXML); } } } function successResponse(responseXml) { var accountId = null; if (responseXml != null) { try { var x = responseXml.getElementsByTagName("a:KeyValuePairOfstringanyType"); if (x.length == 0) { x = responseXml.getElementsByTagName("KeyValuePairOfstringanyType"); } for (var i = 0; i < x.length; i++) { if (x[i].childNodes[0].textContent == "NewAccountId")/*Output Param set in Custom Activity - CopyAccount.cs*/ { accountId = x[i].childNodes[1].textContent; //Open newly created account if (accountId != null && accountId != "undefined" && accountId != "00000000-0000-0000-0000-000000000000" && accountId != "") openNewAccount(accountId, "account"); } } } catch (e) { alert("Erro Occured"); } } } function openNewAccount(recordId, entityLogicalName) { var features = "titlebar=yes, resizable=yes"; window.open("/main.aspx?etn=" + entityLogicalName + "&pagetype=entityrecord&id=" + encodeURIComponent(recordId), "_blank", features, false); } //In case of error function errorResponse(responseXml) { if (responseXml != null && responseXml.firstChild != null && responseXml.firstChild.firstChild != null) { try { var bodyNode = responseXml.firstChild.firstChild; for (var i = 0; i < bodyNode.childNodes.length; i++) { var node = bodyNode.childNodes[i]; if ("s:Fault" == node.nodeName) { for (var j = 0; j < node.childNodes.length; j++) { var faultStringNode = node.childNodes[j]; if ("faultstring" == faultStringNode.nodeName) { alert("Error: " + faultStringNode.textContent); break; } } break; } } hideProcessingBar(); } catch (e) { hideProcessingBar(); alert("Error while Copy account"); }; } else { hideProcessingBar(); alert("Error while Copy account"); } } // Return CRM path function getClientUrl() { var strUrl = Xrm.Page.context.getClientUrl(); if (strUrl.substr(strUrl.length - 1) != "/") { strUrl += "/"; } return strUrl; }