Custom Actions in JavaScript with Output Parameters in D365 and PowerApps

3 Comments

In this post, we will look at how to retrieve output parameters from custom actions in the Dynamics 365 and Power Apps from JavaScript.

Firstly, I blogged previously about how to run custom actions in Dynamics 365 / Power Apps using Xrm.WebApi.online.execute. It appears in some conditions, this functionality does not return output parameters from an action. Issues I have found specifically include using this with Unified Interface / UCI pages with the JavaScript on a non-HTML web resource.

Let’s go through an example to see how this works.

First, let’s create a new custom action in Dynamics 365 / Power Apps. Our action will add 2 numbers together and return the answer. We have 3 arguments:

  • Number1 – Input Integer
  • Number2 – Input Integer
  • Number3 – Output Integer

Save and activate the action.

In the Web API, we can see the signature of this action created and the response we expect:

Next, let’s create a new custom action in Visual Studio.

Create a new Class Library (.NET Framework):

Give it a name, e.g. Carl.AddNumbers:

Add Microsoft.CrmSdk.CoreAssemblies through NuGet:

Now the code. Below we receiving Number1 and Number2 as InputParameters, and outputting Number3 as our added answer:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;

namespace Carl.AddNumbers
{
    public class CustomAction : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);

            var Number1 = (int)context.InputParameters["Number1"];
            var Number2 = (int)context.InputParameters["Number2"];
            var Number3 = Number1 + Number2;

            context.OutputParameters["Number3"] = Number3;
        }
    }
}

Build the project and sign the assembly:

Deploy the assembly:

And register a new step with Primary entity = None:

Now, let’s run this through JavaScript.

Using the Xrm.WebApi.online.execute, our code looks like below:

var parameters = {};
parameters.Number1 = 7;
parameters.Number2 = 9;

var new_AddNumbersRequest = {
    Number1: parameters.Number1,
    Number2: parameters.Number2,

    getMetadata: function() {
        return {
            boundParameter: null,
            parameterTypes: {
                "Number1": {
                    "typeName": "Edm.Int32",
                    "structuralProperty": 1
                },
                "Number2": {
                    "typeName": "Edm.Int32",
                    "structuralProperty": 1
                }
            },
            operationType: 0,
            operationName: "new_AddNumbers"
        };
    }
};

Xrm.WebApi.online.execute(new_AddNumbersRequest).then(
    function success(result) {
        if (result.ok) {
            var results = JSON.parse(result.responseText);
console.log(result);
        }
    },
    function(error) {
        Xrm.Utility.alertDialog(error.message);
    }
);

Running this in the browser debugger, our output looks like below without responseText returned:

And running this from a web resource, we see we get responseText back:

To clarify, we sent 7 and 9 and received 7+9 = 16:

Note – the web resource method takes a different code path through the platform, I’m not sure why the output would be different but if anyone has any insight please post in the comments.

The fix for this, is to use XMLHttpRequest instead of the Xrm.WebApi. The code:

var parameters = {};
parameters.Number1 = 7;
parameters.Number2 = 9;

var req = new XMLHttpRequest();
req.open("POST", Xrm.Page.context.getClientUrl() + "/api/data/v9.1/new_AddNumbers", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function() {
    if (this.readyState === 4) {
        req.onreadystatechange = null;
        if (this.status === 200) {
            var results = JSON.parse(this.response);
        } else {
            Xrm.Utility.alertDialog(this.statusText);
        }
    }
};
req.send(JSON.stringify(parameters));

In running this in the browser, we get our desired output parameter back:

UPDATED:

Thanks for Jim Halligan for posting a better way to do this in the comments below.

The full code:

var parameters = {};
parameters.Number1 = 7;
parameters.Number2 = 9;

var new_AddNumbersRequest = {
    Number1: parameters.Number1,
    Number2: parameters.Number2,

    getMetadata: function () {
        return {
            boundParameter: null,
            parameterTypes: {
                "Number1": {
                    "typeName": "Edm.Int32",
                    "structuralProperty": 1
                },
                "Number2": {
                    "typeName": "Edm.Int32",
                    "structuralProperty": 1
                }
            },
            operationType: 0,
            operationName: "new_AddNumbers"
        };
    }
};

Xrm.WebApi.online.execute(new_AddNumbersRequest).then(
    function success(result) {
        result.json().then(
            function (response) {
                var sixteen = response.Number3;
            }
        );
    }
    ,
    function (error) {
        Xrm.Utility.alertDialog(error.message);
    }
);

This produces:

 

THANKS FOR READING. BEFORE YOU LEAVE, I NEED YOUR HELP.
 

I AM SPENDING MORE TIME THESE DAYS CREATING YOUTUBE VIDEOS TO HELP PEOPLE LEARN THE MICROSOFT POWER PLATFORM.

IF YOU WOULD LIKE TO SEE HOW I BUILD APPS, OR FIND SOMETHING USEFUL READING MY BLOG, I WOULD REALLY APPRECIATE YOU SUBSCRIBING TO MY YOUTUBE CHANNEL.

THANK YOU, AND LET'S KEEP LEARNING TOGETHER.

CARL

https://www.youtube.com/carldesouza

 

ABOUT CARL DE SOUZA

Carl de Souza is a developer and architect focusing on Microsoft Dynamics 365, Power BI, Azure, and AI.

carldesouza.comLinkedIn Twitter | YouTube

 

3 Responses to Custom Actions in JavaScript with Output Parameters in D365 and PowerApps

  1. Hi Carl,
    Thank you for your great job, is this way of calling parameters works with dynamics 9.1 on-premise with unify interface, i try another way with process.js but unfortunately it didn’t work and the ribbon bottom do nothing in unify interface.?

Leave a Reply

Your email address will not be published. Required fields are marked *