Category Archive Uncategorised

ByRob Peledie

Query Dynamics 365 / CDS Data With SQL

So fairly recently Microsoft announced the ability (in preview) to query CDs data with SQL – as opposed to Fetchxml as we have been used to with online.

I will write up a fuller discussion of this, once I have had a proper play, but there were some issues with setting this up, so I put together a short (ish) video to walk through the steps.

ByRob Peledie

Consuming an Open API and JSON in Power Apps – 101

It’s been a while since I wrote anything too technical, and I’ve had a chance during this lockdown to brush up on some stuff I haven’t really played with in Power Apps,  so  thought I would look at something a little different….. connecting and consuming an Open API, and consuming the results in a Power App. 

Before I get started, there is also a video to go with this article

 There are plenty of open API’s you could use to have a play around, but I decided to use the one from CoinGecko, which gives lots of options for real time Cryptocurrency prices. You don’t need to sign up to it, and there’s no authentication required, which makes life easier if this is your first venture.

If you navigate to the CoinGecko API site, you’ll see the complete list of options, and get a chance to test out your requests right there. For example the first, and most basic is to ping the api.

So for the example we’re going to build, let’s keep it nice and simple. A Power App that retrieves the current prices for Bitcoin in 3 currencies, then allows you to choose your preferred currency, your holding, and show your live value.

Firstly lets create the Flow that gets the data from the CoinGecko API. Go to flow.microsoft.com and log in. Once logged in, go to your flows and click New –> Instant – from blank

You’ll then get the opportunity to choose your trigger, and in this case we want to choose PowerApps, as an action in our PowerApp will call the flow and API

Once you’ve clicked create, your flow will open, and the PowerApps trigger will be shown as the first step

Before we go any further, lets just step through the process that we’re going to do. This is the finished flow

So if we break it down in to simple steps……. The Power App calls the flow. this then uses the HTTP action to call the API. The JSON results are Parsed, and the Responses captured.

This then gives us the resulting data to be consumed in the Power App.

So let’s break it down. Firstly that HTTP Step. If I open up that step this is what you’ll see

So the Method we’re going to use here is GET – because we’re getting data! Seriously though, if you want to know more about these methods, then check out this.

So the URI is where we form our request, and in this case it’s a really simple request for the Price of Bitcoin in 3 currencies – USD, GBP and EUR.

Since theres no Authentication for this API, we can easily see if this request works by posting that URI in a web browser

So the results you see there are in a JSON format. We now need to Parse them, and break them down in to their parts so we can consume and use them in a readable format.

Here we add the Parse JSON action.

So firstly you’ll see that we want to pick up the Body as Content – that’s the payload or data we are retrieving. The Schema may seem a little daunting, but there’s a neat little trick here……. “Generate from sample”

In this, we can just paste in the returned data that we got before in our test with the URL, and the flow will just generate the schema for you!

Finally we just add the Response action, and you’ll see it’s almost identical to the Parse – just with the addition of the status code of 200 which effectively means OK. This then allows the response to be consumed in your Power App

So, that should be your flow created. Don’t forget to name it and save it. Next let’s create a simple Power App and consume that data. 

Go to make.powerapps.com and create a new Canvas app from blank. The first thing we’ll do is add a button – for this simple example the button is going to call the flow which in turn calls the CoinGecko api. I’ve just renamed mine to “Update Prices” .

Now there’s a few things we want to do in order to grab those prices. In the formula box I have added the following

ClearCollect(getrates,GetCoinGecko.Run())

I’m not going to go into all the details of this but essentially we are creating a collection, calling it “getrates” and the data that feeding it is coming via the flow we previously created (Mine is named “GetCoinGecko”

If you want to check your flow is working, just check your collection

I have also added a few labels….. 3 to identify the currency, and 3 to hold the data we pull back

so far then we have a mechanism for getting the data from the API via flow, and triggered by the button. it’s being stored in the collection. We now have to show it in the label fields.

In the formula for the label for GBP I have added the following

First(getrates).bitcoin.gbp

This formula calls the first record in the collection and in this case the GBP value and displays it

Repeat for the USD and EUR data, and there you have it!

Have a play…… why not add a drop down and option to put your holding to show your value (I wish I had 100!)

ByRob Peledie

Common Data Model Vs Common Data Service

I thought I would put together a short explanation of Microsoft’s Common Data X conventions, and specifically what the meaning and differences are between CDM and CDS.

One of my drivers for this is that I didn’t fully understand it myself, or at least I find it difficult to articulate the definitions, and there’s surprisingly little about the connection between the terms….

So let’s start off with the “official” definitions of both

Common Data Model


The Common Data Model is a declarative specification, and definition of standard entities that represent commonly used concepts and activities across business and productivity applications, and is being extended to observational and analytical data as well. CDM provides well-defined, modular, and extensible business entities such as Account, Business Unit, Case, Contact, Lead, Opportunity, and Product, as well as interactions with vendors, workers, and customers, such as activities and service level agreements. Anyone can build on and extend CDM definitions to capture additional business-specific ideas.

Common Data Service


Common Data Service lets you securely store and manage data that’s used by business applications. Data within Common Data Service is stored within a set of entities. An entity is a set of records used to store data, similar to how a table stores data within a database. Common Data Service includes a base set of standard entities that cover typical scenarios, but you can also create custom entities specific to your organization and populate them with data using Power Query. App makers can then use PowerApps to build rich applications using this data.

There we go…… thats clear Isn’t it?………….

Still doesn’t feel like a clear explanation, so let’s try again…..

I think the clue to understanding this is in the last word of both expressions – Model and Service

A Model provides a framework, or architecture that standardises something….. so for example you might use the expression 
“the project became a model for other schemes” to infer that other projects will be based on this. 

So in this context, the Common Data Model is a standardisation of data concepts.

On the Microsoft GitHub page for CDM, you can find the poster below, which I think really explains the concept


The Common Data Model standard defines a common language for business entities covering, over time, the full range of business processes across sales, services, marketing, operations, finance, talent, and commerce and for the Customer, People, and Product entities at the core of a company’s business processes. The goal of CDM is to enable data and application interoperability spanning multiple channels, service implementations, and vendors. CDM provides self-describing data (structurally and semantically), enabling applications to easily read and understand the data.

I think that starts to focus our understanding a little better.

Now, if you really want to dig in to the Schema, and get a good understanding, then you can use the CDM Entity Navigator to drill in to it

So…….. How does CDS fit in to this? Well as with CDM, let’s look at the last word – Service.

If we view the CDM as the standard of entity schema, then the CDS is the mechanism for enabling you to build that data.

To put its simply……if you were to spin up a new environment of CDS here, then it would build it based on the CDM schema, and supply you with some of those standard Entities and relationships defined in the CDM Schema, but the actual data etc would be provisioned or managed by the Service…CDS.

Hopefully the above has helped to explain the difference between CDM and CDS and how they fit in to the landscape.

ByRob Peledie

Dynamics 365 User Access Report with FetchXml and Power BI

Ok, so that’s not the snappiest of titles, but essentially it’s my lazy way of covering a couple of topics in one blog post:

  1. Need to report on Licensed Users and When they Last Accessed Dynamics
  2. Showing that in a Power BI Report using FetchXML

It’s worth noting at this point, how fantastic the Dynamics 365, and generally the Microsoft community is. Most of what I did has already been done and blogged about for free. I’ve tried to reference everyone who’s blog posts helped me.

So the first thing I needed was some fetch to give me the last logged in (or Access in Audit entity terms) for users.  I got the following from www.mscrmsolution.com but could have hand crafted in FetchXML Builder in XrmToolbox

<fetch aggregate='true' >
    <entity name='audit' >
    <attribute name='createdon' alias='LastAccessTime' aggregate='max' />
    <filter>
        <condition attribute='operation' operator='eq' value='4' />
        <condition entityname='su' attribute='isdisabled' operator='eq' value='0' />
    </filter>
    <link-entity name='systemuser' from='systemuserid' to='objectid' alias='su' >
        <attribute name='systemuserid' alias='SystemUserId' groupby='true' />
        <attribute name='domainname' alias='DomainName' groupby='true' />
        <attribute name='fullname' alias='FullName' groupby='true' />
    </link-entity>
    </entity>
    </fetch>

Couple of things worth noting here. Operation = 4 which is the Access record in the Audit (as opposed to Update, Create etc)

So at this point, I had the first piece done, as all I initially wanted was a way to see how long it was since users logged in. To get a quick view I just pasted the results in Excel and used a formula to calculate the days.

What I actually wanted to do was create a Power BI report that would connect to Dynamics, and use this FetchXml dynamically.

Ulrik Carlsson (CRMChartGuy) has a great post on this, and all credit to him for the following. (You may want to read his post in entirety, as I have summarized some bits)

Firstly open up your Power BI desktop, and choose Get Data –> Web

When this opens choose the Advanced option

So there a few steps here to get the connection working:

  1. The Service Root URL that you would otherwise use in Power BI https://MYCRMORG.api.crm.dynamics.com/api/data/v9.1/
  2. The PLURAL name of the entity schemaname follow by ?fetchXml=
    Example: audits?fetchXml=
  3. The FetchXML above, encoded as a URL (You can get this encoded at 
    https://www.freeformatter.com/url-encoder.html )
  4. Type in “Prefer” – it is not option you can select
  5. Exactly type: odata.include-annotations=”OData.Community.Display.V1.FormattedValue” (Important that you type in the Quote marks to avoid formatting issues)

Click OK

Open up the Query Editor

Click on “To Table” in the convert area, then click on the expand button (two arrows pointing away from each other)

And there you have it…..A live power BI report showing users access.

I’m not going to go in to how to “Pretty” the report up, I’ll leave that to you! 

The process above would be the same for any FetchXml query, and if you don’t need to hand craft the Fetch, then you can start with an Advanced Find, and export it out.

ByRob Peledie

Learn More With….. Microsoft Learn!

I’m pretty well Microsoft through and through. However a few years ago I had a detour in to the depths of the realm know as Salesforce (It’s fine, I’m ok now)…..

Seriously though, There are a few things that Salesforce do quite well, and one of the things I thought they did well was Trailhead. Trailhead was an online, free learning platform which has a gamification feel about it, and allowed users to acquire the skills needed to be anything from a good user to a Salesforce Dev.

I always thought it was a great concept and executed really well, and something Microsoft could take note of.

Well…….

A few years forward and we have Microsoft Learn!

Now I have to say, the look and feel is very similar to Trailhead, but that’s not a bad thing, after all, Salesforce did it well.

So what can you learn? Well there’s lots of Learning paths you can take including Azure, Dynamics, Power BI and more, but as I’m well and truly entrenched in the Powerapps/Dynamics space, this is the Path I chose, and there really is some great modules.

The modules are so well put together, and really informative. If you’re going through one of the Azure modules, you even get a Sandbox instance right in the browser to work through the lesson

So give it a go…. Learn something new today.

ByRob Peledie

Integration With Dynamics 365 CE And Companies House API – Azure Logic App

Introduction and Background

Before I start the overview of this process, I think it’s worth noting that over the last few years, the options for integration, and to be fair, any sort of extension and development in Dynamics 365 has/is shifting from being a C# development only domain, or at least a coding exercise, to giving us the option to do this via an extensive toolset – Azure, Office 365 to mention a few.

So for this example – Integration of data from an external data source – I will be going through the process in what I consider the easiest and lowest overhead in terms of coding. Yes there are a number of different options for achieving this, and coding something is one of those, but my favourite expression at the moment is “Don’t crack a walnut with a sledgehammer”.

So a couple of assumptions in terms of your setup. You’ll need:

  • An Azure Account
  • Dynamics 365 Instance
  • A perfunctory understanding of API’s and JSON

The use case for this integration is to call out to the Companies House API and pull back some company data in to Dynamics 365. There is a lot of information stored there about Ltd Companies in the UK, and could be really useful.

The Companies House API is still in Beta……to be fair it’s been Beta for a couple of years, but seems fairly stable, and there is a wealth of documentation and a forum. You will need to create an account on the site in order to access and use the API’s.

You can do this, and access the documentation and Forum here: https://developer.companieshouse.gov.uk/api/docs/

The process is going to be something like this:

So one of the first things you’ll need to do once you have created an account on the Companies House website is register an application. This process then assigns you an API Key used for authentication. There a few options for type of API, and restriction of IP addresses etc, but for this example we’ll go for a REST API. Once this is completed, you’ll get an API key.

The next step is to setup you Azure Logic App. I’ll skip the bits around setting up Resource Groups etc. CLick on Create Resource, Integration then Logic App:

Add the details:

Once this is all done, you can start to build out your logic. When your resource is ready you can navigate to it. If you’re familiar with Microsoft Flow, you might recognise some similarities.

There’s a reason why Logic Apps and Flow look similar. Flow is built on top of Logic Apps. You can read more details about the similarities and differences here

Click on the Blank Logic App and add the trigger for Dynamics 365. In this example I am going to trigger the integration when a new Account is created, but it could also be when a record is updated and so on.

So the next stage is to use the HTTP connector set it up to point to the Companies House API. For authentication use Raw, and you’ll only need the value (no need for username and password)

You’ll also notice that the URI is appended with a Dynamics Field, in this case the Account Number field which needs to store the Company number, as this is the format for searching for the company. Obviously that means you need to know the company number!

Once the HTTP is set, you need to Parse the resulting JSON. For this you need the Parse JSON Operation. Here you will set the Schema for the returning JSON.

For the GET Company Schema use the following:

{
    "properties": {
        "accounts": {
            "properties": {
                "accounting_reference_date": {
                    "properties": {
                        "day": {
                            "type": "string"
                        },
                        "month": {
                            "type": "string"
                        }
                    },
                    "type": "object"
                },
                "last_accounts": {
                    "properties": {
                        "made_up_to": {
                            "type": "string"
                        },
                        "period_end_on": {
                            "type": "string"
                        },
                        "period_start_on": {
                            "type": "string"
                        },
                        "type": {
                            "type": "string"
                        }
                    },
                    "type": "object"
                },
                "next_accounts": {
                    "properties": {
                        "due_on": {
                            "type": "string"
                        },
                        "overdue": {
                            "type": "boolean"
                        },
                        "period_end_on": {
                            "type": "string"
                        },
                        "period_start_on": {
                            "type": "string"
                        }
                    },
                    "type": "object"
                },
                "next_due": {
                    "type": "string"
                },
                "next_made_up_to": {
                    "type": "string"
                },
                "overdue": {
                    "type": "boolean"
                }
            },
            "type": "object"
        },
        "can_file": {
            "type": "boolean"
        },
        "company_name": {
            "type": "string"
        },
        "company_number": {
            "type": "string"
        },
        "company_status": {
            "type": "string"
        },
        "confirmation_statement": {
            "properties": {
                "last_made_up_to": {
                    "type": "string"
                },
                "next_due": {
                    "type": "string"
                },
                "next_made_up_to": {
                    "type": "string"
                },
                "overdue": {
                    "type": "boolean"
                }
            },
            "type": "object"
        },
        "date_of_creation": {
            "type": "string"
        },
        "etag": {
            "type": "string"
        },
        "has_been_liquidated": {
            "type": "boolean"
        },
        "has_charges": {
            "type": "boolean"
        },
        "has_insolvency_history": {
            "type": "boolean"
        },
        "jurisdiction": {
            "type": "string"
        },
        "last_full_members_list_date": {
            "type": "string"
        },
        "links": {
            "properties": {
                "filing_history": {
                    "type": "string"
                },
                "officers": {
                    "type": "string"
                },
                "persons_with_significant_control": {
                    "type": "string"
                },
                "self": {
                    "type": "string"
                }
            },
            "type": "object"
        },
        "registered_office_address": {
            "properties": {
                "address_line_1": {
                    "type": "string"
                },
                "address_line_2": {
                    "type": "string"
                },
                "locality": {
                    "type": "string"
                },
                "postal_code": {
                    "type": "string"
                }
            },
            "type": "object"
        },
        "registered_office_is_in_dispute": {
            "type": "boolean"
        },
        "sic_codes": {
            "items": {
                "type": "string"
            },
            "type": "array"
        },
        "status": {
            "type": "string"
        },
        "type": {
            "type": "string"
        },
        "undeliverable_registered_office_address": {
            "type": "boolean"
        }
    },
    "type": "object"
}

If all goes well, when you add the final Operation – Update Record – You should see all the returned data options:

Obviously the fields need to be available on the Dynamics 365 Accounts form.

Then….. Time to test!

Add a new Account in Dynamics and include the Company Number:

Once you save the record, the call is made to the Companies House APi, and returns any details it finds:

So this is very much a click and configure integration, but I think a nice use of the Logic App solution, and an easy integration with REST API’s.

ByRob Peledie

Show Image if field value equals…

Before I start, a massive shout out to Charles Osei .As part of the TDG team, we had a discussion, and his solution totally solved the requirement I had. Also another great example of how a collaborative group can work.

Had a requirement recently to show something a little more visual on a record form if a tick box was chosen…… something that would immediately show the user the status or conditions on a record.
In this example, were going to show Icons for Key Accounts and Sensitive Accounts at the top of the form if the corresponding fields are ticked.

Firstly, find your icons. For me I decided on a key for the Key Accounts, and an exclamation for the sensitive accounts, but I also added some text:

These need to be added to Dynamics as Web Resources.

Next add a section on your account form (I added a 3 column one) and add the two new icon web resources to it. Make sure you untick the box “Visible by Default” for each web resource.

You also need to add your radio buttons on the form – in my case one for Key Account and One for Sensitive.

Once these are all on, save and publish.

Next create a new web resource of type Script (JScript).

//Shows/hides keyaccount img webresouce based on a tickbox two option field

function alertpic (executionContext) 
{
    var formContext = executionContext.getFormContext();
	
    var keyaccount = formContext.getAttribute("uob_keyaccount").getValue();
	
    if (keyaccount === true) {
        formContext.getControl("WebResource_keyacc").setVisible(true);
    }
    else {
        formContext.getControl("WebResource_keyacc").setVisible(false);
    }
}

//Shows/hides sensacc img webresouce based on a tickbox two option field

function sensalert (executionContext) 
{
    var formContext = executionContext.getFormContext();
	
    var sensacc = formContext.getAttribute("uob_sensitiveaccount").getValue();
	
    if (sensacc === true) {
        formContext.getControl("WebResource_sensacc").setVisible(true);
    }
    else {
        formContext.getControl("WebResource_sensacc").setVisible(false);
    }
}

So the first variable sets the context (this will be passed as a parameter when you call the function).

The second variable is the tick box field.

Then depending on the value (True/False) it shows or hides the Icon.

Don’t forget to call the function from both Onload and Onchange (On the field)

The result:

ByRob Peledie

Using SSIS for Bulk Data Deletion in Dynamics 365

I had a situation recently that an instance (not one I managed I hasten to add!) had started to grow in storage, to the point that it was at nearly 200% capacity. I was asked to look at it. Turned out that Plugin Tracing had been switched on, and a plugin was throwing errors. Unfortunately there were now so many records in the Log file that it wouldn’t open (Usual generic unhelpful SQL Error).

Taking a quick look at organisation insights confirmed that this was consuming nearly 60gb of storage, and a quick record count (Using Record Counter in XrmToolBox) indication there was approaching 10,000,000 records.

Normally I would use the standard Bulk Delete option, however for a couple of reasons I didn’t think this was a viable option:

  1. It would take too long
  2. It kept falling over after 1000 deletes (probably due to the number of records, but I didn’t get to the bottom of it)

In the end I decided to go back to trusty old SSIS, and (again) the lovely KingswaySoft solution for Dynamics 365.

The steps are essentially:

  1. Create a CRM connection
  2. Retrieve what you want to delete (Using Dynamics Data Source Component)
  3. Delete

If you’ve used the SSIS Toolbox before, then you’ll know how to setup a connection.

To retrieve the data, I decided to go with FetchXML as I wanted to specify a date range, so the following was added to the Dynamics Source Data Flow:

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="plugintracelog">
    <attribute name="plugintracelogid" />
    <filter type="and">
      <condition attribute="createdon" operator="on-or-before" value="2018-11-20" />
    </filter>
  </entity>
</fetch>

So the Fetch above would pull back any log files created before 20/11/2018.

Once this is done, connect the Source to the destination, and open up the Destination Module

Add your connection in Connection Manager.
In Action, choose Delete.
In Destination Entity, choose the Plugintracelog entity

I enabled multithread, and chose 32 threads.

Once that is all done, Save, Build and Run.

By365Knowledge

Check Back Soon!

Thanks for checking out our new site!

Check back soon to see our updated blog posts!

I have decided to start again with the posts, as some of the old posts were for previous versions of Dynamics CRM/365 and not relevant.

 

Thanks,

365Knowledge Team