In previous post I described how to perform CRUD operations using OOB wrapper for WebApi operations released as a part of v9.0 release. In this I will describe 2 remaining methods – execute and executeMultiple. Methods are used to execute actions or functions.
Let me start from execute and actions. execute method accepts “request” object as parameter and returns Promise object as all other methods described before. To get understanding of those objects I had to reverse-engineer source code. If you’re interested about in all requests available OOB you can check following JS files for reference:
https://yourcrm.crm.dynamics.com/webresources/sales/clientcommon/sales_clientcommon.js
Request has to contain not only data of request itself but special function getMetadata that returns object that completely describes request here are required members for that function:
- “boundParameter” – if your Action/Function has no binding then pass null, if it’s bound to entity – pass “entity”, if it’s bound to set of entities, pass “entityset”.
- “parameterTypes” property should contain metadata that describes all the parameters you have in your action/function.
- “operationName” is self-explanatory – it’s a name of Action of Function you want to call.
- “operationType” – set 0 for Action and 1 for Function
![]() |
![]() |
![]() |
Example of Unbound Action | Example of Entity-Bound Action | Example of EntitySet-Bound Action |
Here is example of WinOpportunity action that is unbound action:
var winOpportunityRequest = { OpportunityClose: { "opportunityid@odata.bind": "/opportunities(32DE8FA9-03AA-E711-A94E-000D3A109280)", "actualrevenue": 100, "actualend": new Date(), "description": "Your description here" }, Status: -1, getMetadata: function() { var metadata = { boundParameter: null, parameterTypes: { "OpportunityClose": { "typeName": "Microsoft.Dynamics.CRM.opportunityclose", "structuralProperty": 5 }, "Status": { "typeName": "Edm.Int32", "structuralProperty": 1 } }, operationName: "WinOpportunity", operationType: 0 }; return metadata; } }; Xrm.WebApi.execute(winOpportunityRequest) .then(function(result) { //Handle retrieved data }) .fail(function(error) { var message = error.message; //Add handling of error that occurred });
Following screenshot demonstrates mapping between metadata of request and request object:
Example of CalculateActualValueOpportunity action that is entity-bound action:
var calculateActualValueOpportunityRequest = { entity: { id: "32DE8FA9-03AA-E711-A94E-000D3A109280", entityType: "opportunity" }, getMetadata: function () { var metadata = { boundParameter: "entity", parameterTypes: { "entity": { "typeName": "Microsoft.Dynamics.CRM.opportunity", "structuralProperty": 5 } }, operationName: "CalculateActualValueOpportunity", operationType: 0 }; return metadata; } }; Xrm.WebApi.execute(calculateActualValueOpportunityRequest) .then(function (result) { var response = JSON.parse(result.responseText); var calculatedValue = response.Value; //Handle retrieved data }) .fail(function (error) { var message = error.message; //Add handling of error that occurred });
Following screenshot demonstrates mapping between metadata of request and request object for Entity-Bound Action. Main difference between this and previous request objects – boundParameter property of object is set to “entity” instead of null and “entity” property in parameterTypes:
Example of FulfillSalesOrder that is EntitySet-Bound action. Main difference between this and previous requests – “boundParameter” property is set to “entityset” instead of “entity” like in previous example and “entityset” property available in “parameterTypes” instead of “entity”.
var fulfillSalesOrderRequest = { OrderClose: { "subject": "Put Your Fulfill Subject Here", "salesorderid@odata.bind": "/salesorders(58D2C742-9F0D-E711-8102-3863BB354FF0)", "description": "Additional Description Here", "actualend": new Date() }, Status: -1, getMetadata: function () { var metadata = { boundParameter: "entityset", parameterTypes: { entityset: { typeName: "mscrm.salesorder", structuralProperty: 4 }, OrderClose: { typeName: "Microsoft.Dynamics.CRM.orderclose", structuralProperty: 5 }, Status: { typeName: "Edm.Int32", structuralProperty: 1 } }, operationName: "FulfillSalesOrder", operationType: 0 }; return metadata; } }; Xrm.WebApi.execute(fulfillSalesOrderRequest) .then(function (result) { var response = JSON.parse(result.responseText); //Handle retrieved data }) .fail(function (error) { var message = error.message; //Add handling of error that occurred });
In the next part I will demonstrate how to build and use request objects for functions.
Any idea if this is supported or if this is the intended usage? I was thinking that eventually this will be added to Xrm.WebApi.messages that refreshes with changes and probably also a tsd file to go along, so I can reduce the boilerplate.
Natraj,
To be honest I can’t give you exact answer until SDK is released.
Andrii
Natraj,
Looks like my description is accurate 🙂
https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference/xrm-webapi/execute
I missed just operationType = 2 for CRUD.
Do you know if “Xrm.WebApi.execute” is available in 8.2? If not, is my only option to follow this approach?
https://www.wipfli.com/insights/blogs/connect-microsoft-dynamics-365-blog/160810-calling-custom-actions-from-javascript
Cheers,
Mark
Mark,
Xrm.WebApi namespace was released as a part of v9.0 and it’s not available in earlier versions. With 8.2 you will have to use other approach like in article you mentioned.
Thanks,
Andrew
I have created an action , New_SendReportToSharePoint
Call metadata, I see this definition
java-script request looks like this.
var accountid = Xrm.Page.data.entity.getId();
var new_SendReportToSharePointRequest = {
entity: {
id: accountid,
entityType: “account”
},
ReportPayload: “mybase64 encoded string”,
getMetadata: function () {
var metadata = {
boundParameter: “entity”,
parameterTypes: {
“entity”: {
“typeName”: “Microsoft.Dynamics.CRM.account”,
“structuralProperty”: 5
},
“ReportPayload”: {
“typeName”: “Edm.String”
}
},
operationName: “new_SendReportToSharePoint”,
operationType: 0
};
return metadata;
}
};
Execution looks like this.
Xrm.WebApi.execute(new_SendReportToSharePointRequest)
.then(function (result) {
var response = JSON.parse(result.responseText);
var calculatedValue = response.Value;
//Handle retrieved data
})
.fail(function (error) {
var message = error.message;
//Add handling of error that occurred
});
}
I don’t see the response entering success or failure branches. I suspect it is my ‘ReportPayLoad’ input parameter. I’m not sure if there is a specific value for structuralproperty I am supposed to pass for ReportPayLoad. Also, I do not see any trace of the plug-in executing.
Cheers
Mark,
What version are you on? If it’s earlier then 9.0 usage of Xrm.WebApi should cause error in your code.
Thanks,
Andrew
It seems like you can also use
result.json().then(function(json) {
//this contains the response properties in JSON format
});
in your response handler.
Probably Microsoft has implemented some custom json deserializing :-).
Nathan,
Thanks for a tip. Have never seen that.
Andrew
Hello Andrew, Thanks for your usefull posts; Do you have any suggestion or example to develop Xrm.WebApi.Execute samples with user defined Action like new_myaction (or new_webapiaction56e28da25300e811a959000d3a1a941e) ??
Best regards.
Hello I tried on my Demo (365 V9.0) this code
var calculateAccountWebApiRequest = {
entity: {
id: accountid,
entityType: “account”
},
getMetadata: function () {
var metadata = {
boundParameter: “entity”,
parameterTypes: {
“entity”: {
“typeName”: “Microsoft.Dynamics.CRM.account”,
“structuralProperty”: 5
}
},
operationName: “cg_webapiaction56e28da25300e811a959000d3a1a941e”,
operationType: 0
};
return metadata;
}
};
Xrm.WebApi.execute(calculateAccountWebApiRequest)
.then(function (result) {
var response = JSON.parse(result.responseText);
var calculatedValue = response.Value;
//Handle retrieved data
})
.fail(function (error) {
var message = error.message;
//Add handling of error that occurred
});
I received this error : –> error.message = “Request message has unresolved parameters.”
Do you have any suggestion to solve this Issue ?
Can you please post screenshot of your action somewhere and post a url here?
hello Andrew,
this is the link
https://1drv.ms/i/s!Av4DLblClmD4ivJk4CTxfRIKYM-GoA
you can watch the screenshot of the user defined action
let me me know if you don’t see the image
I have similar issues. It seems that request is not get serialized in proper way. Here is the code that worked for me. Check if it worked for you:
var parameters = {
Target: {
entityType: “account”,
id: accountid
}
};
Xrm.Utility.invokeProcessAction(“cg_webapiaction56e28da25300e811a959000d3a1a941e”, parameters)
.then(function (result) {
var actionResponse = result.get_outputParameters();
var resultString = actionResponse.Result;
console.log(“Action was executed. Result is equal to ” + resultString);
})
.fail(function (error) {
console.log(“error during execution of action -” + error.debugMessage);
});
Hello Andrew
your code work (I changed only characthers –>”<– )
this my code changes
1) I created new action cg_onboundwebapiaction
2) set up Entity = none(global)
3) I changed the code i this way
var calculateAccountWebApiRequest = {
/* entity: {
id: accountId.toString().replace("{","").replace("}",""),
entityType: "entity"
}, */
getMetadata: function () {
var metadata = {
boundParameter: null,
parameterTypes: {
/* "entity": {
"typeName": "Microsoft.Dynamics.CRM.account",
"structuralProperty": 5
} */
},
operationName: "cg_onboundwebapiaction",
operationType: 0
};
return metadata;
}
};
Xrm.WebApi.execute(calculateAccountWebApiRequest)
.then(function (result) {
var response = JSON.parse(result.responseText);
var calculatedValue = response.Result;
})
.fail(function (error) {
var message = error.message;
});
it works
thanks for your help !!