February 25, 2024

new project: QR Code Custom APIs

As I wrote in my previous post, in the recent months I created several Custom APIs and some of them are available inside my GitHub account.

The latest one is QR Code Custom APIs

Right now there is a single Custom API called GenerateQRCodeUrl

As input accepts a Url (string) and it returns the Base64 representation (string) of a PNG file, this can be used for example inside HTML content (setting the src property like data:image/png;base64, [BASE64 VALUE]) or for example to store the value as a note/attachment.

Here an example of a QR Code generated with this Custom API (it points to www.microsoft.com)


Big thanks to the project QRCoder that I am using inside this Custom API.

February 9, 2024

Impersonate Dataverse Users connected to Entra ID Groups

When a Security Group is assigned to a Dataverse Environment users need to be part of the selected Microsoft Entra ID Group (directly as members or if they are inside a group that is member of the main group) otherwise they cannot be added.

This facilitates the work of the IT department to manage who can access or not a specific environment, also a specific Team inside Dataverse can be created to map the Microsoft Entra ID Group:
Keep in mind that to a Dataverse Team you can assign Security Roles or Column Security Profiles.
Which is the disadvantage? By default users appear inside the Environment only after their first login, for some apps this is not a big deal, but for other apps users must be present before their first login.

To force the users you can use a PowerShell cmdlet (link) or a Power Automate flow (link1, link2), in this way the users will be added to the environment and they will appear inside the systemuser table.

However this approach solves half of the problem (in my opinion) because the users are added indeed to the Environment, but they are not added to the Dataverse Team connected to the Entra ID Group they are coming from, the association to the Team will happen indeed at their first login.

Let's recap: inside Entra we have the user "John Doe", it has been added inside the Entra ID Group called "Super Users" setup as Security Group for the Environment.
Inside the Environment there is the Team (Entra ID type) connected to Entra "Super Users", we forced the synchronization of the user so there is a systemuser record related to "John Doe" but this record is not associated with the Team "Super Users".

And you can think: why we should care? the problem is that the user is inside the Environment but without security roles, probably the security roles will be inherited from the Teams the user is a member of, but right now is not member of any team, they need to login first.

Again: why we should care? the problem is that if the user has no security roles, the user cannot be the owner of a record inside your Environment.

Think about a migration: you have 500 users, and 10000 account records to migrate from Ennvironment A to Environment B, these 500 users they have the right security role by the Team described above but we cannot assign them an account until they login first.

The solution is to programmatically impersonate these users and perform an action inside the Dataverse, in this way we simulate a login and all the processes associated with it (including the association to the Team)

You can probably do this with a Power Automate flow but I decided to implement this logic in C#, mainly because the WhoAmI request is not available inside the unbound actions but is one of the common requests to be executed using the C# Dataverse SDK:
QueryExpression querySystemUsers = new QueryExpression("systemuser");
querySystemUsers.ColumnSet = new ColumnSet("fullname");
EntityCollection collSystemUsers = service.RetrieveMultiple(querySystemUsers);
// Note: if your users are more than 5000 you need to do pagination!

Dictionary<Guid, string> dictErrors = new Dictionary<Guid, string>();
foreach (Entity user in collSystemUsers.Entities)
{
    try
    {
        service.CallerId = user.Id;
        service.Execute(new WhoAmIRequest());
    }
    catch (Exception ex)
    {
        dictErrors.Add(user.Id, $"{user.GetAttributeValue("fullname")} - {ex.Message}");
    }
}
As you can see inside the code, the property "CallerId" is used to impersonate the user before executing the WhoAmIRequest (probably you can use also the property "CallerAADObjectId" if you have a list of the Entra Object IDs if the users are not synced before).

Why I added a try/catch inside my code? If for example the user has not a license, it will throw an exception, so better to handle this scenario as well.

Hope it helps!





January 9, 2024

Custom APIs for Power Automate: why they should be developed

Power Automate is an important piece of the Power Platform, no doubts about this.
Can it be improved? Sure.

Low-Code and Pro-Code are two buzz words constantly being around Power Platform, which side you prefer it's not my business, as I often says there are different ways to implement a process, it's also the beauty of programming (traditional or visual).

One thing I do not like is to create convoluted processes to achieve something that is very easy using another tool, we always need to tend to simplification in my opinion, considering the context where the application lives.

How can we improve and simplify flows created in Power Automate? If your flows have Dataverse at your disposal, one way is definitely Custom APIs.

The documentation link is this one https://learn.microsoft.com/en-us/power-apps/developer/data-platform/custom-api and at the beginning is written:

"...you and other developers can call in their code or from Power Automate."

Last Nordic Summit I had the pleasure to meet Amey Holden, she presented a session about Power Automate and one of the examples she demoed was about Choices, she needed to query the Metadata and her flow was working. However I instantly saw the opportunity to create something to help the specific task she faced. The result was a Custom API and she described it in this blog post:

Converting Dataverse Choice(s), (Multi-select) Option Sets, or Picklists in Power Automate

The Custom API I created (download here) simplified the flow, no need to query the Metadata writing the http query, no need to add special conditions, it's just a block doing the task but it's easy to use and does the work.

Why I am talking now about this? In the last months I created several Custom APIs designed to be used inside Power Automate flows, and yesterday I created another one that is public (RegexCustomAPIs) to execute Regex operations. (thanks Mark Christie for giving me the idea).

The Regex operations available are Match and Replace and they may fail sometimes due to the Regex pattern passed as input, but it's a starting point. As I said in the beginning there are different ways to implement something and you can find other ways to execute a Regex inside Power Automate, what I created is just another way and it may be useful to you.

So next time you are creating a flow and you think a Custom API can make the flow easier to interact and less cluttered, worth asking if it's doable.

October 18, 2022

Dataverse REST Builder available as Browser Extension

Today (18 October 2022) I did a session at WPC 2022 about Dataverse Web API and I announced that Dataverse REST Builder is now available as browser extension for Google Chrome and Microsoft Edge, here the links if you are interested:

Chrome Web Store

Microsoft Edge Add-ons

Big thanks to my friend Natraj Yegnaraman for suggesting me the idea, his "Level up for Dynamics 365/Power Apps" extension is well known to Dynamics 365/Power Apps users.

How it works Dataverse REST Builder Browser Extension? After you click on the extension icon you are prompted to enter the Environment URL in order to get the Access Token:

After you authenticate, Dataverse REST Builder is loaded in the same way as the XrmToolBox, Managed Solution and Dataverse DevTools versions.

How Dataverse REST Builder is able to obtain the Bearer Token in this scenario? It uses the same Application Client ID defined inside the Microsoft documentation in order to work with Postman: Set up a Postman environment

This Client ID allows two callback URLs, https://localhost and https://callbackurl, inside a browser extension we are able to obtain the URL return after the authentication process is completed (the token is one of the parameters), similar of what Postman does (maybe you don't remember but Postman started as a browser extension).

This solved the main problem, running Dataverse REST Builder inside an extension was indeed possible and doesn't require me to register an Azure application that maybe needs to be whitelisted by your organization, it uses a Microsoft Application Client ID.

The other problem was the use of eval() function to execute the generated code (keep in mind that for generating just the code eval() is not used). Browser extensions stop eval() due to security concerns, however with V3 specifications there is a possibility to load a page inside a sandbox (details here) allowing the use of eval(), so you can execute the generated code as well (Xrm.WebApi still works only with the Managed Solution version).

This is also the reason why there isn't a Firefox extension, Firefox extensions still use V2 specifications and there isn't a concept of sandbox. If in the future they allow this approach I think I can release DRB for Firefox too.

The Browser Extension version can be improved (I have already some ideas), let's see what the future brings.

During the next days I will update the other versions to match the version number (the Browser Extension currently shows 1.0.0.40) and publish the code to a separate GitHub repository.

I hope you find this version useful.

August 3, 2022

PCF Gallery and comments

If you browsed PCF Gallery you probably noticed that a comments section (hosted by Disqus) was present. From 15 July Disqus introduced ads inside their Basic Plan and now requires at least a Pro Plan (11 US$ / Month) to have an ad-free comments section.

I am evaluating alternatives but meanwhile I decided to remove the comments section from PCF Gallery.



Posted on Wednesday, August 03, 2022 | Categories:

February 14, 2022

Dataverse REST Builder and FetchXML

In the last version of DRB I just published (1.0.0.31) I added a new tab FetchXML for the Retrieve Single and Retrieve Multiple request types:

You can't create a 1 to 1 conversion between Web API and FetchXML because the two query languages are not compatible (meaning you can usually do more stuff with FetchXML) but it's possible to convert some queries (FetchXML Builder has the option to export to Web API for a while now).

To be honest adding the FetchXML tab to DRB was only an exercise for me (and the generated code can be improved), I don't think someone will use my tool to generate FetchXML when there is FetchXML Builder (I am also an avid user of the tool).

However it allowed me to refresh a bit the FetchXML syntax and more important dealing with two aspects inside the XrmToolBox version:
  • Sending information from the web page to the container hosting the WebView2 component
  • Use the integration between tools offered by the IMessageBusHost interface
The first can be done using chrome.webview.postMessage from the web page and listening to the event WebMessageReceived inside the container.

The second utilizes the OnOutgoingMessage event, my friend Jonas Rapp wrote a page with some examples: Integrate with FetchXML Builder

If you are curious on how these things work you can check the code from this repository.

Leveraging this code, DRB can send the FetchXML code to FetchXML Builder when is executed inside XrmToolBox:
hope it helps!


January 24, 2022

Relationship Columns added to DRB filter

I admit I recently "spammed" Dataverse REST Builder when I answer questions regarding Dataverse Web API, often an error is related to the code syntax or to the query (especially when dealing with navigation properties) so having a tool to generate the syntax is useful in my opinion.


The error was not difficult to find but the intention of the author was something similar to this query:
"retrieve contacts where the account number of the parent account is X"

This kind of query was not possible to build with Dataverse REST Builder before, the filter capabilities were limited to the columns of the main table, so if you were retrieving contacts you were limited to contact columns.

With the new version of DRB (1.0.0.26) it's possible to add "Relationship Columns" from the N:1 relationships, the next screenshot shows how it appears:


I highlighted the new button available inside the UI, relationship columns have also a different background color (in order to separate them from primary table columns).
The first dropdown is connected to the available N:1 relationships, the second one will list the columns of the related table.
Two important things:
  1. Not all the operators are available when dealing with relationship columns, for example the "Today" operator for DateTime columns (because the syntax looks for properties inside the main table), so I removed this kind of operators for relationship columns.
  2. Not all the relationships can be navigated and filtered, like the "Owner" one (but you can use the "Owning Team" or the "Owning User"), they appear inside the UI but an error appear when the query is executed.
To my understanding both points are limitations of the platform but maybe I am wrong, hope it helps.