CRM SDK Archives - Aric Levin's Digital Transformation Blog https://aric.isite.dev/tag/crm-sdk/ Microsoft Dynamics 365, Power Platform and Azure Thu, 12 May 2022 03:45:48 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.3 Hiding Grid Item Entity Images from your Model Driven App http://aric.isite.dev/dynamics/post/hiding-bubbles-model-driven-apps/ Sat, 29 May 2021 01:00:00 +0000 https://aric.isite.dev/index.php/2021/05/29/hiding-grid-item-entity-images-from-your-model-driven-app/ As we all know when we display our grids in flow (responsive) mode, the style of the grid changes from table style into card view style. When this happens, what we see is a bubble that shows up next to each card item, and we don’t really have much control over the colors or the text within those bubbles.

The post Hiding Grid Item Entity Images from your Model Driven App appeared first on Aric Levin's Digital Transformation Blog.

]]>
As we all know when we display our grids in flow (responsive) mode, the style of the grid changes from table style into card view style. When this happens, what we see is a bubble that shows up next to each card item, and we don’t really have much control over the colors or the text within those bubbles.

These bubbles are also called the Grid Item Entity Images, and it has been a request for quite some time to be able to customize them. Below is an image that shows the bubbles on a form in a Model Driven App.

Model Driven App - Entity Grid Item Images (Bubbles)

At this point in time, there is no way to customize them, but Microsoft provided a way to Hide these Entity Images. There are a few different ways of removing them, and you can choose your own, but I will explain the different ways.

The first way, which is probably the simplest is using a Utility called FCB.Editor. The FCB.Editor utility is not available for download as open source or from the Microsoft web site, but it can be requested by opening a Microsoft Support Incident and asking for the managed solution.

The FCB.Editor allows us to update or remove existing Features that are not part of the System Settings or cannot be modified using the Settings within the Power Platform Admin Center. The image below shows the FCB.Editor managed solution.

FCB Editor by Microsoft PFE

In order to Remove the Bubbles, all that needs to be done is enter FCB.HideGridItemEntityImages in the text box and set the value in the feature drop down to false. Making this change will remove all the bubbles within the environment. This is an organization wide settings, and cannot be changed per entity.

The FCB.Editor basically queries the features field of the Organization table, and updates the Xml so that the HideGridItemEntityImages is set to false. In case you are unable to get your hands on FCB.Editor, you can use the Xrm.WebApi to query and update

The following three functions or Api calls should allow you to retrieve, update and remove values from the Features column of the Organization table.

The first function is to retrieve the feature set. This is done by calling a retrieve multiple and returning a single result. The following syntax shows how to do that:

Organization Features - Retrieve

Next we want to be able to remove a particular feature. In order to do that, we first have to retrieve the Features Xml, find the feature syntax and remove it from the Xml. The following example shows how to remove the FCB.HideGridItemEntityImages. The following syntax shows how to do that:

Organization - Features - Remove Feature

Finally we want to be able to add a particular feature. This requires us to provide the feature name as well as whether the feature is enabled or not. This is similar to the remove functionality, but we have to build out the feature code as well.

Organization - Features - Add New Feature

After this change is completed, you can log back into your environment and see that the data is displayed without bubbles.

Once I get some time, I will work on creating a small tool, app or solution to modify these settings.

The post Hiding Grid Item Entity Images from your Model Driven App appeared first on Aric Levin's Digital Transformation Blog.

]]>
CRUD Support for Virtual Tables http://aric.isite.dev/development/post/crud-support-virtual-tables/ Mon, 05 Apr 2021 08:45:00 +0000 https://aric.isite.dev/index.php/2021/04/05/crud-support-for-virtual-tables/ It seems like this was only a few days ago, but based on the sample that was published by Microsoft it’s been almost 2 weeks since Microsoft released CRUD support on Virtual tables.

The post CRUD Support for Virtual Tables appeared first on Aric Levin's Digital Transformation Blog.

]]>
It seems like this was only a few days ago, but based on the sample that was published by Microsoft it’s been almost 2 weeks since Microsoft released CRUD support on Virtual tables.

To tell you the truth, I have not really worked with Virtual Entities, ever since it was released, and I would have a lot of reasons to actually use them, it just never seemed the right time. In the recent release, I actually did my own little PoC to determine the complexity, and if it was always that simple, probably something to regret.

Let’s jump into it. Virtual tables (or Virtual entities) have been available for quite some time now, but only for read access. Now with the addition for Create, Update and Delete, this gives us for access to integrating between our Dataverse environment and a publicly available SQL Server (or other platform). In today’s post we will show how to go through the process of creating the SQL Server table, creating the plugin, data provider, data source and finally the virtual table an connecting all the pieces together.

All of the source code in this post is shown in images, but will be available via the Github Link at the bottom of the post.

Let’s start with the database. In this case I used an Azure SQL database, and created a table called Service Request. The script for creating the table is shown below.

Virtual Tables - Create Table in SQL Server

Next we create a Plugin Project in Visual Studio. You will need to install the following packages in your project in order to get access to all of the required resources (per Microsoft documentation):

  • Microsoft.CrmSdk.CoreAssemblies
  • Microsoft.CrmSdk.Data
  • Microsoft.CrmSdk.Deployment
  • Microsoft.CrmSdk.Workflow
  • Microsoft.CrmSdk.XrmTooling.CoreAssembly
  • Microsoft.IdentityModel.Clients.ActiveDirectory
  • Microsoft.Rest.ClientRuntime
  • Newtonsoft.Json

Within the plugin we will create 6 Classes. The first is a static class containing the Connection code, and the other classes are each for a message (Create, Retrieve, RetrieveMultiple, Update, Delete). You can create them as a single file or in multiple files. For the demonstration they are all created in separate files.

The following using statements have been added to all files, although not all is required for all classes.

Virtual Tables - Using Statements

Let’s start with the Connection class. We use the SqlConnectionStringBuilder class to generate the Connection string and return it to the rest of the classes that will consume it. This is shown in the image below.

Virtual Tables - Static Connection Class in Plugin

Next, let’s look at the CRUD classes. All of the classes implement the IPlugin interface and call the Execute function of that Interface. In each of the class based on the required functionality we retrieve the Execution Context in order to read data from the Dataverse environment, and then synchronize between our Dataverse environment and our Azure SQL Server. The screenshots below show the code for each of these.

Create Class:
Virtual Tables - Create Class

Retrieve Class:
Virtual Tables - Retrieve Class

Retrieve Multiple Class:
Virtual Tables - Retrieve Multiple Class

Update Class:
Virtual Tables - Update Class

Delete Class:
Virtual Entities - Delete Class

Once the code for the Plugin is completed we will go ahead and register the plugin via the Plugin Registration Tool. Before registering the plugin, make sure that you have the latest version of the Plugin Registration Tool that provides support for CRUD operations in virtual tables. At the time of writing this post, the required version was 9.1.0.24. You can find the download link below:

https://www.nuget.org/packages/Microsoft.CrmSdk.XrmTooling.PluginRegistrationTool

Now let’s go ahead and register the Plugin. This should include all of the five messages above. Once the Plugin is registered, we go ahead and Register a new Data Provider (using the Plugin Registration Tool).

Click on the Register button, and select Register New Data Provider (Ctrl + P).

When selecting the Data Source Entity for the first time, choose the Create New from the drop down. It is important to select the solution that contains the publisher that has the prefix that you want to use, or you will have to modify you code for something else.

Virtual Tables - Plugin Registration Tool - New Data Provider

Once we are done with creating the data provider in the Plugin Registration Tool, we can go ahead and start setting up the Virtual Table in our Dataverse environment. This functionality is not available yet in the Maker Portal, so we will have to do this in the Classic interface (Advanced Settings).

Navigate to Settings and Administration, and select the Virtual Entity Data Sources, and click on the New button. A popup will appear with a drop down to select a Data Provider as shown in the image below.

Virtual Tables - Select Data Provider (Dataverse)

Select the name of the Data Provider that you selected, and click on the OK button. Then you will be able to provide a name for the Data Source.

Click on Settings again and select Solutions. Select the name of the solution where you want to create the fields for this table. Check the Virtual Entity option, and select the Data Source that you just created. Enter a Display Name, Plural Name and Name for the entity. You will notice that there are two additional Names which are the External Name and the External Collection Name. For the External Name, you should enter the name of the Source table. The External Collections name can contain the same values as the Plural table name.

Virtual Tables - Create Virtual Table (Dataverse)

Once you have finished creating the table, go ahead and create all of the columns that you are going to use to view or update within the Virtual Entity. Only add columns that you want to either read from your Azure SQL table or that you want to write back. Any columns that are for management only are not really required. The image below show the columns that were created for our test:

Virtual Tables - Table Columns (Dataverse)

Next, we need to add this entity to our Model Driven App, so that we can test this out. Select an existing MDA or create a new one and add the entity to it.

Finally go ahead and test the results.

Virtual Tables - Demo

The animated screenshot above shows adding, reading and updating entity fields using CRUD operations.

You can click on the link below to get access to the Source Code:
https://github.com/ariclevin/VirtualTables

The post CRUD Support for Virtual Tables appeared first on Aric Levin's Digital Transformation Blog.

]]>
No-Code Solution for custom Change Log using Web Hooks and Cloud Flows http://aric.isite.dev/development/post/no-code-custom-change-log-webhook-cloud-flow/ Mon, 25 Jan 2021 00:30:00 +0000 https://aric.isite.dev/index.php/2021/01/25/no-code-solution-for-custom-change-log-using-web-hooks-and-cloud-flows/ In one of our recent requirements, we had to log changes to certain fields in a few different entities. Since we needed the value of the field before and after the change, the logical option was to use plugins and adding a pre-image step to it in order to save that data.

The post No-Code Solution for custom Change Log using Web Hooks and Cloud Flows appeared first on Aric Levin's Digital Transformation Blog.

]]>
In one of our recent requirements, we had to log changes to certain fields in a few different entities. Since we needed the value of the field before and after the change, the logical option was to use plugins and adding a pre-image step to it in order to save that data.

There are however other alternatives, that might make more sense, especially if you want to minimize the amount of code and plugins that are accessible within the system.

The solution is simple. We create a Webhook and add to it the corresponding step and Pre-Image, and upon execution it will be triggering a Cloud flow where we can use the values from the Input Parameters and the Pre-Entity Image.

Let’s go ahead and see how we implement this. The first step is to create a Cloud flow, and set the trigger to When a HTTP request is received.

Dataverse Web Hook - Cloud Flows - HTTP Request is Received

The HTTP POST URL is not available until the flow is saved, so enter the request Body JSON Schema. You will need to enter an action to Save the Flow, so you can enter an Initialize Variable, which we will use later set a name for the flow and Save the record. Once the record is saved, the HTTP POST URL will be filled in and you will be able to configure the Webhook. Copy the HTTP POST URL and paste it in NotePad or other text editor. The result should be similar to what you see below:

https://prod-XXX.westus.logic.azure.com:443/workflows/41e03b6243cc47273a71f827fb3bd29b/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=e5138Klq7cOcbG1RJ2bXA42et4vFM0-kZ3k8jyK7Txs

Add new lines between the url and the query string parameters and remove the separators so that it looks like this:

https://prod-XXX.westus.logic.azure.com:443/workflows/41e03b6243cc47273a71f827fb3bd29b/triggers/manual/paths/invoke

api-version=2016-06-01

sp=%2Ftriggers%2Fmanual%2Frun

sv=1.0

sig=e5138Klq7cOcbG1RJ2bXA42et4vFM0-kZ3k8jyK7Txs

Replace all the %2F encodings with the corresponding character (/). This will change that line to look like this: sp=/triggers/manual/run

Now, let’s go and open the Plugin Registration Tool, and click on the Register drop down and select Register New Web Hook, or CTRL+W for short.

Dataverse Web Hook - Cloud Flows - Register Web Hook

This will open the Register New Web Hook dialog when we will enter the HTTP URL and the different parameters that we specified above as shown in the screenshot below.

Dataverse Web Hook - Cloud Flows - Web Hook Registration

Now that we have registered the Web Hook, you should be able to see the new Web Hook in the list of Registered Plugins. Select the Web Hook, and select Register New Step (either by Right Clicking on the Web Hook and selecting Register New Step or from the top tab menu).

Just as you would perform this step registration process for a plugin, do the same for the Web Hook. Select the Message, Primary Entity and Filtering Attributes as shown in the image below. Of course you should customize this for your own message..

Dataverse Web Hook - Cloud Flows - Register New Step

Since we want to get the value before the change and after the change, we need to register a new image for the step of type Pre Image, as shown in the screenshot below. Add the name and entity alias, and specify the parameters that you want for you Pre Image.

Dataverse Web Hook - Cloud Flows - Register Pre Image

Now that we are done with the configuration within the Plugin Registration Tool, let’s take a look at where this data will be stored. We created a new entity called Change Log that contains information about the entity and the record that was modified, along with fields to store the values before and after the change.

Dataverse Web Hook - Cloud Flows - Change Log Table

Next, let’s go back the flow that we created. We will start by initializing a few variables that will be used to store some of the values, and then retrieve the values from the HTTP Post method.

It is a good idea to run the flow once so that you can review the Outputs of the When a HTTP request is received trigger, and that will help you with constructing the expressions needed for the different steps.

Dataverse Web Hook - Cloud Flows - HTTP Request received outputs

The variables are shown in the image below. The Pre and Post variables will be added later, while the Entity Id, Entity Name and User Id can be filled out during the initialization as follows:

  • triggerBody()?[‘PrimaryEntityId’]
  • triggerBody()?[‘PrimaryEntityName’]
  • triggerBody()?[‘UserId’]

Dataverse Web Hook - Cloud Flows - Initialize Variables

Since getting the values from the Input Parameters and the PreImage is a little more complex, I used two compose actions for these, and set the Inputs to as follows:

  • triggerBody()?[‘InputParameters’][0][‘value’][‘Attributes’]
  • triggerBody()?[‘PreEntityImages’][0][‘value’][‘Attributes’]

Dataverse Web Hook - Cloud Flows - Compose Data Operations

The final step before storing the record is doing an Apply to each of the Input parameters and check the value corresponding to the attribute that was changed. We run this for both the PreEntity image results and the Input Parameter results and have a condition to check for the Input Parameter.

The Condition logic expression is: items(‘Apply_to_each_PreEntity_Image’)?[‘key’], and the Set Variable Pre contains the following expression: items(‘Apply_to_each_PreEntity_Image’)?[‘value’]

Dataverse Web Hook - Cloud Flows - Apply to Each, Conditions and Set Variables

The same applies to the other apply to each action. Once we have retrieved all the information that we need, the change log record will be created. 

Dataverse Web Hook - Cloud Flows - Create Change Log Record

The results will look like this:

Dataverse Web Hook - Cloud Flows - Change Log Record Results

The post No-Code Solution for custom Change Log using Web Hooks and Cloud Flows appeared first on Aric Levin's Digital Transformation Blog.

]]>
Configure Azure Service Bus to integrate between CDS and On-Premise SQL database http://aric.isite.dev/azure/post/configure-asb-integrate-cds-sql/ Mon, 06 Jan 2020 07:17:00 +0000 https://aric.isite.dev/index.php/2020/01/06/configure-azure-service-bus-to-integrate-between-cds-and-on-premise-sql-database/ In this blog post I will demonstrate how to use Azure Service Bus and a Listener application to integrate between the Common Data Service (Dynamics 365 or Power Apps Model Driven Application) and an On Premise SQL Service database.

The post Configure Azure Service Bus to integrate between CDS and On-Premise SQL database appeared first on Aric Levin's Digital Transformation Blog.

]]>
In this blog post I will demonstrate how to use Azure Service Bus and a Listener application to integrate between the Common Data Service (Dynamics 365 or Power Apps Model Driven Application) and an On Premise SQL Service database.

There are various other ways to implement this, with the combination of Azure products such as Azure functions, Azure Logic Apps, On-Premise Data Gateway and Microsoft Flow, but those are not always available, especially when working in non-commercial environments, or when IT restricts what resources are available to the different departments of the agencies.

In order to implement this, there are a few prerequisites that have to be completed. These are set up the database server, write the console application to act as the event listener, install the Azure Service Bus, create plugin code to call the Azure Service Bus when a particular event happens. The logic of this article will be as follows: When an account record gets created or updated, it will call the Azure Service Bus in order to update an On-Premise SQL database that a new record is created or an existing record got updated.

Configuring the SQL database

We will start with the first step which is the configuration of the database. You can set up the database with a single table (to use only for Accounts), or add some related tables if necessary. We will also create a couple of stored procedures to Insert and Update the Accounts table. Links to code files will be shared at the end of the post. The image below displays the database structure. For the purpose of this articles, the Contacts and Users tables will not be required.

Azure Staging SQL Database with Tables and Stored Procedures

Create the Azure Service Bus Namespace

We can now create the Azure Service Bus. Login to your Azure Portal and search for Service Bus under the list of available Resources. Click on the Add button to add a new service bus.

Add New Azure Service Bus Namespace

This will open the create namespace window. Enter a name for your service bus in the Create Namespace window. It will append servicebus.windows.net to the name that you specify. Select a pricing tier, your subscription, resource group and location where you want this hosted. If you do not have a resource group, you can create a new one from this window.

Azure Service Bus Create Namespace

It will take a couple of minutes (or less) to create your namespace, and then the Azure Service Bus will be visible on your screen. The first thing that we need to do is check the Shared access policy. There is a default Shared Access policy that is available with the new Azure Service Bus that was created, and includes the three available claims: Manage, Send, Listen.

Send we only need Send and Listen, we will create a new Shared access policy, naming it IntegrationSharedAccessKey (or any other name that you would like) and set the available claims to Send and Listen. After you create your shared access policy, click on it to see the Keys and the Connection Strings. You will need them for configuring CDS and your Console application.

Configure the Service Endpoint in CDS

Next, let’s add this to out CDS environment, by running the Plugin Registration Tool. We will be using the Plugin Registration Tool for version 9.1. Run the Plugin Registration Tool and Create a new connection to your CDS environment. Click on Register and Select a new Service Endpoint. Copy the Connection String from your Service Bug Resource in Azure, and paste it in the popup window. Make sure that the Let’s Start with the connection string from the Azure Service Bus Portal… option is selected (as shown below).

Add Service Bus Endpoint Connection String

In the next window, Service Endpoint Registration make the following changes:

  • In the namespace address, change sb to https
  • In the Designation Type change to Two Way (you can also do One Way if you prefer, but in this particular examples we are using two-way.
  • Enter a path for the Service Endpoint. This will be used by the console application to listen to where changes are being made.
  • The Authorization Type should be set to SASKey, with the SASKeyName as the name of your Shared Access policy in Azure, and the SAS Key copied from the Primary Key in the Shared Access policy.

Azure Service Bus Service Endpoint Registration

After we have created the Service Endpoint, we need to capture the Guid of the Service Endpoint as we will use it from the plugin that we will soon start developing. In order to get the Guid of the Service Endpoint, click on the Properties tab, and scroll down till you see ServiceEndpointId property. Copy the Guid from there. We can hard code this in our application, or add it as Environmental Variable inside of CDS.

Add Environmental Variable in CDS

Navigate to a solution inside of Power Apps, select the solution and click on the New button on the command bar. Your will see the option to add new environmental variable. Enter a display name, schema name (automatically populated), description and data type. As this is going to store a Guid, you should use Text as the data type. You can enter a default value for your new EndpointId or specify a new value. The screenshot below shows how this is added.

Common Data Service Environmental Variable

As the Environmental Variables are still a new feature and there are some issues that have to be dealt with, you can use the Portal Settings entity or another Configuration entity to store your variables.

Writing the Plugin Code

We can now start developing the plugin code. This is a simple plugin that will run on the Account Create and Account Update messages. Our Plugin includes three code files: Plugin.cs, Account.cs and AccountLogic.cs.

The Plugin.cs is the standard tool generated Plugin.cs file that implements the IPlugin interface. There are only a couple of changes that were done to this class, since we need to communicate with Azure Service Bus.

We added an internal property called CloudService of type IServiceEndpointNotificationService. In the LocalPluginContext constructor, we set the value for the CloudService property.

Add Property for Cloud Service

Get Service for Azure Service Bus Listener

The Account Class adds the Create and Update events to the RegisteredEvents collection, and adds two functions: ExecutePostAccountCreate and ExecutePostAccountUpdate which get the Account Id and call the CreateAccount or UpdateAccount of the logic class.

Account Entity Plugin Logic

The AccountLogic class has a construction that takes four parameters: the Plugin Execution Context, Organization Service, Tracing Service and the Service Endpoint Notification Service. These are all used for the different purposes of the plugin.

Both the CreateAccount and UpdateAccount functions have the exact same logic. The difference is in the message which is going to be passed to the Azure Service Bus as part of the context.

The CreateUpdateAccount function Retrieves all the data from the Account record, gets the Endpoint Id (from the Enviromental Variables Entities), adds the Account record to the Shared Variables of the Context and finally calls the Azure Service Bus passing the context, which includes the data from the Account entity.

Create and Update Account

After the plugin receives the response, it writes the response to a note within the account record. After the plugin is complete, make sure to sign and compile it, and then register it with the plugin registration tool. When the assembly is registered, add two messages (one for Create and one for Update of the Account entity).

Plugin Registration Tool Account Plugin

Writing the Listener Windows Service Application
The final step is to work on the Console Application. We can start by writing the helper class that will connect to SQL Server and Create a new Account record. The first thing that we need to do is add a connection string to the App.Config that is part of the Console Application. If an App.Config file does not exist, you can create one.

In the Connection String section enter the following code:

<add name=”AzureStaging” connectionString=”Data Source={LOCALDBSERVERNAME};Initial Catalog=AzureStaging;User ID=azureadmin;Password=Azur3Adm1n;Persist Security Info=False” />

We create a SqlDataManager class which will call the SQL server stored procedures to Create and Update the account records. The functions will receive the values of the different fields in SQL Server and add them as Stored Procedure parameters as shown below:

Listener Create Account (SQL Data Manager)

Next we create the class to listen and process the incoming requests from Azure Service Bus. The class has a default public function called Execute which accepts a RemoteExecutionContext parameter. This parameters contains the Shared Variables that we passed from our plugin as well as the execution context that allows us to retrieve the message name to know if this is a create or an update.

Azure Service Bus Listener Entry Point

The CreateAccount and UpdateAccount functions receive the Account entity, take the necessary attributes and call the CreateAccount function of the SqlDataManager class in order to store the data in SQL Server.

Azure Service Bus Listener Create Account

We added the Service class to the project, which contains an eventlog component that will write errors to the Event Log. The OnStart Event will listen to events and the OnStop Event will stop listening to the Azure Service Bus.

Azure Service Bus Windows Service Start/Stop

The Console application will run as a Windows Service. The solution includes the Project Installer class which allows us to install this as a Windows Service class. The Main entry point of the application provides us with some testing capabilities as well as installation or uninstallation of the Windows Service.

We added a Program class that allows us to install and uninstall the Windows Service from within our Visual Studio debugger.

Install or Uninstall Windows Service from Visual Studio Debugger

Once the Windows Service is installed by running the VS application with the –install parameter, you will see the results in Services. Verify the Service is running, and depending whether you are testing this on your Local machine or on a Server, determine if to use the Local System account or the Network Service account.

Azure Service Bus Installed Windows Service

Now that we have done installing all the components, it is time to test all the parts working together. We tried running the first test, and the test did not have all the required fields. The description field was missing, so the result was a new note added to the timeline returning the error of a missing field from SQL Server.

Azure Service Bus Integration (End to End - First Try)

We then tried again, providing the Description field as well. This time we saw the success message in the timeline.

Azure Service Bus Integration (End to End - Second Try)

We wanted to verify that the data existed in SQL Server, so we ran a SQL Statement to validate the data, and received the following results:
New Record created in SQL Server. Results successful

Hope this will be a benefit for you. All the Plugin Source, Database Source and Listener Console Application Source Code is available on Github.
https://github.com/ariclevin/Integration/tree/master/ASBListener

The post Configure Azure Service Bus to integrate between CDS and On-Premise SQL database appeared first on Aric Levin's Digital Transformation Blog.

]]>
Credit Card Validator PCF Control http://aric.isite.dev/powerapps/post/credit-card-validator-pcf-control/ Mon, 27 May 2019 16:18:00 +0000 https://aric.isite.dev/index.php/2019/05/27/credit-card-validator-pcf-control/ Recently, I published a blog post on creating a PowerApp that validates a Credit Card number, and displays the correct image next to the card based on the Card number. As my first PowerApps Component Framework application, I took the same logic of the PowerApp that I created, and decided to create a PCF control that will do the same. I have also created a training guide for this, so that you can follow this logic step by step, which you can download at the bottom of this post.

The post Credit Card Validator PCF Control appeared first on Aric Levin's Digital Transformation Blog.

]]>
Recently, I published a blog post on creating a PowerApp that validates a Credit Card number, and displays the correct image next to the card based on the Card number. As my first PowerApps Component Framework application, I took the same logic of the PowerApp that I created, and decided to create a PCF control that will do the same. I have also created a training guide for this, so that you can follow this logic step by step, which you can download at the bottom of this post.

In order to develop a PCF control, there are a few prerequisites that need to be installed on your machine. The first is that you need to have Visual Studio 2017, so that you can use the Developer Command Prompt for VS 2017, and you need to download and install Node.js. In the demo document we use the 10.15.3 LTS version (at the time of writing this article). We also need to download and install the PowerApps Command Line Interface (CLI).

I prepared this lab particularly for part of a Dynamics 365 Saturday NYC workshop that will be held on June 7th and 8th. This lab will cover creating the project,  configuring the control manifest file, building the index.ts file and the stylesheet (if required), building the control, testing the control and deploying the control into your Microsoft Dynamics 365 or CDS environment. We will finally create a field for the Credit Card number, and add the control to the form.

The animated gif below shows the end result of using the PCF control on a form in Unified Interface

PCF Demo

You can download the lab instructions, source code and solution using the links below:

Demo and Lab pdf file

Dynamics 365 Solution file

PCF Control Source Code files

The post Credit Card Validator PCF Control appeared first on Aric Levin's Digital Transformation Blog.

]]>
Global Cloning functionality for Dynamics 365 http://aric.isite.dev/dynamics/post/global-cloning-for-dynamics-365/ Thu, 15 Feb 2018 05:28:00 +0000 https://aric.isite.dev/index.php/2018/02/15/global-cloning-functionality-for-dynamics-365/ Recently I had a requirement to provide cloning capabilities for one of the projects that I was working on. It wasn't so simple as to just clone an individual record, but also provide the ability to clone the relationships.

The post Global Cloning functionality for Dynamics 365 appeared first on Aric Levin's Digital Transformation Blog.

]]>
Recently I had a requirement to provide cloning capabilities for one of the projects that I was working on. It wasn’t so simple as to just clone an individual record, but also provide the ability to clone the relationships.

This is where it becomes tricky, as some entities cannot be easily cloned due to some of the restrictions, so we wanted to provide this solution the ability to restrict certain actions from happening. For example, the address1_addressid and address2_addressid fields in the Account and Contact entities cannot be cloned as they point to the Customer Address record, so the Guid there has to be unique.

So for the first scenario, we needed to provide the system with the ability to restrict certain fields from being cloned, by providing a status of Active or Inactive, the cloning solution will decide whether or not to clone the record. The screenshot below shows the Clone Settings entity, with the list of attributes that are available for cloning. Notice the highlighted row is marked as Inactive., which means it will not be cloned.

Clone Settings Entity

Next we had to deal with relationships. One of the issue with relationships is that there are probably many relationships that you do not want to be cloned. In the related entities, we provided 3 statuses: Duplicate, Reassociate or Inactive. The Inactive option skips the cloning procedure for the relationship. The Duplicate will make a duplicate of the record Related entity record and the Reassociate will reassociate the related lookup from the source record to the cloned record.

Clone Relationships

We modifies the application ribbon so that the Clone button will appear on every entity (based on a webapi call to check if the entity is enabled for cloning in the Clone Settings), and added a global script library for this purpose on for calling the Clone action. The end result is as follows.

Original and Cloned records

This solution works for our purpose, but I would consider it a Beta Release for anyone who is interested in source code. It’s available on github, so you can make whatever changes that you want. I will add instructions on how to use sometime soon.

The post Global Cloning functionality for Dynamics 365 appeared first on Aric Levin's Digital Transformation Blog.

]]>
Dynamics 365 v9 – The end of the SDK http://aric.isite.dev/dynamics/post/dynamics365-v9-end-of-sdk/ Thu, 02 Nov 2017 02:30:00 +0000 https://aric.isite.dev/index.php/2017/11/02/dynamics-365-v9-the-end-of-the-sdk/ With the release of Dynamics 365 (online), version 9.0, there are a lot of changes in our developer resources. One of the biggest changes though, is that the Microsoft Dynamics CRM SDK will no longer be available as a download. The new name of the SDK, as it was known will be the Microsoft Dynamics 365 Customer Engagement Developer Guide.

The post Dynamics 365 v9 – The end of the SDK appeared first on Aric Levin's Digital Transformation Blog.

]]>
With the release of Dynamics 365 (online), version 9.0, there are a lot of changes in our developer resources. One of the biggest changes though, is that the Microsoft Dynamics CRM SDK will no longer be available as a download. The new name of the SDK, as it was known will be the Microsoft Dynamics 365 Customer Engagement Developer Guide.

An SDK is a combination of documentation and resources that are used for the development of tools and addons . Until now, the term “SDK” refered to the documentation for Dynamics CRM/365 and for the download package containing the assemblies and tools, and the offline version of the documentation. In order to clear up this confusion, and to be consistent with the terms for the Microsoft documentation, the developer documentation will not be refered to as the Developer Guide. This name is more descriptive for the content that supports developers in creating tools and addons using the available APIs.

Probably the greatest single change is that Microsoft will no longer be providing a download package for all the documentation, tools and sample code. Instead Microsoft will be offering an a-la-carte approach so that you can download the individual things as you need them. SDK assemblies and tools will be distributed only via NuGet. Microsoft will provide a script that will allow downloading the assemblies and tools from NuGet directly, and all the sample code will be available on msdn or on github.

The new documentation will be available on docs.microsoft.com, which will include documentation for the Client APIs, Web APIs, and more.

To read the full details regarding this release, see the Dynamics 365 blog on msdn: https://blogs.msdn.microsoft.com/crm/2017/11/01/whats-new-for-customer-engagement-developer-documentation-in-version-9-0/

Enjoy a new era.

The post Dynamics 365 v9 – The end of the SDK appeared first on Aric Levin's Digital Transformation Blog.

]]>
Closing Incident Record http://aric.isite.dev/dynamics/post/closing-incident-record/ Thu, 13 Oct 2016 18:36:00 +0000 https://aric.isite.dev/index.php/2016/10/13/closing-incident-record/ Recently I had this question come up, and wanted to discuss the difference between closing an incident (Case) as resolved, or closing an incident as cancelled. There are a few other options, but we will focus on these two.

The post Closing Incident Record appeared first on Aric Levin's Digital Transformation Blog.

]]>
Recently I had this question come up, and wanted to discuss the difference between closing an incident (Case) as resolved, or closing an incident as cancelled. There are a few other options, but we will focus on these two.

The Case entity in CRM, has an associated entity called Case Resolution (incidentresolution). When a case was opened and then completed with a resolution, the closure of the case will be via the Incident Resolution Entity, as shown in the code below.

IncidentResolution resolution = new IncidentResolution
{
   Subject = "Resolved Sample Incident",
   IncidentId = new EntityReference(Incident.EntityLogicalName, _incidentId)
};

// Close the incident with the resolution.
CloseIncidentRequest request = new CloseIncidentRequest
{
   IncidentResolution = incidentResolution,
   Status = new OptionSetValue((int)incident_statuscode.ProblemSolved)
};

CloseIncidentResponse closeResponse = (CloseIncidentResponse)service.Execute(closeIncidentRequest);

However, when an incident as cancelled, there is no resolution, so the closure of the incident happens directly within the Case entity, and there is no need for a closure. See the code below to notice the difference.

SetStateIncidentRequest request = new SetStateIncidentRequest()
{
   IncidentState = new OptionSetValue(2), // Cancelled
   IncidentStatus = new OptionSetValue(6), // Cancelled
   EntityId = new EntityReference("incident", incidentId)
}

The post Closing Incident Record appeared first on Aric Levin's Digital Transformation Blog.

]]>
Retrieving All Record owned by other Team Members – Part II http://aric.isite.dev/development/post/retrieving-all-record-owned-by-other-team-members-part-ii/ Wed, 18 Nov 2015 16:00:00 +0000 https://aric.isite.dev/index.php/2015/11/18/retrieving-all-record-owned-by-other-team-members-part-ii/ In a recent post we showed how to retrieve all the team members of a particular record. This was different then using the default My Team Comments view, and we showed the relationship that is needed.

The post Retrieving All Record owned by other Team Members – Part II appeared first on Aric Levin's Digital Transformation Blog.

]]>
In a recent post we showed how to retrieve all the team members of a particular record. This was different then using the default My Team Comments view, and we showed the relationship that is needed.

In this post we will show how to implement that same query using C# code. This can be used from within a plugin or a custom application that uses the CRM SDK.

        
      internal EntityCollection RetrieveMyTeamComments(Guid userId)
        {
            ColumnSet commentsColumns = new ColumnSet("bgx_commentid", "bgx_autonumber", "bgx_categoryid", "bgx_comment", "bgx_response", "ownerid", "owninguser", "bgx_submissionid");

            EntityCollection rc = new EntityCollection();
            QueryExpression query = new QueryExpression()
            {
                EntityName = "bgx_comment",
                ColumnSet = commentsColumns,
                Distinct = true,
                Criteria =
                {
                    Conditions = 
                    {
                       new ConditionExpression("statecode", ConditionOperator.Equal, 0)
                    }
                },
                LinkEntities = 
                {
                   new LinkEntity()
                   {
                       LinkToEntityName = "systemuser",
                       LinkToAttributeName = "systemuserid",
                       LinkFromEntityName = "scag_comment",
                       LinkFromAttributeName = "owninguser",
                       JoinOperator = Microsoft.Xrm.Sdk.Query.JoinOperator.Inner,
                       EntityAlias = "user",
                       LinkEntities = 
                       {
                           new LinkEntity()
                           {
                               LinkToEntityName="teammembership",
                               LinkToAttributeName="systemuserid",
                               LinkFromEntityName = "systemuser",
                               LinkFromAttributeName="systemuserid",
                               JoinOperator = Microsoft.Xrm.Sdk.Query.JoinOperator.Inner,
                               EntityAlias= "teammembership1",
                               LinkEntities = 
                               {
                                   new LinkEntity()
                                   {
                                       LinkToEntityName="team",
                                       LinkToAttributeName="teamid",
                                       LinkFromEntityName = "teammembership",
                                       LinkFromAttributeName="teamid",
                                       JoinOperator = Microsoft.Xrm.Sdk.Query.JoinOperator.Inner,
                                       EntityAlias= "team",
                                       LinkEntities = 
                                       {
                                           new LinkEntity()
                                           {
                                               LinkToEntityName="teammembership",
                                               LinkToAttributeName="teamid",
                                               LinkFromEntityName = "team",
                                               LinkFromAttributeName="teamid",
                                               JoinOperator = Microsoft.Xrm.Sdk.Query.JoinOperator.Inner,
                                               EntityAlias= "teammembership2",
                                               LinkEntities = 
                                               {
                                                   new LinkEntity()
                                                   {
                                                       LinkToEntityName = "systemuser",
                                                       LinkToAttributeName = "systemuserid",
                                                       LinkFromEntityName = "teammembership",
                                                       LinkFromAttributeName = "systemuserid",
                                                       JoinOperator = Microsoft.Xrm.Sdk.Query.JoinOperator.Inner,
                                                       EntityAlias = "systemuser",
                                                       LinkCriteria = new FilterExpression
                                                       {
                                                           FilterOperator = LogicalOperator.And,
                                                           Conditions = 
							   {
                                                               new ConditionExpression("systemuserid", ConditionOperator.Equal, userId)
                                                           }
                                                        }
                                                   }
                                               }
                                           }
                                       }
                                   }
                               }
                           }
                       }
                   }
                }
            };

            EntityCollection results = new EntityCollection();
           
            try
            {
                results = service.RetrieveMultiple(query);
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                Console.WriteLine(ex.Message);
            }

            return results;

        }

You will notice the difference between the code and the advanced find from the previous view is that in the view there is only three levels of relationships, while in the code there are 5.
The reason for this is that in the advanced find view, we do not need to create the relationship with the teammembership entity.

The post Retrieving All Record owned by other Team Members – Part II appeared first on Aric Levin's Digital Transformation Blog.

]]>
Checking if a solution exists and upload it to CRM using the SDK http://aric.isite.dev/dynamics/post/check-solution-exists-upload/ Fri, 21 Aug 2015 03:07:00 +0000 https://aric.isite.dev/index.php/2015/08/21/checking-if-a-solution-exists-and-upload-it-to-crm-using-the-sdk/ Many times we encounter an external application that requires a solution to be installed in your CRM environment, but it might not be there or we might require to upgrade an existing solution.

The post Checking if a solution exists and upload it to CRM using the SDK appeared first on Aric Levin's Digital Transformation Blog.

]]>
Many times we encounter an external application that requires a solution to be installed in your CRM environment, but it might not be there or we might require to upgrade an existing solution.

The first thing that we want to check is if the solution that we are looking for already exists in CRM. The following function checks for that exactly.

Many times we encounter an external application that requires a solution to be installed in your CRM environment, but it might not be there or we might require to upgrade an existing solution.

The first thing that we want to check is if the solution that we are looking for already exists in CRM. The following function checks for that exactly.

        public EntityCollection RetrieveSolutions(string solutionName)
        {
            QueryExpression query = new QueryExpression
            {
                EntityName = "solution",
                ColumnSet = new ColumnSet(true),
                Criteria =
                {
                    Conditions =
                    {
                        new ConditionExpression("uniquename", ConditionOperator.Equal, solutionName)
                    },
                }
            };

            RetrieveMultipleRequest request = new RetrieveMultipleRequest();
            request.Query = query;

            try
            {
                RetrieveMultipleResponse response = (RetrieveMultipleResponse)service.Execute(request);
                EntityCollection results = response.EntityCollection;
                return results;
            }
            catch (System.Exception ex)
            {
                return null;
            }
        }

Just pass the name of the solution to the function, and it will return all solutions that match that solution name. Should be either 0 or 1 values returned. I can use the following code to check for additional information about the solution (such as version number):

                if (results.Entities.Count > 0)
                {
                    string friendlyName = results.Entities[0].Attributes["friendlyname"].ToString();
                    string versionNumber = results.Entities[0].Attributes["version"].ToString();
                }

The next phase is to import the solution if none exists, or if you had a newer version that you would like to import, the same codeset will work. We can call the following function, and pass the full path of the solution file (zip file):

        
public static bool ImportSolution(string fileName)
        {
            byte[] fileBytes = File.ReadAllBytes(fileName);
            ImportSolutionRequest request = new ImportSolutionRequest()
            {
                CustomizationFile = fileBytes
            };

            try
            {
                ImportSolutionResponse response = (ImportSolutionResponse)service.Execute(request);
                return true;
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw ex;
            }
        }

That is basically the entire process. If the import fails, you will receive a Fault Exception and can check the data returned in the catch block.

The post Checking if a solution exists and upload it to CRM using the SDK appeared first on Aric Levin's Digital Transformation Blog.

]]>