Mon, 11/23/2020 - 13:30 By Fabian Kalchofner
Dataverse Custom API

With the new Dataverse Custom API feature, we will be able to execute custom code directly. Please bear in, that this feature is still in preview.
In the past, we used custom actions to immitate a custom API. Custom actions were defined in CRM as workflow action and custom code was then called via workflow execution.

For a comparison of workflow custom actions and custom APIs, please check the official documentation: https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/custom-actions#compare-workflow-custom-action-and-custom-api

In this article, we will describe, how a custom API will be defined.

Define a new custom API

Custom APIs are solution aware and we highly recommend creating the custom API within a solution. However, you could also create it outside any solution.

Create custom API

Create custom API

  • Unique Name: Prefixed unique name, cannot be changed after creation
  • Name
  • Display Name: Localized name
  • Description: Localized description
  • Binding Type: The binding type, cannot be changed after creation
    • Global
    • Entity
    • EntityCollection (only for functions)
  • Bound Entity Logical Name: Entity logical name, required when binding type is not global, cannot be changed after creation
  • Is Function: Choose between function (yes) and action (no), cannot be changed after creation
    • An action is an operation that makes changes to data in the system (HTTP POST)
    • function is an operation that makes no change to data (HTTP GET)
    • If you intent to use the custom API within a flow, it is recommended to select action
  • Allowed Custom Processing Step Type: Choose, if other plugins can be registered to this API, cannot be changed after creation
    • None: No custom processing steps allowed.
    • Async Only: Only asynchronous custom processing steps allowed
    • Sync and Async: No restriction. 3rd party plug-ins can add synchronous logic to change the behavior of the message.
  • Execute Privilege Name: (Optional) Name of the privilege that allows execution of the custom API. Currently, you can only use OOTB privilege names.
  • Plugin Type: Select a plugin, which will be executed when the API is called. If you leave this blank for testing purposes, the API can still be called, but will return default values.
     

Create custom API request parameter

If you have bounded your action to an entity, you don't have to create a parameter to get the record, where the action or function is executed.

Custom API request parameter

  • Custom API: Select the previously created custom API record, cannot be changed after creation
  • Unique Name: The name must be unique related to a custom API record, cannot be changed after creation
  • Name: Recommended naming convention: {Custom API Unique Name}.{Parameter UniqueName}
  • Display Name: Localized name
  • Description: Localized description
  • Type: The type of the request parameter, cannot be changed after creation
    • Boolean
    • DateTime
    • Decimal
    • Entity
    • EntityCollection
    • EntityReference
    • Float
    • Integer
    • Money
    • Picklist
    • String
    • StringArray
    • Guid
  • Logical Entity Name: Entity logical name, required when type is Entity, EntityCollection, or EntityReference, cannot be changed after creation
  • Is Optional: Indicates, if the parameter is required or optional, cannot be changed after creation
     

Create custom API response property

Custom API response property

  • Custom API: Select the previously created custom API record, cannot be changed after creation
  • Unique Name: The name must be unique related to a custom API record, cannot be changed after creation
  • Name: Recommended naming convention: {Custom API Unique Name}.{Parameter UniqueName}
  • Display Name: Localized name
  • Description: Localized description
  • Type: The type of the response property, cannot be changed after creation
    • Boolean
    • DateTime
    • Decimal
    • Entity
    • EntityCollection
    • EntityReference
    • Float
    • Integer
    • Money
    • Picklist
    • String
    • StringArray
    • Guid
  • Logical Entity Name: Entity logical name, required when type is Entity, EntityCollection, or EntityReference, cannot be changed after creation

Plugin

  • Write the Plugin
    • The plugin will be executed in stage 30 (platform core operation)
    • The plugin message name will be equal to the custom API unique name
    • The request parameter will be in the plugin input parameters
  • Register the assembly
    • There is no plugin step to register, simply register the assembly
  • Assign plugin assembly to custom API record by updating the custom API record

 

Example

We will create a custom API to export PDF document from a word template.

Custom API

  • Unique Name: new_exportPdfDocument
  • Name: Export PDF document
  • Display Name: Export PDF document
  • Description: Export word template as PDF document
  • Binding Type: Entity
  • Bound Entity Logical Name: documenttemplate
  • Is Function: action
  • Allowed Custom Processing Step Type: Async Only
  • Execute Privilege Name: -
  • Plugin Type: Dynamics_Chronicles_Plugins.ExportPdfDocument
     

Custom API request parameter

  1. Entity id

    • Custom API: Export PDF document
    • Unique Name: entityId
    • Name: new_exportPdfDocument.entityId
    • Display Name: Entity id
    • Description: Entity id of the related record
    • Type: Guid
    • Logical Entity Name: -
    • Is Optional: No
  2. Entity type code

    • Custom API: Export PDF document
    • Unique Name: entityTypeCode
    • Name: new_exportPdfDocument.entityTypeCode
    • Display Name: Entity type code
    • Description: Entity type code of the record
    • Type: String
    • Logical Entity Name: -
    • Is Optional: No

Custom API response property

  • Custom API: Export PDF document
  • Unique Name: pdfDocument
  • Name: new_exportPdfDocument.pdfDocument
  • Display Name: PDF document
  • Description: Generated pdf document
  • Type: String
  • Logical Entity Name: -
     

Plugin

  • Get the parameters from context.InputParameters and parse them accordingly.
  • Execute the ExportPdfDocument request
  • Set context.OutputParameters
  • Register the assembly
  • Assign plugin assembly to custom API record by updating the custom API record
if (!context.MessageName.Equals("new_exportPdfDocument") || !context.Stage.Equals(30))
{
    tracingService.Trace("ExportPdfDocument plug-in is not associated with the expected message or is not registered for the main operation.");
    return;
}


if (!context.InputParameters.Contains("Target") || !(context.InputParameters["Target"] is EntityReference))
{
    tracingService.Trace("Target not found or not of type EntityReference");
}

try
{
    var target = (EntityReference)context.InputParameters["Target"];
    var entityId = (Guid)context.InputParameters["entityId"];
    var etc = (int)context.InputParameters["entityTypeCode"];

    var request = new OrganizationRequest("ExportPdfDocument");
    request["EntityTypeCode"] = etc;
    request["SelectedRecords"] = $"[\"{entityId}\"]";
    request["SelectedTemplate"] = target;

    var response = organizationService.Execute(request);
    context.OutputParameters["pdfDocument"] = Convert.ToBase64String((byte[])response["PdfFile"]);
}

Usage

Depending on the configuration, the custom API can either be executed by WebApi, Flow, or Plugin.

For our example, you could create a flow, which executes the action with Perform a bound action of the Common Data Service (current environment) connector.

Flow

Dataverse Custom API

Add new comment

Image CAPTCHA
Enter the characters shown in the image.