TIL: Do not use ExecuteMultipleRequest in Dynamics 365 Plugins/CWA

Today I learned a new thing about ExecuteMultipleRequest within Dynamics 365 plugins and/or custom workflow activities. The following article: https://docs.microsoft.com/en-us/dynamics365/customer-engagement/guidance/server/avoid-batch-requests-plugin suggested that we should avoid any usage of Batch Request in server-side codes.

Background story

My colleague reported that when he is using ExecuteMultipleRequest within the plugin, it is throwing an SQL Timeout error, while he changed it to the single request model, the plugin runs fine.

In the past, I always consider it as the go-to model, when I need to perform multiple requests like creating/updating multiple records. And I used to use this ExecuteMultipleRequest to log exceptions to Dynamics 365 records in the past (according to this MSDN article: https://msdn.microsoft.com/en-au/library/jj863631.aspx).

msdn.png

The Truth

Now I learned that ExecuteMultipleRequest is not designed to be used within server-side codes such as Plugins and CWA. Reason:

guidance.png

The design of batch pattern is to reduce the lags due to the network latency (the application is performing HTTP request to the Dynamics 365 API). Where having the code running on the “same” network is defeating the purpose of the design.

Another reason:

reason_2.png

There is a throttling limit on the batch pattern, by using the batch request in plugins, it is unnecessarily reducing the available “slot” for the concurrent bulk request to run.

Final Remarks:

remarks.png

HTH!

Advertisements

Microsoft Flow: Creating Dynamics 365 Scheduled Report – Low Code Approach

Recently I’ve been exploring the power of Microsoft Business Application Platform. One of the most common requirements that I think we can solve in the Low Code Approach is the scheduled report.

For this example, I’m going to use this example user story to describe the scheduled report requirement: As a sales manager, I want to receive a daily digest of the new opportunities, so that I have the visibility of new opportunities in my organisation.

Before thinking about the solution, we might need to look at the platform that we are working on right now. Microsoft Business Application Platform, where Dynamics 365 plays an integral part in it, comes with Microsoft Flow that has numerous connectors available. This opens up a very broad capability in building the business workflow.

So, without further ado, here is my “Low-Code” approach generating the scheduled report (if you want the more complex one using SSRS, Bob Guidinger, has the solution here).

The first step in the Flow is to set the schedule:

Recurrence_Step.png

Next, we need to construct the filter for the Get List of Records from Dynamics 365 oData query, to build it I’m using Jason Lattimer’s CRM Rest Builder 

Filter_Builder.png

Once the query is generated, copy the filter as the base to be put in Flow

Filter-Copy.png

To get the created on = yesterday, we could use the Flow Built-In Formula/Expression:

List_Records.png

You also could try the query whether it’s successful or not by running the Test process on Flow

Test_Result.png

This will need a bit of Dev knowledge to understand the JSON output of the list records, but we can confirm that it is returning the list correctly or not

Testing_on_the_List_Records.png

Once confirmed, then we can construct the HTML table for the email body using the Create HTML Table action on Flow and to some field mapping.

Create_HTML_Table.png

And then send the email action:

Send_email_v1.png

Make sure that to select the Is HTML to Yes, otherwise, the HTML tags will be rendered as literal text

Is_HTML.png

This will produce a very basic email, that tick the box of the requirement, but not pretty

V1_Email.png

So, to make it more appealing, I’m adding the “Low-Code” CSS to style the table using the compose action before sending the file

CSS_Prettify.png

Attribution: CSS is a copy from w3schools: https://www.w3schools.com/css/tryit.asp?filename=trycss_table_fancy

Now with the CSS, the table is looking more appealing

CSS_Applied.png

Another ask, can we also have this table/report as HTML. The answer is Yes. Microsoft Flow has connectors to convert HTML to PDF via 3rd party service such as Muhimbi PDF or Plumsail Documents (which requires subscription/license)

SaveToPDF.png

The quick and dirty option to save to PDF is via OneDrive actions, by creating the HTML and Convert the file to PDF.

OneDrive_Option.png

Typically you could create a folder in OneDrive to store the report temporarily and do periodic clean-up.

Then this can be added to the email as an attachment:

Add_Email_Attachment.png

Which produces the email with the PDF attachment:

Email_With_Attachment.png

And the PDF file opened with PDF reader:

Open_in_PDF.png

My Final Flow is something like this:

Final_Flow.png

 

HTH! Happy Flow-ing!

Gotcha: Don’t Use Nested Security Group

Some time ago, I published a blog post about a tip about using Security Group in Dynamics 365 Online Deployment. And I’ve got a feedback from one of my colleagues where the security group is not allocating the users properly. So, I investigated the behaviour with my colleague and found an interesting setup.

TL;DR; version: Do not use Nested Security Group, as Dynamics 365 would not honour it.

The Long Version

So, I noticed in my colleague’s environment they have set up nested security group. To explain, I’m going to “replicate” the scenario in my environment.

I have set up my sandbox environment to use “Dynamics Sandbox” security group as follow:

Sandbox Security Group.png

And the Dynamics Sandbox security group has membership as below:

Parent_Group.png

“Dynamics Test” there is the child group that I have setup with the following members:

Child Group.png

Normally, When I have a nested group like that. I would expect Test User 2 – 5 will also be included in the Enabled Users list. However, this is the result:

Actual.png

To ensure the rest of the users are synced to Dynamics 365 the group must be flattened:

Flatten_Model.png

Then, you’ll be able to see them in Dynamics 365.

Actual-flatten.png

I have confirmed the behaviour with the Microsoft support, that nested group is not supported at this moment.

Hope this helps!

Dynamics 365 Online Deployment Tips: Set Your Security Group!

The feature of Security Group in the Dynamics 365 Online deployment has been there for a while. However, I often find either people do not understand it correctly or this feature is not being considered as an important “checklist item” for a smooth deployment. So, in this post I will share some reasons on why we need to plan setting up the security group.

To support the example, I’ve set up the following scenario:

In my instance I have 4 users:

Users List.png

And 2 Security Groups for Production and Sandbox

Security Group.png

Where in Production, everyone is the member of the group:

Prod Membership.png

While in Sandbox, Test User 3 should not access the environment

Sandbox Membership.png

Now, let’s begin with the reasons why we need to implement Security Group.

#1 For Authorisation Purpose

In typical Dynamics 365 implementation, there will be multiple instances, such as DEV, TEST, UAT and PROD. When the instance has been associated with the security group, only users that are member of the security group can access the environment. The traditional way to restrict access by not assigning the security role to the users is still viable, but this leads to the reason #2 below.

The difference on the error message would be as follow:

  • Not assigned with the security role

NoSecurityRole.png

  • Not part of the Security Group

Not Part of Group.png

#2 To Keep Users in the Instance Clean

On top of the first point, to prevent the users to access the environment, having security group configured for the environment will also prevent the users that are not part of the security group to be synchronised with the environment.

A thought come into my mind: it won’t harm right to have the users synced. As long as, we are not assigning the security role to them. Yes, it’s true from the authorisation perspective. However, having them in the environment that they are not supposed to be, also means they will be under the list of “Enabled User” that can be used in selection when assigning records. In multi-organisations deployment, it also means the user from different organisations are visible to the environment. These situations could cause confusion to the users.

The list from Production environment:

ProdList.png

The list from the Sandbox environment:

SandboxUserList.png

#3 To Hide Unnecessary Items at the Apps List/Instance Picker

With the “App” concept in Dynamics 365 Online, the home.dynamics.com will contain all kind of “Apps”. This includes the Apps that deployed within the instances. When a user have the privilege to access multiple instances, they also will see the “Apps” that are deployed in those instances. IMHO, it is always the best approach to hide anything that users should not see, so that they could focus on what they need to do with the system.

For example, my user that has full access to all environments, could see the following:

AppsAll.png

Meanwhile, the Test User 3, can only see 1 “App” that is associated to the instance that this user has access (controlled via the Security Group).

AppsTestUser.png

The same thing with the Instance Picker (this has been superseded by the home.dynamics.com). However, if users might have bookmarked this page.

The following is the list from my user:

MyUserInstancePicker.png

Meanwhile, this is from the view of Test User 3.

TestUserInstancePicker.png

Conclusion

Implementing Security Group for Dynamics 365 implementation should be considered in the design and planning to ensure proper and robust security and user experience.

Hope this helps!

 

References

https://blogs.msdn.microsoft.com/crm/2017/03/30/my-apps-on-home-dynamics-com/

https://docs.microsoft.com/en-us/dynamics365/customer-engagement/admin/add-instance-subscription#BKMK_man_sec_group

FetchXML Trick – Cross Entity Criteria in a Group Filter

Recently, I had a tricky question: Can you create a view that is displaying records that are either owned by a team or the users that are a member of that particular team.

EDIT: Jonas Rapp provides a feedback to get more efficient with his tool 😉

The TL;DR; Answer

Use “Alias” + FetchXML editing using XrmToolBox (View Designer + FetchXML Builder – this is the one stop shop!).

 

The Longer Answer

The typical answer to the above scenario would be querying the record with the criteria as “Owner ID = the team OR related Owner (user) is a team member of the team”. Using the Advanced Find query, typically this is the query…

Typical_Adv_Find_Query.png

However, it seems we can’t group the “main” criteria and the Linked-Entity criteria. Looks like we are stuck here… Worry not, there is a trick for that. So, before I go to the solution here are some setups to set the background.

I have 3 users in my instance:

UserList.png

And I’ve set 2 teams for the testing purpose:

Team A with myself and Test User 1 as the member.

Team_A.png

And Team B with Test User 2 as the member.

Team_B.png

Now I have some records for testing purpose:

Sample_Data.png

So, when based on the query to see the Team A records, I would expect to see 3 records there. Using the initial query (above) will return no result, as it is treated as ‘AND’ operation.

To get the FetchXML correctly, I need to edit the FetchXML, my go-to tools for this would be XrmToolBox‘s FetchXML Builder.

To start with, I’ll export the FetchXML out of my initial query, it will look like this:

Base_FetchXML.png

Now the trick is to use the “alias” of the related team entity to form the FetchXML like this:

ModifiedXml.png

As you can see above, we are able to set the condition in the “main” filter and set the operator to OR. Below is the result of the fetch… it works as expected 🙂

TestResult.png

Now, I want to put the query to the view, how to do that?

I’ll use XrmToolBox’s Fetch XML Builder to modify the FetchXML of the view. In my case, I’ve setup a Test Query view. Click on Open View….

OpenView.png

And then select the corresponding view:

Select_View.png

Copy & Paste the FetchXML that we had tested previously into the FetchXML window, if you wish, you could test execute the query. Then click on the “OK” button down there and then click on the “Save As” button up there and save it back to the view.

Save As.png

 

And here’s the result:

FinalResult.png

 

HTH!

Dynamics 365 Portal – When the Custom CSS won’t load.

Recently, I’m working on a demo that I need to skin the Dynamics 365 portal to have a look and feel based on the client’s theme. One of the pages is the dashboard/landing page that showing some charts.

Let say the URL of the page is called “Dashboard”.dashboard.png

It’s showing up the chart nicely. However, I would like to hide the out of the box chart title, as it seems always giving me a static name (based on the chart name in Dynamics 365, where sometimes I would like to label it to something else).

Header.png

My approach is to hide this using CSS (display:none;). So, the usual way I change this is by opening up the Web Page record and add the CSS under the Custom CSS part of the web page.Web_Page_Custom_CSS.png

However, it doesn’t change the layout and even after I reset the cache from the “/_services/about” page of the portal.

My problem was solved by editing the web page via the portal itself. So, I navigated to the page, click on Edit and under the Options tab, I add the CSS there.

Options_Custom_CSS.png

Once I’ve used this part to set the CSS, now the undesired element is gone.

Gone.png

 

HTH!

 

 

Just Some Tips Working with Virtual Entities

Recently I spent some time working on Virtual Entities, one of the new features in Dynamics 365 v9.0. To learn more about Virtual Entities, you can read the official documentation here and how to set it up here. In this post, I would like to share my tips and findings working with Virtual Entities and connecting it to a custom oData v4.0 Web API.

During my attempt setting up Virtual Entity, I encountered a very generic error: “Entity could not be retrieved from data source.” for different problems.

Error.PNG

The error message is not that descriptive and doesn’t provide further information for me to troubleshoot. I’ve submitted a feedback for this, if you also encounter the similar issue: https://ideas.dynamics.com/ideas/dynamics-crm/ID0003358

The tips in this post hopefully can be helpful to fix the above issue 🙂

Background

So, to set the context, in my sample scenario I have a custom oData data source with metadata as below:

VE-Casesensitive.PNG

Tip #1 – Make sure the path is in the correct case (Upper/Lower)

 

I was under an assumption: oData seems to be just an URL, so if I throw in the path as all lower case it should be fine…

Well, one of the reason the error being thrown is because oData seems to expect case sensitive path. I entered “movies” instead of “Movies” and in the field mapping I put “rating” instead of “Rating”. So, make sure the mapping and path is the same as the metadata.

VE-Case.png

Tip #2 – Missing Field Mapping

In my experiment, I created a few extra fields that doesn’t match the metadata definition. Well, this should not create any harm right, just like other custom entity…

Apparently, when there is a missing field in the mapping, the virtual entity is showing the above error.

So, make sure you have the all fields to be mapped correctly and do not create any field that is not in the oData definition. Luckily, you can still omit fields that you don’t like (e.g: when I don’t have “ReleasedYear” field, the VE still works fine).

VE-Mapping.png

Tip #3 – Setting Field Requirement(s)

If you noticed my oData definition for Rating field, it is mentioned there: Nullable=”false”. If the oData set up the field to be mandatory, the corresponding field in the VE also need to be set “Business Required”VE-Field Requirement.PNG

Tip #4 – Be Careful with the “Numbers”

In my oData definition, I have the Rating field, which is a decimal field. But how about in Dynamics 365 we want it to be stored as a different field type, whole number or float instead? Well, VE doesn’t support that, so we need to ensure the field data type is the same from the data source to the VE’s field.

VE-Data type.png

That’s all for today. Hope this helps!