Dataverse Custom API – Global and Entity (Binding Type) example


We can define the Custom API’s binding type as Global, Entity, or Entity Collection. In this post, we can see how a Global and Entity binding type Custom API can be defined, write a corresponding plugin, and then invoke/test through Postman.

We can create Custom API through Plugin Registration Tool, Power Apps, Code, Solution files, and or can use XrmToolBox Plugin – Custom API Manager.

Below we have defined a Custom API name custom_GlobalAPI, with binding type as Global and one Request (input) parameter and Response (output) Property of type string.

Below is how we define the plugin type for it and can access the input and output parameters through context.

To test it we can use the XrmToolBox Custom API Tester plugin as shown below

And from Postman, once we have the access token, we can call the Custom API as shown below.

Now for a Bound Custom API, we have the following definition. It is bound to the Contact table and has one input parameter and one output parameter similar to our Global Custom API.

Below is how we define the plugin type for it, and can access the input and output parameters similar to Global Custom API.

However, in the case of binding type Entity, we will have the Request parameter named Target of type Entity Reference for the bound entity added automatically.

We can test it using the Custom API Tester plugin, however as it is bound type, we need to select/specify the contact record (the table it is bound to), before we can execute it.

To call it from Postman, we need to use the fully qualified name i.e. Microsoft.Dynamics.CRM.[unique name of the Custom API] unlike Global one.

 public class APIPluginGlobal : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService orgService = factory.CreateOrganizationService(context.UserId);

            try
            {
                tracingService.Trace("start plugin execution: {0}", this.GetType().FullName);

                // check for the message name i.e. Unique Name of the Custom API
                if (context.MessageName.Equals("custom_GlobalAPI", StringComparison.OrdinalIgnoreCase))
                {
                    // check for the request parameter in the inputparamters of the context 
                    if (context.InputParameters.Contains("inputParam"))
                    {
                        // get the value of the input parameter
                        string inputValue = context.InputParameters["inputParam"].ToString();
                        // set the value of response property through outputparameters 
                        context.OutputParameters["outputParam"] = "Got following value as Input : " + inputValue;
                    }
                }

                tracingService.Trace("end plugin execution: {0}", this.GetType().FullName);
            }
            catch (System.ServiceModel.FaultException<OrganizationServiceFault> ex)
            {
                tracingService.Trace(ex.Detail.Message);
                throw;
            }
            catch (Exception ex)
            {
                tracingService.Trace(ex.ToString());
                throw;
            }
        }
    }
public class APIPluginBound : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService orgService = factory.CreateOrganizationService(context.UserId);

            try
            {
                tracingService.Trace("start plugin execution: {0}", this.GetType().FullName);

                // unique name of the custom api
                if (context.MessageName.Equals("custom_BoundAPI", StringComparison.OrdinalIgnoreCase))
                {
                    // Target property of type Entity Reference
                    if (context.InputParameters.Contains("Target") &&
                        context.InputParameters["Target"] is EntityReference)
                    {
                        var contact = (EntityReference)context.InputParameters["Target"];
                        // access the input request parameter
                        if (context.InputParameters.Contains("inputParam"))
                        {
                            string inputValue = context.InputParameters["inputParam"].ToString();
                            // set the output parameter value
                            context.OutputParameters["outputParam"] = "Got following as Input Parameter : " + inputValue
                                + " for record : " + contact.Id.ToString();
                        }
                    }
                }

                tracingService.Trace("end plugin execution: {0}", this.GetType().FullName);
            }
            catch (System.ServiceModel.FaultException<OrganizationServiceFault> ex)
            {
                tracingService.Trace(ex.Detail.Message);
                throw;
            }
            catch (Exception ex)
            {
                tracingService.Trace(ex.ToString());
                throw;
            }
        }
    }

Hope it helps..

Advertisements

Free up storage space – Dataverse / Dynamics 365


Recently for setting up a new environment, we created a new sandbox environment and copied the production environment to it. Next, we had to reduce the storage space occupied by this new environment.

We followed the below steps

  • Bulk Deletion Job – Delete Email Messages having Attachments older than 1 month.
  • Bulk Deletion Job – Delete Notes having attachments older than 1 month.
  • Delete System Job with Status as Succeeded.
  • Delete Process Session with Status as Complete
  • For Logs, we deleted Audit Logs
  • Similarly, we can also delete Plugin Trace Logs records.

These steps allowed us to decrease the Database Usage from 110 GB to 65 GB.

And File Usage from 315 GB to 16 GB.

Also, check –

Get all the details here –

https://learn.microsoft.com/en-us/power-platform/admin/free-storage-space

Hope it helps..

Advertisements

Use Query Assist Copilot to create Segments (Dynamics 365 Marketing)


Using Query Assist Copilot we can create segments easily through its Natural Language Processing (NLP) capability.

Create a new Segment from Real-Time Marketing >> Audience >> Segments

Specify the segment name and the target audience (either contact or lead)

Now in Query Assist, we can specify the details of the segment

It also provides us the suggestions.

Let us select the “Contacts who were created last year and make more than $50K” option and append “who work in Financial Industry to it”.

Clicking on Create will open the segment designer page along with the Query Assist panel, which shows the result of the Query.

Click on Use to use that query result.

We can add further conditions to it.

Here we selected the example “Contact who opened an email

We can then add the result through the “Use” option

The query gets updated with the new condition

We also get the option to generate a summary for the segment or get suggestions for improving the segment.

Clicking on View Summary generates the summary.

Get all the details here

Hope it helps..

Advertisements

Pin Activities in Timeline – Dynamics 365


With the 2023 Release Wave 2, as per Microsoft Documentation, we can pin activities such as records to the top of the timeline.

We could see that option available for the Notes in the timeline.

It also shows the number of records pinned.

To unpin it, we need to click the icon again, and the record will move to its original position.

Hope it helps..

Advertisements

Use Sales Copilot to get recent updates (Catchup) on a lead and opportunity (Dynamics 365)


Using Sales Copilot, we catch up on updates to a lead and opportunity record since the last seven days or the last login.

We can use the prompt catchup with lead or catchup with opportunity followed by @ and the name of the record.

Sales Copilot uses Audit History to show the recent updates.

Allow data movement across regions in the Power Platform Admin Center using Enable copilots and generative AI features outside United States and Switzerland – Power Platform | Microsoft Learn

To enable Sales Copilot, navigate to

Sales Hub >> App Settings >> Sales Copilot (preview) >> Set up Sales Copilot

Or if we have already enabled it, we can manage the features provided along with the different apps we want to apply the Sales Copilot using the Manage apps option.

Here we can specify to which apps we want to enable the Compose and Chat feature.

For the Record catch-up feature, the first 10 fields of the view are considered. We can see “Default System View” selected by default.

However, we have the option to select a different view, and then the fields of the selected view will be used for generating the catchup content.

Below if we select the Open Opportunities view, we can see its corresponding fields that will be considered for the catchup.

We can open an existing lead or opportunity record or from the Chat tab of Sales Copilot can use catchup with opportunity prompt as shown below to get the updates.

We can see the catch-up details generated.

Also, we see another prompt – “Catch up since my last
login (16 hours ago)”, along with “catchup with lead or opportunity” prompt


If there are no updates to a record in the last 16 hours, we get the below message.

Get more details here.

Hope it helps..

Advertisements

Enhanced Active Conversation form in Omnichannel for Customer Service – Dynamics 365


The conversation form in Omnichannel is now updated to allow agents to view and edit customer and case information more efficiently.

To enable it, Inside Customer Service Admin Center app – navigate to Workspaces >> Active Conversation form settings (Manage)

Before we enable it let us have a look at the exiting conversation form.

Now let us enable and compare it with the enhanced one.

We can see the form displaying a Customer 360 Card for Customer (Contact or Account), which also allows for inline editing of details from within the Conversation form, and a similar card showing case details and allowing for inline editing. The fields that are displayed are configurable.

Another change is the color-coded priority and case status field for easy discoverability for the agents.

Hope it helps..

Advertisements