Calling an Action using SAOP Request in CRM 2013

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

Action

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

action-step-assembly

Map Action Input Properties:

input-params

Map Action’s Output parameters with the value returned by custom activity:

output param

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;
}

2 thoughts on “Calling an Action using SAOP Request in CRM 2013

Leave a comment