Nov 17, 2023

Write a Custom API call from Clout Flow

In a previous article, we check how we Write a Custom API and calling it from classic workflow. It worked well, yet we encountered some hiccups in deployment. Actually, recommended way it co call it from a Cloud Flow than a workflow.

Lets check that using a simple sample Cloud Flow. Implementation of the Custom API remains the same. Please refer that part from previous post. 

Lets do the calling part from a Cloud Flow. I would select a flow that would could be triggered on demand from the custom entity (in our case so_office).

First I am selecting a task to trigger when selecting a record from Office where I need to select the environment along with entity.


Then I need to select Perform a bound action from list of actions of Microsoft Dataverse.


Now interestingly, we can see our Custom API within the Action lists shown, which we would select as below. Then we need to pass the row Id passed by trigger from the first action.


Now if you go open and office record, you are able to runt he Flow on Demand as any other workflow is triggered. 


Here I demonstrated only simple on demand flow for ease of demonstration, but what we need to learn is, in any flow we can call out Custom API using Performa Bound Action of Microsoft Dataverse. Most importantly, this is the recommended way than calling from a workflow. 

Nov 4, 2023

Check if deployed assembly got your code

While we have all the processes in place for deployments, I still sometimes feel like checking if my code change was actually deployed. This happens when we work with many developers at the same time where anyone can deploy a new version of assembly to DEV environment. What is in the DEV at the time of the deployment will be pushed to other environments. Here we explain a way to decompile and check the assembly using two tools.

A. Download the Assembly using Assembly Recovery Tool (Xrm Toolbox)

Once we connect to an environment and load the tool, it list down all the assemblies of the environment.



Then its a matter of selecting the correct assembly and download.


B. Decompile the code using JetBrains DotPeak (https://www.jetbrains.com/decompiler/)

Download and install the JetBrains DotPeak tool in your PC/ Laptop.

Then you are able to open the folder where you saved the Assembly in the previous step where you can go down to classes and identify the method you are interested in. Then double click it and you will get the code in right hand side pane.


Hope this helps.

Oct 21, 2023

Can Fetch Xml Builder be used to extend the limitations of Dataverse views ?

Base of Views in Dataverse is actually fetchxml. Views got limitations. Not all the features of Fetchxml being used in creation of views. In other hand Fetchxml builder allows filter data based on complex fetchxmls and it allows creating views in Dataverse based on them. Someone would thing, just as I did, this can be a way to views with more complex criteria. Hm.. lets find out. 

Lets take this example. We have below hierarchy of entities.

Out requirement is to create a view of Sub Depots where Account Category = Distribution and you need to show both Sub Depots against the Account Name.

Lets try this in Dataverse OOB capabilities. 


Though you can easily set the criteria, you will not be able to show the Account name since Account entity is 3 hops away as per the given hierarchy of entities. You are only able to show just two levels. In this case, Sub Depots and Depots.

Lets try Fetch Xml Builder of Xrm Tool Box.


And Results showing without any issue.


Now we will try our next step of transferring this same Fetch to Dataverse. 

Now select Save View as option;


Then you get below option to select if you need a personal or system view.


Then you are allowed to give a name to the new view.


View is now created.

Lets try the view now in Dataverse. When you check the fields you will see Dataverse is throwing a error saying these Account fields to be removed,


If you try to run as it is, it will through below error message.


Conclusion

NO! 
You cannot use Fetch Xml Builder to create Views in Dataverse that extends the limitations.

Oct 18, 2023

Write a Custom API and call from Workflow

A Custom API is comparatively a new mechanism to create your own API in Dataverse. This is like a Action where you can package few steps to accomplish something. Advantage is you can then call from anywhere, either client side or server side etc. Obviously it can be called via a workflow or Cloud Flow too. Custom API is more flexible since coding is possible.

In this scenario we will see how to create a simple Custom API and call it from a classic workflow.

Writing a Custom API

1) We need to write a code which is pretty similar to a Plug-in. This is where we define our logic. In my case I am accepting a parameter string (i.e. DetailStr) and update Description (i.e. so_description) field of the custom entity called Office (i.e. so_office).

namespace AccAdmin.Plugins.CustomApi
{
    public class UpdateOffice : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context;
            IOrganizationServiceFactory factory;
            IOrganizationService service;

            try
            {
                context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
                ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

                if (!context.InputParameters.Contains("DetailStr"))
                    throw new InvalidPluginExecutionException($"DetailStr not designated or Invalid..");

                if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is EntityReference target)
                {
                    if (target.LogicalName != "so_office") return;
                    factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                    service = factory.CreateOrganizationService(context.UserId);

                    Entity entity = new Entity();
                    entity.LogicalName = "so_office";
                    entity.Id = context.PrimaryEntityId;
                    entity["so_description"] = (string)context.InputParameters["DetailStr"];
                    service.Update(entity);
                }
            }
            catch (FaultException<OrganizationServiceFault> e)
            {
                throw e;
            }
            finally
            {
                service = null;
                factory = null;
                context = null;
            }
        }
    }
}

2) Once register the Plug-in, Custom API step will be visible as a step as below.


3) Now we start configuration. First add new Custom API to your solution.
    

Once save my Custom API was seen like below. It will have an unique name which we use to call this. We have set Enable for Workflow = Yes since we plan to call this from a Workflow. Most importantly, we have set our Plug-in step as the Plugin Type which is the linking point of our logic to the API. 


* Idea of all other settings

4) Same way we added the Custom API, we now add a parameter to our solution. Parameter is optional. In our case we plan to pass a string parameter.


Once created, parameter was seen as below. Nothing complex about this. You may notice we have selected Custom API we defined in previous step is set here for Custom API field.


Now we are done with our Custom API

Calling the Custom API from Workflow

Here I am create just an On Demand workflow so we can easily check it.

5) I am initiating a very simple Async workflow against Office entity.


6) Now I am adding a step of performing an Action. Interestingly, when I check the list of available Actions, I am seeing my Custom API by its unique name.


I see two parameters here. One is Target where we need to pass the current office record. Other one is what we define in Custom API which is needed for our logic.


7) Now its a matter of running our Workflow On Demand for any selected Office record.

* 
Unique Name: Unique name for the Custom API (Start with the publisher’s prefix which you have specified on your solution).

Name: Name for the Custom API.

Display Name: Display Name for this Custom API. In case we have enabled multi-languages on the System, we can provide a specific name for the custom API based on the language.

Description: This field is to store the description of this Custom API.

Binding Type: The Binding Type is the Options set field and could be set as Global, Entity, and Entity Collection. This should be specified as per your operation requirement (Entity Collection is only supported in Function Type Custom API).

Bound Entity Logical Name: This field is required when we select the Binding Type as Entity or Entity Collection. For the binding type as Global, it can be empty.

Is Function: It defines whether your custom API is a Function (this can only be called using Get Method) or Action (this can only be called using POST method).

Is Private: To define the Custom API is private or public (setting it private makes it accessible to only the owner of the Custom API).

Allowed Custom Processing Step Type: Allowed Custom Processing Step Type is another Option set field with options like None, Async Only, Sync, and Async. These options let you define whether the other plugins could be registered on this Custom Message and also lets you define its behavior. Like Async Only allows the plugins to register only onPost operation with Execution Mode to Asynchronous, and same for the Sync and Async option.

Execute Privilege Name: We can define the privilege that allows execution of the custom API. As per Microsoft docs, we can also create custom privileges and it is currently in development. We can use OOB privileges, for example,prvCreateLead, prvWriteLead, etc.

Plugin Type: Set the reference of your plugin for this API.

Warning
This example works fine. Anyway, there has been some deployment issues reported as per now we write this. So it is always advisable to call your Custom API from a Cloud Flow than a classic workflow. That worked perfectly.

Sep 21, 2023

Check current environment inside Flow

It can be useful to understand what environment flow is running on. This enables us perform separate action or use separate values based on the environment. Lets see how to do that.

Component we use here is Get Environment as Admin of Power Platform for Admins.


This lists down available environments along with option to give custom value which we select here. 


Then we need to select below formula.

workflow()['tags']['environmentName']


When we do any action, now we are allowed to select Display Name from same component and it will return the respective environment name.


We can use Compose component to check if you get the Environment name correctly.


Usually we use IF condition to perform separate action or use separate values by environment. In below example, IF condition is used to set company Email address only if the Environment is UAT otherwise use personal Email address.
 
if(equals(outputs('Get Environement as Admin')?['body/properties/displayName'],'UAT'),'info@abc.com','sumedha@abc.com')

Hope this helps.

Aug 30, 2023

Show/ Hide Ribbon button based on a Security role

This is a frequently asked requirement in Model driven apps. Obviously you need to use Ribbon Workbench (of Xrm Tool Box). Lets see how we achieve it.

Any button command has Display Rules and Enable Rules. Here we enhance the Enable Rule to achieve this. Actually, we write the logic in a JavaScript to match the security role by Id with logged in users security roles and return True/ false accordingly.

Suppose our JS name is AccountRibbon.js and below is the method I implement. Hope its self-explanatory. 

function IsAutherizationRoleIncluded(execCtx) {

    var currentUserRoles = execCtx._globalContext._userSettings.securityRoles;
    var roleId = "92D1FC2B-8A22-ED11-9DB1-00224818AFAC"; // Id of the role
    roleId = roleId.toLowerCase();
    // Get all the roles of the Logged in User.

    for (var i = 0; i < currentUserRoles.length; i++) {
        var userRoleId = currentUserRoles[i];
        if (userRoleId == roleId) {
            console.log("Role Found");
            return true;
        }
    }
    console.log("Role NOT Found");
    return false;
}

Now we need to associate this method to Ribbon Button as a Custom Rule as below;


Now button will be shown/ hidden based on availability of the security rule.

May 16, 2023

Reset Auto number field

Not like old versions, Dataverse has the capability of setting auto numbers. Its very flexible and can arrange to auto increment as per any pattern you may like. 


Sometime it is required to reset these numbers. Consider a situation that you are doing a data migration that require testing few times in same environment. In this situation, resetting the Auto numbers could be needed.

What you need to do is change the Seed Value and publish. Then Auto Number is reset. 


May 4, 2023

Workflow to run against BPF entity

Though we do so many Business Process Flows, it is not that common to trigger another workflow when applying the BPF. Well ,it is possible. As we do in other instances, we only have to select the BPF Entity/ Table and you will see below configuration page which is pretty usual.

If look carefully, you will notice quite different trigger events are lined-up. In given example, we have selected Process is Applied and Process Status changes.


One of the cool things you can do is to set active step depending on some conditions (Conditions in the entity record where BPF is defined based on). For example, if the BPF is done on Account entity, we can control which step BPF should jump into based on some fields of Account. 

Caution

Anyway, there is one situation you have to be careful of. In some cases, we write more than one Business Process Flows and create a switching mechanism in JS Script. So record is jumping to correct BPF upon opening of the record.

In this case, if you write a WF against a BPF which is not the default one, pl keep in mind your Workflow which should have triggered for Process is Applied will not trigger immediately. It will trigger only after someone open the record. Obviously, JS will fire only after record is open and then only correct BPF is applied for the first time. Make sense right ?