Posts

Dynamics 365 portals

How to setup Dynamics 365 Portals?

In this screen cast video, I show you how to do Dynamics 365 Portals setup. I will cover the installation steps that are needed to take in the Dynamics 365 admin center to have portal up and running against Dynamics 365 online instance. 

This is the first part of the series of Dynamics 365 Portal videos that I’m going to do. In the future parts, I will be covering other aspects of the Dynamics 365 Portals for example the authentication and authorization, configuring the CRM data to be shown in the Portal, Portal development using Jscript and Portal UI tuning. So stay tuned for more.

Dynamics 365 unified service desk

How to setup Dynamics 365 Unified Service Desk and how it is used in Call Center scenarios?

In this screen cast video, I show you how to install a basic Dynamics 365 Unified Service Desk (USD) setup. Furthermore, I share a few nice-to-know things that I learned while I installed my own demo environment. Finally, a few words about setting up a Live Assist chat service and how that is integrated to D365 USD.

Check it out!

How to set Dynamics 365 related entity fields using quickview forms

Challenge

You have a form in Dynamics 365 in which you need to show field values from related entity. It is naturally possible to do this by making a request to the Dynamics server side API’s from client side code. There are a few possibilities to that but I will not focus on those in this blog post.

Instead of server side API requests, there is a simpler way to utilize Dynamics quickview forms and JavaScript. This way you don’t need to do any API requests in code.

The scenario could be such where you have for example a Dynamics 365 Case entity form, and you’d need to show the related Product and Account entity values in lookup fields. These Product and Account lookup fields would get loaded when a Customer Asset entity lookup field value gets changed. This would mean that when user selects a customer asset for a case, then product and customer information would get loaded automatically to the form without user’s having to select them manually from individual lookup fields. By just using quickview form, the fields in it are read-only. So that’s why you’d need to have separate Account and Product lookup fields in Case entity form into which you set the values through JavaScript from the quickview form.

Solution

Below are steps how to do this:

  1. Create one quickview form to the Customer Asset entity. Add two Customer Asset entity fields into this quickview form:
    1. Account (lookup)
    2. Product (lookup)
  2. Insert that quickview form to the Case entity form and set the quickview form properties so that the name of the form is “CustomerAssetProductCustomer” and then set the data source properties of that quickview form according to your field names in the CRM form. You can set the quickview form not be visible by default.
  3. Add a small piece of JavaScript code to the OnChange event of the Customer Asset lookup field on the Case entity form. This JavaScript will fetch the Account and Product values from quickview form and set those values to the corresponding lookup fields on the Case form. While I was testing this scenario, I noticed that without adding a small delay to the JavaScript function processing, the quickview form was not loaded yet when the JavaScript got processed and that’s why it always set incorrect Account and Product values to the lookup fields. Those were the Account and Product lookup values from the previously selected Customer Asset. By adding a half a second delay, the solution started working properly.

function populateFieldsFromCustomerAssetRecord()

{

if(Xrm.Page.getAttribute(“yourcustomerassetlookupfield”).getValue())

{

setTimeout(populateFields, 500);

}

}

 

function populateFields()

{

var quickViewControl = Xrm.Page.ui.quickForms.get(“CustomerAssetProductCustomer”);

if (quickViewControl)

{

if(quickViewControl.isLoaded())

{

var product = quickViewControl.getControl(“msdyn_product”).getAttribute().getValue();

var account = quickViewControl.getControl(“msdyn_account”).getAttribute().getValue();

Xrm.Page.getAttribute(“productid”).setValue(product);

Xrm.Page.getAttribute(“customerid”).setValue(account);

}

}

}


At Cloudriven, we help organizations in every step of the Dynamics 365 projects.  If you require any help just contact us. We are here for you !

Contact Form

Want to know more about our products or services? Fill out the form and we'll be in touch as soon as possible.

Multi-entity data migration from Dynamics 365

Recently I ran into a task where I needed to migrate data from Dynamics 365 into SQL Azure DB. Piece of cake, I will just use the SSIS enhanced with the KingswaySoft SSIS toolkit for Dynamics. Well, there was one a bit of a challenge which is due to Dynamics data model for lead entity. So, let me specify the scenario in a bit more detail.

In high level, this scenario was such that leads stored in Dynamics 365 should be migrated over to a custom DB hosted in SQL Azure service. However, due to the way this organization had used Dynamics, there were three types of leads in CRM when considering the way how leads were linked to customer entities:

  •  Leads which were not linked to customer entities at all
  •  Leads which were linked directly to account entity
  • Leads which were linked to contact (and then contacts had parent customer as account)

In the SQL Azure DB, the lead table model was such that only company information or CRM account GUID can be saved. So, there was no place to save the contact information of the lead. So somehow in the SSIS package, I would need to fetch the account information to be stored to SQL for the third type of leads in the above list. It is not directly available in the SSIS for mapping when lead entity records are fetched from CRM.

Based on this information I started to plan the SSIS migration package model. Should there be three separate packages, one for each scenario mentioned above or one package in which there would be logic for handling the above three scenarios. For you SSIS gurus out there, this would probably be a no-brainer but for me, it took a bit of an effort to clarify this situation. The way I ended up handling this was within one SSIS package containing conditional split control and merge join control handling the most challenging phase:

So here is the data flow how it goes from top to down:

  1.  KingswaySoft Dynamics CRM source component queries leads from Dynamics 365
  2. Within the conditional split control, I use the lead.customeridtype attribute to check the type of the customer saved to each lead:
  3. Lead data is sent to three different data flow paths depending from the customeridtype information.
  4. The easiest ones are the scenarios where lead does not have any customer entity or lead is linked to account entity. From these two, I just send the data over to OLE DB destination control where I map the CRM lead attributes to proper SQL Azure DB fields. For the leads not linked to any customer, the lead.companyname field value is used for the customer info in SQL Azure. For the leads linked to account, the account.name is used.
  5. But then the challenging part: leads which are linked to contact, I should somehow fetch the contact’s parent account but it is not directly available in the lead.customerid attribute when that contains a contact. So what I ended up doing was that I used the SSIS merge join control in which I did a join between the lead.customerid (GUID) and contactid (GUID) and then fetched the contact.parentcustomerid attribute and sent it as an output to the OLE DB destination control. Naturally I needed to query all the CRM contacts and for that I used again the KingswaySoft Dynamics CRM source control. Here are the details of the join control logic:

The rest was just the normal day in the office and mapping the proper fields, pressing the famous Ctrl + F5, fine tuning my chair to proper position, having a sip of griin dii with mind (honey on the side) and watching the data flowing as nicely as crystal clear water in the Näätämö river.

So, with these words, I wish all of you sunny and peaceful moments during the summer. Have fun and live strong!

Web Api Queries

How to make Dynamics 365 Web API queries using OAuth?

Related to my previous blog post, I thought that I would write a new post about Dynamics 365 (on-premise) Web API, ADFS 3.0 and OAuth. This same applies for Dynamics 365 online as well because the Web API is designed to be used by OAuth when Dynamics 365 is either online or configured to IFD-mode with one exception: in this scenario described in my blog post, I use ADFS 3.0 installed on one of my local Windows Server 2012 R2 boxes. Naturally in online scenario, Azure AD would be used for authorization. This actually makes quite significant difference as per my findings. It seems that ADFS 3.0 poses quite a few restrictions in terms of OAuth usage.

The scenario this time is such that I needed to simulate an external application making a request against Dynamics 365 Web API. Initially I thought of doing this whole simulation using the SOAPUI tool but I was not able to get it working. It seems that at least the SOAPUI tool for obtaining the OAuth access token always sets the response_type parameter to value “token” instead of “code” which is needed in my case. So, because of that, I ended up doing this simulation in the following sequence of steps and tools:

  1. Register client application to ADFS using PowerShell
  2. Make an HTTP GET request using browser against the proper OAuth endpoint in ADFS to obtain the OAuth authorization code
  3. After getting the authorization code from the second step, do HTTP POST request against another OAuth endpoint to obtain the OAuth access token. For this step, I used the Fiddler tool.
  4. Use the OAuth access token from step 3 to make the actual Dynamics 365 Web API request. For this step, I used SOAPUI tool.

Below these steps are described in more detail.

Register client application

I pushed my bravery to the limits and started PowerShell in admin mode. The command line entry I used was as following:

Add-AdfsClient -ClientId 017BEFF0-603E-40E7-B19B-94834983CFEE -Name TestOauth2_2 -RedirectUri https://sts.domain.com/adfs/ls/IdpInitiatedsignon.aspx

ClientId: this can be pretty much any GUID which is unique within this ADFS instance. In Azure AD, the client application registration assigns the ClientId automatically
RedirectUri: this is the one which is used to authenticate the user in ADFS

Obtain OAuth authorization code

So, I fired my good old friend and also started IE and typed the following to the address bar:

https://sts.domain.com/adfs/oauth2/authorize?response_type=code&client_id=017BEFF0-603E-40E7-B19B-94834983CFEE&redirect_uri=https%3A%2F%2Fsts.domain.com%2Fadfs%2Fls%2FIdpInitiatedsignon.aspx&resource=https%3A%2F%2Fcrmtenant.domain.com

response_type: with this you specify that you want the authorization code as response
client_id: this must be the same as in step 1 above
redirect_uri: again, the same as in step 1 above
resource: the server or service that the client wants to access. In this case, that is the Dynamics 365 CRM tenant URL

It must be noted here that the URL values must be URL encoded in this request.

When hitting the Enter key after adding the above to the browser address bar, you should see some type of an authentication window. After entering proper credentials, you will see success message in the browser and the browser address bar will contain the authorization code which you need in the next step.

Obtain OAuth access token

There are probably other tools and truths out there than Fiddler but I haven’t found one. So, because of that, I decided to use Fiddler. It has the handy HTTP request composer which I used to make the HTTP POST request against the proper ADFS OAuth endpoint. The request in raw format looks as following:

POST https://sts.domain.com/adfs/oauth2/token/ HTTP/1.1

User-Agent: Fiddler

Content-Type: application/x-www-form-urlencoded

Host: sts.domain.com

Content-Length: 646

grant_type=authorization_code&client_id=017BEFF0-603E-40E7-B19B-94834983CFEE&code= 6ZRcIsJYk5UAmJg&resource=https%3A%2F%2Fcrmtenant.domain.com%2Fapi%2Fdata%2Fv8.1%2F&redirect_uri=https%3A%2F%2Fsts.domain.com%2Fadfs%2Fls%2FIdpInitiatedsignon.aspx

grant_type: the OAuth2 grant type (flow) which is used. This is now the part which I mentioned on the top part of this blog post. It turns out that ADFS 3.0 has several restrictions due to which not all the OAuth2 grant types are supported. One of the underlying reasons to that is that ADFS 3.0 does not support client secrets which are used in several grant types. As far as I know, this is changed in ADFS v. 2016 but then again, Dynamics 365 on-premise does not support ADFS v. 2016. That does not mean that Dynamics 365 on-premise would not work with ADFS v. 2016 but officially it is not supported. So, long story short, I will use here the one grant type which ADFS 3.0 supports and that is called authorization code. More details about OAuth2 grant types can be found for example here: https://alexbilbie.com/guide-to-oauth-2-grants/
client_id: again, the same which is used in earlier steps
code: this is the authorization code obtained in the previous step
resource: the CRM tenant’s Web API URL
redirect_uri: again, the same as above

After successful execution of this HTTP POST request, Fiddler shows the access token which is returned in the JSON format.

Next I fully utilized the famous copy&paste methodology and copied the access token from Fiddler response screen and pasted that to the SOAPUI authentication box.

The only thing left to do was to compose the Dynamics 365 Web API request in SOAPUI as shown below. The results were returned nicely:

Results

Summary

Even though pretty much everything is going to cloud nowadays, I decided to write this blog post related to the on-premise scenario. The reasoning for that is that…hmmm…because it seems that doing things on-premise makes things more interesting. In Azure, there are more or less UI wrappers for everything and it is a bit challenging to see what’s happening under the hood. As we have a saying in Riihimäki jungles: #eilistäpäivää