Azure https://dynamics-chronicles.com/ en Dataverse / Dynamics 365 : Azure Managed Identities from Plugins. Step by Step. https://dynamics-chronicles.com/article/dataverse-dynamics-365-azure-managed-identities-plugins-step-step <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">Dataverse / Dynamics 365 : Azure Managed Identities from Plugins. Step by Step. </span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/julienbiedermann" lang="" about="/user/julienbiedermann" typeof="schema:Person" property="schema:name" datatype="" class="username">julien.biedermann</a></span> <span property="schema:dateCreated" content="2025-07-17T12:47:18+00:00" class="field field--name-created field--type-created field--label-hidden">Thu, 07/17/2025 - 14:47</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><h2>Introduction</h2> <p>The days of storing Client ID and secret of your Key Vault in Dynamics are coming to an end. With <a href="https://learn.microsoft.com/en-us/power-platform/admin/managed-identity-overview">Power Platform Managed Identity</a>, Dataverse plug-ins can now <strong>connect to Azure resources that support managed identity without the need for credentials</strong>. Please note that at the time of writing this article, this feature is still in preview and is not intended for production use.</p> <p>This marks a significant improvement in security and access management, eliminating the risks associated with storing credentials while simplifying integration between Dataverse and Azure. In this article, we’ll explore how this feature works and the process for implementing it.</p> <h2>How to implement it</h2> <p>Microsoft’s documentation is missing some details that can make the configuration process challenging. In this article, I’ll provide a clear, step-by-step guide with practical examples to help you set everything up quickly and efficiently. My goal is to simplify the process and ensure you have a smooth experience getting it to work. </p> <h3>Step 1 : Create a new app registration or user-assigned managed identity</h3> <ol> <li>Create new "User Assigned Managed Identity". You can follow this <a href="https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-manage-user-assigned-managed-identities?pivots=identity-mi-methods-azp#create-a-user-assigned-managed-identity">documentation</a> to create it.</li> </ol> <p><img alt="Create User Assigned Managed Identity" data-entity-type="file" data-entity-uuid="225ecf33-42a1-4fb3-bece-9574ec494fc5" src="/sites/default/files/inline-images/Create%20User%20Assigned%20Managed%20Identity.png" /></p> <ol start="2"> <li>Copy and save the "Client ID" value of your managed identity to be used in step 6</li> </ol> <p><img alt="Client ID managed identity" data-entity-type="file" data-entity-uuid="c17834d3-195e-4ae9-91ba-e1b4a05252f2" src="/sites/default/files/inline-images/managed_identity_2.png" /></p> <h3>Step 2 : Create Key Vault</h3> <ol> <li>Create a key vault</li> <li>Create a secret with name "DynamicsChroniclesSecret" and with secret value = "Managed identity for Power Platform is working"</li> <li>In "Access control (IAM)" of your key vault, add the role assignment "Key Vault Secrets User" to the User Assigned Managed Identity created in step 1</li> </ol> <h3>Step 3 : Create a certificate</h3> <ol> <li>Open Powershell to create a certificate using this script</li> </ol> <pre> <code># Generate a self-signed certificate $cert = New-SelfSignedCertificate -Subject "CN=dynamicschronicles, O=corp, C=dynamicschronicles.ch" -DnsName "www.dynamicschronicles.ch" -Type CodeSigning -KeyUsage DigitalSignature -CertStoreLocation Cert:\CurrentUser\My -FriendlyName "dynamicschronicles" # Set a password for the private key $pw = ConvertTo-SecureString -String "complexpwd12345" -Force -AsPlainText # Export the certificate as a PFX file Export-PfxCertificate -Cert $cert -FilePath 'C:\temp\dynamicschronicles_certificate.pfx' -Password $pw Write-Host "Self-signed certificate exported as C:\temp\dynamicschronicles_certificate.pfx." # Display thumbprint $cert.Thumbprint </code></pre> <ol start="2"> <li>Copy and save the "Thumbprint" value to be used in step 5</li> </ol> <p><img alt="Thumbprint" data-entity-type="file" data-entity-uuid="e5b3e636-8b63-47f9-9b6b-0a40dc76586c" src="/sites/default/files/inline-images/thumbprint1.png" /></p> <h3>Step 4 : Create a plug-in assembly, sign it and register it</h3> <ol> <li>Create a <a href="https://learn.microsoft.com/en-us/power-apps/developer/data-platform/tutorial-write-plug-in">new plug-in using Visual Studio</a>. Here is an example of code :</li> </ol> <pre> <code class="language-cs">using Microsoft.Xrm.Sdk; using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; namespace ManagedPlugin { public class ManagedPlugin : IPlugin { public void Execute(IServiceProvider serviceProvider) { // Obtain the tracing service ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); // Obtain the execution context from the service provider. IManagedIdentityService managedIdentityService = (IManagedIdentityService) serviceProvider.GetService(typeof(IManagedIdentityService)); // Obtain the execution context from the service provider. IPluginExecutionContext context = (IPluginExecutionContext) serviceProvider.GetService(typeof(IPluginExecutionContext)); // Initialize empty token string token = string.Empty; string[] scopes = new string[] { "https://YOUR-DYNAMICS-ORG-URL.crm4.dynamics.com/.default" }; try { tracingService.Trace("Scopes in GetAccessTokenManagedIdentity: " + string.Join(", ", scopes)); token = managedIdentityService.AcquireToken(scopes); tracingService.Trace($"MANAGED IDENTITY TOKEN : {token}"); } catch (Exception ex) { tracingService.Trace($"Failed to acquire token {ex.Message}"); } var keyvaultname = "YOUR-KEYVAULT-NAME"; var secretname = "DynamicsChroniclesSecret"; // Get Token var kv_scopes = new List&lt;string&gt; { "https://vault.azure.net/.default" }; var kv_token = managedIdentityService.AcquireToken(kv_scopes); tracingService.Trace($"KV TOKEN : {kv_token}"); var keyvaultsecretUrl = $"https://{keyvaultname}.vault.azure.net/secrets/{secretname}?api-version=7.4"; try { using (HttpClient client = new HttpClient()) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", kv_token); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var request = new HttpRequestMessage(HttpMethod.Get, new Uri(keyvaultsecretUrl)); var response = client.SendAsync(request).Result; string json = response.Content.ReadAsStringAsync().Result; var keyVaultResponse = System.Text.Json.JsonSerializer.Deserialize&lt;KeyVaultResponse&gt;(json); tracingService.Trace($"KV SECRET VALUE : {keyVaultResponse.value}"); } } catch (Exception ex) { tracingService.Trace($"Failed to acquire token {ex.Message}"); } } } } public class KeyVaultResponse { public string value { get; set; } public string id { get; set; } } </code></pre> <ol start="2"> <li>Replace the following values with yours <ol> <li>Line 27 =&gt; "https://YOUR-DYNAMICS-ORG-URL.crm4.dynamics.com/.default"</li> <li>Line 40 =&gt; "YOUR-KEYVAULT-NAME" (name of the key vault created in step 2)</li> </ol> </li> <li>Build the plugin</li> <li>Sign the plugin using <a href="https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe">signtool</a> and the following Powershell command</li> </ol> <pre> <code>.\signtool sign /f "C:\temp\dynamicschronicles_certificate.pfx" /p "complexpwd12345" "C:\Path_to_your_plugin\bin\Debug\ManagedPlugin.dll"</code></pre> <ol> <li><a href="https://learn.microsoft.com/en-us/power-apps/developer/data-platform/tutorial-write-plug-in#register-plug-in">Register the plug-in</a> and register a new step (i.e. create of account)</li> </ol> <h3>Step 5 : Configure federated identity credentials</h3> <ol> <li>Open the User Assigned Managed Identity created in step 1</li> <li>Navigate to "Settings/Federated credentials" and click on "Add Credential"</li> </ol> <p><img alt="Federated Credentials" data-entity-type="file" data-entity-uuid="fb29314e-d517-45ab-b09c-9c7d8183cd89" src="/sites/default/files/inline-images/FederatedCredentials_0.png" /></p> <ol start="3"> <li>Select "Other" for "Federated credential scenario"</li> <li>Set "Issuer" = https://[Dynamics environment ID prefix].[Dynamics environment ID suffix].environment.api.powerplatform.com/sts <ol> <li>Replace "[Dynamics Environment ID prefix]" with your environment ID <span style="color:#c0392b;">(except the last two characters and without dashes)</span></li> <li>Replace "[Dynamics Environment ID suffix]" with the two last characters of the environment ID</li> </ol> </li> <li>Set "Subject identifier" = component:pluginassembly,thumbprint:[Thumbprint],environment:[Dynamics environment ID] <ol> <li>Replace "[Thumbprint]" with Thumbprint value copied in step 2 </li> <li>Replace "[Dynamics environment ID]" with your environment ID (with dashes)</li> </ol> </li> <li>Set "Name" to whatever you want</li> <li>For "Audience", you can keep the default value</li> </ol> <p><img alt="Environment ID" data-entity-type="file" data-entity-uuid="8e2ed5e8-d8d5-45c7-a3c6-e6e2cdb66053" src="/sites/default/files/inline-images/EnvironmentID.png" /></p> <p><img alt="Federated Credentials" data-entity-type="file" data-entity-uuid="0331c265-af66-4a9d-b593-c229f522bff8" src="/sites/default/files/inline-images/FederatedCredentials1_0.png" /></p> <ol start="8"> <li>Click on "Add" to create the Federated Credential</li> </ol> <h3>Step 6 : Create managed identity record in Dataverse</h3> <ol> <li>Open <a href="https://www.xrmtoolbox.com/">"XRMToolbox"</a> and open the tool <a href="https://www.xrmtoolbox.com/plugins/Driv.XTB.PluginIdentityManager/">"Plugin Identity Manager"</a> (you can also create it manually if you want, see documentation <a href="https://learn.microsoft.com/en-us/power-platform/admin/set-up-managed-identity#create-managed-identity-record-in-dataverse">here</a>)</li> <li>Select your plugin assembly (1)</li> <li>Click on "Link to New Identity"</li> </ol> <p><img alt="Plugin Managed Identity" data-entity-type="file" data-entity-uuid="ac3a181c-b8e4-45c7-b318-2c925e6e13e6" src="/sites/default/files/inline-images/plugin_identity1.png" /></p> <ol start="3"> <li>Fill in the following information and click on "Create and Link" <ol> <li>ApplicationId = "Client ID" value of your managed identity copied in step 1</li> <li>TenantId = Your tenant Id (Directory ID in Azure)</li> </ol> </li> </ol> <p><img alt="Plugin Managed Identity" data-entity-type="file" data-entity-uuid="abecf5db-9e86-4cb9-a3c2-67fee74f336f" src="/sites/default/files/inline-images/plugin_identity2_0.png" /></p> <h2>Verification</h2> <p>Good news ! You're ready to go and check if everything is working well. To do so:</p> <ol> <li>Trigger your plugin. In our case, it will be the creation of an account</li> <li>Open Plugin Trace Log and check the plugin execution and if the secret is correctly retrieved</li> </ol> <p><img alt="Plugin Trace Logs" data-entity-type="file" data-entity-uuid="6d0ec0ce-be69-4d48-b97a-e4747971b3e8" src="/sites/default/files/inline-images/plugintrace1.png" /></p> <p> </p> <p>Everything is working well — we are now able to connect and retrieve secrets from Key Vault without having to store or manage any credentials in Dataverse.</p> <p>I hope this step-by-step guide was clear and helped you configure everything easily on your end. If that’s not the case or if any steps need further clarification, please let me know in the comments.</p> </div> </div> <div class="field field--name-field-image field--type-image field--label-above"> <div class="field__label">Image</div> <div class="images-container clearfix"> <div class="image-preview clearfix"> <div class="image-wrapper clearfix"> <div class="field field--name-field-image field--type-image field--label-above field__item">/sites/default/files/2025-07/article.png</div> </div> </div> </div> </div> Thu, 17 Jul 2025 12:47:18 +0000 julien.biedermann 810 at https://dynamics-chronicles.com Managed Identities from Azure to Dataverse https://dynamics-chronicles.com/article/managed-identities-azure-dataverse <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">Managed Identities from Azure to Dataverse</span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/joaoneto" lang="" about="/user/joaoneto" typeof="schema:Person" property="schema:name" datatype="" class="username">joao.neto</a></span> <span property="schema:dateCreated" content="2024-08-29T12:48:14+00:00" class="field field--name-created field--type-created field--label-hidden">Thu, 08/29/2024 - 14:48</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><h1>Introduction</h1> <blockquote> <p>A common challenge for developers is the management of secrets, credentials, certificates, and keys used to secure communication between services</p> </blockquote> <p>One common practice while designing and architecturing authentication for Apps in the Azure Universe is the use of a App Registration as a controlled way to securely access resources in the the Azure universe and it's been for the last years a common pattern in my designs, perhaps yours also!</p> <p>And if there would be another way of securing access to the Dataverse web services without the need to manage the complexity of secrets, credentials or certificates ?</p> <img alt="App Registration architecture" data-entity-type="file" data-entity-uuid="840fe20b-bef1-4744-9d9a-97354db7d2bc" height="264" src="/sites/default/files/inline-images/Diagram01.png" width="615" class="align-center" /> <h1>What are</h1> <h5>Managed Indentities</h5> <blockquote> <p>Managed identities eliminate the need for developers to manage credentials</p> </blockquote> <p>Managed identities provides automatically a managed identity in Microsoft Entra ID for applications to use when connecting to resources that support Microsoft Entra authentication.</p> <p>Azure Managed Identities are a feature of Azure Active Directory (Azure AD) that allows Azure services to authenticate to other Azure services securely without storing credentials in code or configuration files. They are essentially service principals managed by Azure, providing an identity for applications to use when connecting to resources that support Azure AD authentication.</p> <p><strong>Types of Managed Identities:</strong><br /> <strong>System-Assigned Managed Identity</strong>: This identity is enabled directly on an Azure service instance. Azure automatically manages the lifecycle of this identity, and it's tied to the lifecycle of the service instance. When the resource is deleted, the identity is also deleted.</p> <p><strong>User-Assigned Managed Identity:</strong> Created as a standalone Azure resource, this identity can be assigned to one or more Azure service instances. It exists independently of the resources its assigned to, allowing greater flexibility and reusability.</p> <p> </p> <p><strong>Benefits of Using Managed Identities:</strong></p> <p>Applications can use managed identities to obtain Microsoft Entra ID tokens without having to manage any credentials and:</p> <ul> <li>You don't need to manage credentials. Credentials aren’t even accessible to you.</li> <li>You can use managed identities to authenticate to any resource that supports Microsoft Entra authentication, including your own applications.</li> <li>Managed identities can be used at no extra cost.</li> </ul> <h1>How to use them</h1> <p>To show how to use managed identities to authenticate an Azure app managed by Azure Entra ID into other Azure Entra ID managed resource I'll use the scenario of an Azure Function that access Dataverse to create a contact.</p> <p>The following diagram show us the intended scenario.</p> <img alt="Managed Identity architecture" data-entity-type="file" data-entity-uuid="90214dfb-9e2f-4f82-be7a-14b001046976" height="375" src="/sites/default/files/inline-images/Diagram02.png" width="555" class="align-center" /> <p><strong>1- Create Managed Identity</strong></p> <p>Let's create a managed identity and for that I got another good news that's we don't need to have Entra ID management permissions to create a new one just collaboration on a Azure Resource.</p> <ul> <li>In a resource group lets create a new managed identity: <ul> <li><img alt="Managed Identity creation" data-entity-type="file" data-entity-uuid="94ec1a93-411c-42c9-abcf-7eff9fa5fc1d" height="413" src="/sites/default/files/inline-images/ManagedIdentCreation01.png" width="347" /></li> </ul> </li> <li>Once created get the generated "Client ID"  <ul> <li><img alt="Managed Identity creation " data-entity-type="file" data-entity-uuid="883f4d82-bd2d-445d-94d4-61f08e4b3cee" height="145" src="/sites/default/files/inline-images/ManagedIdentCreation02.png" width="747" /></li> </ul> </li> </ul> <p><strong>2- Configure Power Apps</strong></p> <ul> <li>Go to the Power Platform admin center</li> <li>Then the "Application Users" and select "New app user"</li> <li>Use the "Client ID" from the previous step to find the app, <strong>because managed identities aren't displayed yet by default!</strong> <ul> <li><img alt="Power Platform configuration" data-entity-type="file" data-entity-uuid="371dd245-d25b-43f3-a209-4969750b9c8f" height="216" src="/sites/default/files/inline-images/PowerPlatform01.png" width="337" /></li> </ul> </li> <li>Then complete with the Business Unit (use a custom one) and the Security Roles (use a custom one).   <ul> <li><img alt="Power Platform configuration" data-entity-type="file" data-entity-uuid="7caf3162-4daf-4581-a84d-6f239d13eeea" height="376" src="/sites/default/files/inline-images/PowerPlatform02.png" width="391" /></li> </ul> </li> </ul> <p><strong>3- Azure Function</strong></p> <p>Now its time to create our Azure Function that will authenticate in Dataverse using the managed identity!</p> <ul> <li>For this purpose I've created an Azure HTTP Function in a consumption plan</li> <li>Then I've used the following code to authenticate in Dataverse:</li> <li> <pre> <code class="language-cs"> var tokenCredential = new DefaultAzureCredential(); var ConfigServiceDataverseURI = new Uri("https://yyyyyyy.crm4.dynamics.com"); log.LogInformation("ConfigServiceDataverseURI: " + ConfigServiceDataverseURI); var serviceClient = new ServiceClient(ConfigServiceDataverseURI, async (string dataverseUri) =&gt; { dataverseUri = new Uri(dataverseUri).GetComponents(UriComponents.SchemeAndServer, UriFormat.UriEscaped); return (await tokenCredential.GetTokenAsync(new TokenRequestContext(new[] { dataverseUri }), default)).Token; }, true); </code></pre> </li> <li>And then the create account record part </li> <li> <pre> <code class="language-cs">try { if (!serviceClient.IsReady) throw new Exception("Authentication Failed!"); Random random = new Random(); int randomNumber = random.Next(100000, 999999 + 1); log.LogInformation("randomNumber " + randomNumber); var registration = new Entity("contact"); registration["firstname"] = "model.FirstName - " + randomNumber; registration["lastname"] = "model.LastName"; serviceClient.Create(registration); } catch (Exception ex) { log.LogError(ex.Message); }</code></pre> </li> <li>Now lets configure a User assigned Managed Identity for our Azure Function with the created Managed Identity in the step 1</li> </ul> <img alt="Configure Azure Function" data-entity-type="file" data-entity-uuid="2d0bedc7-fa65-40ec-8039-335f62027a9c" height="238" src="/sites/default/files/inline-images/ConfigureAzureFonction.png" width="943" class="align-center" /> <ul> <li>And then add to the Environmental variables the "AZURE_CLIENT_ID" with the created Managed Identity client ID in the step 1</li> </ul> <img alt="Configure Azure Function" data-entity-type="file" data-entity-uuid="de030749-15f5-482a-a1fe-1ec169f47814" height="192" src="/sites/default/files/inline-images/ConfigureAzureFonction01.png" width="506" class="align-center" /> <ul> <li>Publish you Azure Function and test it, contacts are created without any secret or certificate!</li> <li><img alt="Create Contacts" data-entity-type="file" data-entity-uuid="3f20ec4d-bf2d-4e48-b640-aab874fcbe6d" height="220" src="/sites/default/files/inline-images/Create.Contacts.png" width="525" class="align-center" /></li> </ul> <p>One point that needs attention is that in my example I'm using the DefaultAzureCredential that allows our code to use the credential use locally, in another words it allows to run and debug the code locally.</p> <p>Either the way using the DefaultAzureCredential will have our application to search for the credentials using the following pipeline (order):</p> <ul> <li>EnvironmentCredential, </li> <li>ManagedIdentityCredential, </li> <li>SharedTokenCacheCredential, </li> <li>VisualStudioCredential, </li> <li>VisualStudioCodeCredential, </li> <li>AzureCliCredential, </li> <li>AzurePowerShellCredential, </li> <li>InteractiveBrowserCredential</li> </ul> <p>Using the ManagedIdentityCredential will make our code to directly use the Managed Identity declared in our Azure resource.</p> <h1>Why to Use it</h1> <p>Azure Managed Identities provide a secure and streamlined way to authenticate Azure resources with Dataverse, eliminating the need for manual credential management.</p> <p>By leveraging Managed Identities, developers can enhance security, simplify configuration, and reduce the overhead associated with traditional authentication methods</p> <p><strong>Comparison with App Registration Authentication</strong><br /> While both Managed Identities and App Registrations can be used for authenticating with Dataverse, there are significant differences:</p> <p>Managed Identity: Credentials are automatically managed by Azure, removing the need for manual handling and reducing the risk of credential leaks.</p> <p><strong>Lifecycle and Scope</strong></p> <p>App Registration: Exists independently within Azure AD and can be used by applications running anywhere, including outside Azure.<br /> Managed Identity: Tied to an Azure resource (system-assigned) or managed as a resource (user-assigned). Primarily intended for use within Azure.</p> <p><strong>Security</strong></p> <p>App Registration: Higher risk due to manual credential management. If credentials are compromised, it can lead to unauthorized access.<br /> Managed Identity: Provides enhanced security by avoiding hard-coded credentials, and the credentials are not accessible to developers or users.</p> <p><strong>Complexity</strong></p> <p>App Registration: Involves more steps to set up, including creating the app registration, generating secrets or certificates, and configuring permissions.<br /> Managed Identity: Simpler to configure, with Azure handling the creation and rotation of credentials automatically.</p> <p> </p> <p><strong>In summary</strong></p> <p>Azure Managed Identities offer a more secure and easy approach for authenticating Azure resources with Dataverse compared to App Registrations.</p> <p>They are ideal for applications running within Azure that require secure access to other Azure resources without the overhead of managing credentials.</p> <p>However, App Registrations are still very relevant for scenarios where applications run outside of Azure or require specific access scopes.</p> </div> </div> <div class="field field--name-field-image field--type-image field--label-above"> <div class="field__label">Image</div> <div class="images-container clearfix"> <div class="image-preview clearfix"> <div class="image-wrapper clearfix"> <div class="field field--name-field-image field--type-image field--label-above field__item">/sites/default/files/2024-11/icon.png</div> </div> </div> </div> </div> Thu, 29 Aug 2024 12:48:14 +0000 joao.neto 811 at https://dynamics-chronicles.com Power Platform Dataflow Tutorial Deep Dive https://dynamics-chronicles.com/article/power-platform-dataflow-tutorial-deep-dive <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">Power Platform Dataflow Tutorial Deep Dive</span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/stephane-pelhatre" lang="" about="/user/stephane-pelhatre" typeof="schema:Person" property="schema:name" datatype="" class="username">Stephane Pelhatre</a></span> <span property="schema:dateCreated" content="2024-06-17T12:35:36+00:00" class="field field--name-created field--type-created field--label-hidden">Mon, 06/17/2024 - 14:35</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><p><em>Power Platform Dataflow Tutorial Deep Dive</em></p> <h2>Introduction</h2> <p>Dataflows are a self-service, cloud-based, data preparation technology. Dataflows enable customers to ingest, transform, and load data into Dataverse environments, Power BI workspaces, or an organization's Azure Data Lake Storage account.<br /> Dataflows are authored by using Power Query, a unified data connectivity and preparation experience already featured in many Microsoft products, including Excel and Power BI.<br /> Customers can trigger dataflows to run either on demand or automatically on a schedule.</p> <p>Dataflows are featured in multiple Microsoft products and don't require a dataflow-specific license to be created or run. They are available in Power Apps, Power BI, and Dynamics 365 Customer Insights.</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="b015a862-560c-4d05-8ef8-59f2003813ee" src="/sites/default/files/inline-images/dataflow-function_0.png" /></p> <p>The previous image shows an overall view of how a dataflow is defined.<br /> A dataflow gets data from different data sources.<br /> Then, based on the transformations configured with the Power Query editor, the dataflow transforms the data by using the dataflow engine.<br /> Finally, data are loaded to the output destination, which can be a Power Platform environment, a Power BI workspace, or the organization's Azure Data Lake Storage account.</p> <p>Dataflows are cloud-based. A dataflow is stored and runs in the cloud. However, if a data source is on-premises, an on-premises data gateway can be used to extract the data to the cloud.</p> <p>Power Query is the data transformation engine used in dataflow. This engine supports many transformations. It also uses a graphical user interface called Power Query Editor.</p> <p>In this article we will study the use of dataflow in the Power Platform through a tutorial.</p> <h2>Dataflow in practice</h2> <p>In this tutorial we will import a CSV file into a Dataverse custom table.</p> <h3>Create a dataflow</h3> <p>To create a dataflow just go to make.powerapps.com on your Power Platform environment and select 'Dataflows' in the left pane.<br /> Then click on '+ New dataflow' on the top.</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="f058575d-d04f-413b-baeb-ba011da864e2" src="/sites/default/files/inline-images/powerapps.png" /></p> <p>You will get the following screen:</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="cecb17d4-5335-4e50-a572-f988c10b1094" src="/sites/default/files/inline-images/firsst%20screen_0.png" /></p> <p>I named my dataflow 'Import persons'.</p> <p>If you want to load data to an Azure data lake for analytical purposes check 'Analytical entities only'.<br /> In this tutorial I leave the checkbox unchecked as I want to load data into a Dataverse table.</p> <h3>Data sources</h3> <p>First step is to select a data source.<br /> Around 50 data sources are available as you can see below.</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="6ba0eb96-fe18-4606-9edf-79aaeca798b4" src="/sites/default/files/inline-images/sources_0.png" /></p> <p>Main types of source:</p> <ul> <li><strong>Files </strong>: Excel, Text/CSV, XML/JSON, ...</li> <li><strong>Databases </strong>: SQL Server, Oracle, MySQL, PostgreSQL, ...</li> <li><strong>Azure </strong>: Azure SQL Database, Synapse Analytics, Blobs, Data Lake Storage Gen2, ...</li> <li><strong>Online services</strong> : Sharepoint, Exchange, Google Analytics, ...</li> </ul> <p>In this tutorial I will use a CSV file. You can directly drag&amp;drop your file in the interface.</p> <p><img alt="Excel_connect" data-entity-type="file" data-entity-uuid="e62f4ac0-7ba2-43f9-bdaf-20fa78f64f44" src="/sites/default/files/inline-images/Excel%20connection.png" /></p> <p>You get a preview of your file. Then click on 'Transform Data'.</p> <p><img alt="excel preview" data-entity-type="file" data-entity-uuid="24168957-2b84-4873-9627-c13313eec1b3" src="/sites/default/files/inline-images/excel%20preview_1.png" /></p> <h3>Data filtering</h3> <p>You get the screen of Power Query Editor</p> <p>At the top we have the formula bar (as in Excel or Power-fx). We will see in this article that we can display the current formula, the full script or hide this formula bar.<br /> Below you can see your data.<br /> And on the right side we have the 'Applied steps' pane with all steps/actions performed. It's a little empty because we've just started, but don't worry it will fill up:</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="4c6a78c7-0022-4905-ba0a-cc3a84f41852" src="/sites/default/files/inline-images/screen%20home_0.png" /></p> <p>We have several tabs:</p> <ul> <li><strong>Home </strong>: functionalities to filter data and some features of other tabs</li> <li><strong>Transform</strong>: data transformations</li> <li><strong>Add column</strong>: add a new column to apply a transformation</li> <li><strong>View </strong>: display settings</li> </ul> <p>In this tutorial I first click on 'Use first column as headers' in the ribbon as the first line of my CSV file contains column names.</p> <p>The tab 'Home' contains several interesting features: for instance you can filter rows.<br /> To perform that action you first have to select a column and then click on the button 'Filter Rows'.<br /> Another interesting feature is the possibility to remove duplicates.<br /> As previously you first have to select a column and then click on the command 'Remove duplicates' in the menu 'Remove rows'.<br /> In my example I apply this command on the column <em>LastName </em>: we can see in the screenshot below that we have a duplicate in this column (raley - lines 1 and 4)</p> <p><img alt="remove dup" data-entity-type="file" data-entity-uuid="380cf750-ea01-41b0-92be-a2997f4b2b53" src="/sites/default/files/inline-images/remove%20duplicates_0.png" /></p> <p>And we obtain the expected result:</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="fc94d39b-daf2-480d-a3ee-384c1480903e" src="/sites/default/files/inline-images/duplicates2_1.png" /></p> <p>You can also remove blank rows or lines with errors.</p> <h3>Transformations</h3> <p>When you have filtered your data you can now apply some transformations.<br /> Click on 'Transform' tab. You will get a ribbon dedicated to transformation features.</p> <p><br /> <img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="ccb08364-224e-40fa-9768-30ac32d89849" src="/sites/default/files/inline-images/ribbon%20transformation.png" /></p> <p>You can perform many data transformations. This is a non-exhaustive list of transformation features:</p> <ul> <li>Transform any column: <ul> <li>Replace values</li> <li>Change type</li> <li>Detect data type</li> <li>Mark column as key</li> <li>Rename column</li> <li>Pivot/Unpivot columns</li> <li>Fill up/down</li> <li>Move column</li> </ul> </li> <li>Transform text column <ul> <li>Split (by delimiter, number of characters, lower/upper case and more)</li> <li>Format (lower/upper case capitalize words, trim, clean and more)</li> <li>Extract (length, first/last characters, range and more)</li> <li>Statistics (count/distinct values)</li> </ul> </li> </ul> <p>As a first example let's remove the characters 'xxx' in the column <em>Firstname</em> (in <em>rickiexxx </em>or <em>xxxryan</em>).<br /> Select column <em>Firstname </em>and then select the command 'Replace values...' in the menu 'Replace values'<br /> In my example I want to remove 'xxx' so I leave 'Replace with' empty.</p> <p><img alt="replace values" data-entity-type="file" data-entity-uuid="be4509a6-65d9-4878-a775-145e7dfb169e" src="/sites/default/files/inline-images/replace%20values.png" /></p> <p>And we obtain the expected result:</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="7f6ae239-1fd6-47d7-bae0-a58e53cb276f" src="/sites/default/files/inline-images/result%20replace%202.png" /></p> <p>Note that at the top in the formula bar you can see the source code (Power Query M) of the last command :<br /> <em>Table.ReplaceValue(#"Removed duplicates", "xxx", "", Replacer.ReplaceText, {"Firstname"})</em></p> <p>Now let's change data type of column <em>Age. </em>It is currently a text column and I will change it to a whole number column.<br /> We can see that in line 3 the column <em>Age </em> contains 'abc' : let's say that it is an error as this column should contain only whole numbers.<br /> So I first select column <em>Age </em>and then in the menu 'Data type' I select the item 'Whole number'.<br /> This is the result:</p> <p><img alt="age1" data-entity-type="file" data-entity-uuid="90b74c27-8d2a-4a56-abbf-c3cf73bfd6a3" src="/sites/default/files/inline-images/age1_0.png" /></p> <p>We get an error in line 3. This makes sense as original data 'abc' is not a number.<br /> To solve this problem I select the column <em>Age </em>and select the command 'Replace errors...' in the menu 'Replace values'.<br /> In my example I set value to 99</p> <p><img alt="replace errors" data-entity-type="file" data-entity-uuid="2be1d771-af22-4e71-9b96-34f46be971e2" src="/sites/default/files/inline-images/replace%20errors_0.png" /></p> <p>And I get the expected result:</p> <p><img alt="age2" data-entity-type="file" data-entity-uuid="af77d668-356f-47e6-b7a7-37c67ec48948" src="/sites/default/files/inline-images/age2_0.png" /></p> <p>The menu 'Format' contains several interesting commands:</p> <p><img alt="format" data-entity-type="file" data-entity-uuid="a3dd1341-bf74-4b70-91b0-5ab8501420a0" src="/sites/default/files/inline-images/format.png" /></p> <p>We have the classic commands lowercase, uppercase, trim.<br /> But we also have the nice command 'Capitalize Each Word' (first letter of each word converted into an uppercase letter) and the command 'Clean' that removes all non-printable characters.</p> <p>Now I apply the command 'Capitalize Each Word'  on column <em>FirstName </em>and the command UPPERCASE on the column <em>Lastname</em>.<br /> This is the result:</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="7ccc9ad2-5e76-436b-a904-f46a0f689b68" src="/sites/default/files/inline-images/uppercase.png" /></p> <h3>Add new column</h3> <p>Click on 'Add column' tab, you will get a ribbon dedicated to new columns.</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="6d5cb8ca-3fb9-4068-acc5-1879e65439ad" src="/sites/default/files/inline-images/ribbon_column.png" /></p> <p>With commands in tab 'Transform' you apply the transformation to the original column (in-place) as we have seen previously.<br /> Commands in tab 'Add column' store the result of the transformation in a new column.<br /> The menu 'Format' we used previously in tab 'Transform' is also in tab 'Add column'.<br /> But if you use one the commands (for instance UPPERCASE) you will see that a new column is created.</p> <p>With the command 'Custom column' you add a new column but you cannot select a built-in command : you have to write your code (formula) in Power Query M language.</p> <p>As an example, let's create a column <em>Fullname </em>that concatenates columns <em>Firstname </em>and <em>Lastname </em>separated by a comma.<br /> Click on the command 'Custom column' and set the parameters:</p> <ul> <li>New column name : <em>Fullname</em></li> <li>Datatype : Text</li> <li>Custom column formula: I use the Power Query M function<em>Text.Combine()</em> with the 2 columns <em>Firstname </em>and <em>Lastname </em>and comma as separator<br /> You only have to type your function in the editor and click on fields in the section 'Available columns(s)' on the right to add the columns to the formula.</li> </ul> <p><img alt="combine" data-entity-type="file" data-entity-uuid="8c5abc3b-2ee0-4426-ac14-438c24265068" src="/sites/default/files/inline-images/combine_0.png" /></p> <p>And we obtain the expected result:</p> <p><img alt="combine2" data-entity-type="file" data-entity-uuid="9e20a444-41ce-4e78-bc06-466bceac4907" src="/sites/default/files/inline-images/combine2_1.png" /></p> <p>Another interesting feature is <strong>Conditional column</strong> : with this feature you can create new columns whose values are based on one or more conditions applied to other columns.</p> <p>Let's create a conditional column named 'Is too young' : the result will be set to TRUE is Age &lt; 18 otherwise result will be FALSE.</p> <p>You just have to click on the command 'Conditional column' and fill the data as below.</p> <p><img alt="condition_column" data-entity-type="file" data-entity-uuid="c87fed9d-e781-42db-896b-e358b9c8d9cc" src="/sites/default/files/inline-images/condtional_column.png" /></p> <p>In my example I use a static value (18) but it is possible to specify another column as value.</p> <p>And this is the result:</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="b596d6c6-b146-4882-92a1-6c4fcd6152fd" src="/sites/default/files/inline-images/too%20young.png" /></p> <p>And now I change the data type of column 'Is too young'. I select the command 'Detect data type' in tab 'Transform': it automatically detects the best data type for the selected column.</p> <p><img alt="detect type" data-entity-type="file" data-entity-uuid="a90d0dd0-0c56-4912-a698-a9d814051c23" src="/sites/default/files/inline-images/detect%20date%20type_1.png" /></p> <p>As this column contains only strings 'TRUE' or 'FALSE' the best data type is logical true/false (boolean).<br /> And as you can see below it worked : the icon in the header of the column has changed to indicates that the column is now a logical column.</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="517dc8b0-b942-4e29-9cc8-459f4b507bc1" src="/sites/default/files/inline-images/datatype2_1.png" /></p> <h3>'Applied steps' pane</h3> <p>And what about the 'Applied steps' pane on the right side?<br /> It displays all the steps executed until now.</p> <p>If you want to view the content of a specific step, simply click on the gear wheel on the right.<br /> To remove a step click on the cross on the left.</p> <p><img alt="view_step" data-entity-type="file" data-entity-uuid="3de1e405-dab0-4643-a5e1-13730e31fc38" src="/sites/default/files/inline-images/view_step_0.png" /></p> <p>If you right-click on a step you access a context menu : rename the step, insert a new step, move the step, ...</p> <p><img alt="context menu" data-entity-type="file" data-entity-uuid="c5878b5f-34e9-4671-a2e2-d818eb5ab74d" src="/sites/default/files/inline-images/context%20menu%20step_0.png" /></p> <p>At the bottom of the pane you have a menu 'Step'. If you click on it you will have 3 choices: Off, Query script, Step script (default).<br /> This defines what is displayed in the formula bar.</p> <p><img alt="viewstep2" data-entity-type="file" data-entity-uuid="152237f2-e61b-42c4-ab06-088f83430a34" src="/sites/default/files/inline-images/view_step2.png" /></p> <p>'Off' : hide the formula bar</p> <p>'Step script' : display in the formula bar the formula (code M) of the selected step.</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="098112cb-34c6-42be-9c83-2fade00a9d53" src="/sites/default/files/inline-images/formula_2.png" /></p> <p>'Query script' : display in the formula bar the full script (all steps).</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="a84d199b-0bde-4074-b90f-33c93c4180f2" src="/sites/default/files/inline-images/view_step3_0.png" /></p> <p>Next to the 'Step' button there is 'Diagram view' button. It displays in the formula bar the diagram of all steps.</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="ce576561-2b0e-4964-9290-ca9db9d8003a" src="/sites/default/files/inline-images/diag1_1.png" /></p> <p>If you click on the '+' in the diagram a context menu is displayed : you can filter data, add a step, etc...</p> <p><img alt="diag2" data-entity-type="file" data-entity-uuid="e8f79485-3f06-4827-b9ce-eedf0b6461bd" src="/sites/default/files/inline-images/view_diagram2.png" /></p> <p>The 'View' tab contains several display settings including those we have just seen (step script, query script, diagram view),</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="0678e527-04e8-4252-981b-aa4c3ceb7262" src="/sites/default/files/inline-images/view%20tab.png" /></p> <h3>Importing data into Dataverse</h3> <p>When you have finished applying transformations to you data you can click on button 'Next' at the bottom of the screen and move to next step to import transformed data into a Dataverse table.</p> <p>You can choose whether you want to load data into a new table or an existing one.<br /> In my example I create a new table <em>Person</em>.<br /> To do that simply name the table and choose which column is your unique primary column.<br /> An automatic mapping is performed.</p> <h3><img alt="export" data-entity-type="file" data-entity-uuid="c049226c-9d49-4b0f-95ff-1c1ad1bbf1ee" src="/sites/default/files/inline-images/export%20dataverse_0.png" /></h3> <p>Then click on 'Publish'.<br /> If the publish is successful you get the following screen:</p> <p><img alt="export2" data-entity-type="file" data-entity-uuid="19d957c0-ed6a-44d4-a1cb-c7b151614908" src="/sites/default/files/inline-images/export%202.png" /></p> <p>Finally you can schedule your dataflow : click on the 3 dots '...' and select 'Edit Refresh settings'</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="cd2a7eb1-39dd-4a04-954c-c125c27af4e4" src="/sites/default/files/inline-images/schedule1.png" /></p> <p>You can run your dataflow manually or schedule it based on a specific frequency.</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="78baab5e-ed75-420d-bd24-a7c0221f669b" src="/sites/default/files/inline-images/schedule2.png" /></p> <p>Note that you can get the following message if your refresh frequency exceeds the allowed limit of 48 refreshes per day.</p> <p><img alt="Power Platform Dataflow Tutorial Deep Dive" data-entity-type="file" data-entity-uuid="31088401-e59c-41a4-9ca0-0b8967b9cb88" src="/sites/default/files/inline-images/schedule3.png" /></p> <p>And the result in the Power Platform:</p> <p><br /> <img alt="result" data-entity-type="file" data-entity-uuid="5ac53ee8-d680-40f8-a584-e7f4f1bf6980" src="/sites/default/files/inline-images/result.png" /></p> <h2>Dataflow refresh</h2> <p>Each time you refresh a dataflow, it fetches records from the source and loads data into Dataverse.<br /> If you run the dataflow more than once you can:</p> <ul> <li>Create new records for each dataflow refresh, even if such records already exist in the destination table. In this case you will create duplicates.</li> <li>Create new records if they don't already exist in the table, or update existing records if they already exist in the table. This behavior is called <em>upsert</em>.</li> </ul> <p>Using an alternate key column indicates to the dataflow to upsert records into the destination table, while not selecting a key indicates to the dataflow to create new records in the destination table.</p> <p>For instance if your data source has a column that is different for all rows (a guid or any unique identifier) you can use this column has an alternate key in your Dataverse table.</p> <p>You can get details here: <a href="https://learn.microsoft.com/en-us/power-query/dataflows/get-best-of-standard-dataflows">https://learn.microsoft.com/en-us/power-query/dataflows/get-best-of-standard-dataflows</a></p> <h2>Power Query M language</h2> <p>As mentioned previously Dataflow is based on Power Query and its related language.<br /> The Power Query editor contains many built-in commands to perform basic operations and transformations.<br /> But you will probably have to use the language to write your own transformations. It is what we call 'writing code M'.<br /> The M stands for data Mash-up, as Power Query is all about connecting to various different data sources and “Mashing” them up.<br /> The Power Query M formula language is optimized for building flexible data mashup queries. It's a functional, case sensitive language similar to F#.<br /> Power Query Formula Language is used in a number of Microsoft products such as Power BI Desktop, Excel, and Analysis Services.</p> <p>Details about Power Query M language are out of the scope of this article.<br /> Specifications of the language can be found here:<br /> <a href="https://download.microsoft.com/download/8/1/A/81A62C9B-04D5-4B6D-B162-D28E4D848552/Power%20Query%20M%20Formula%20Language%20Specification%20(July%202019).pdf">https://download.microsoft.com/download/8/1/A/81A62C9B-04D5-4B6D-B162-D28E4D848552/Power%20Query%20M%20Formula%20Language%20Specification%20(July%202019).pdf</a></p> <p>The specification describes the values, expressions, environments and variables, identifiers, and the evaluation model that form the Power Query M language’s basic concepts.</p> <p>The official reference guide : <a href="https://learn.microsoft.com/en-gb/powerquery-m/power-query-m-function-reference">https://learn.microsoft.com/en-gb/powerquery-m/power-query-m-function-reference</a></p> <p>Many categories are available:</p> <ul> <li>    Accessing data functions</li> <li>    Binary functions</li> <li>    Combiner functions</li> <li>    Comparer functions</li> <li>    Date functions</li> <li>    DateTime functions</li> <li>    DateTimeZone functions</li> <li>    Duration functions</li> <li>    Error handling</li> <li>    Expression functions</li> <li>    Function values</li> <li>    List functions</li> <li>    Lines functions</li> <li>    Logical functions</li> <li>    Number functions</li> <li>    Record functions</li> <li>    Replacer functions</li> <li>    Splitter functions</li> <li>    Table functions</li> <li>    Text functions</li> <li>    Time functions</li> <li>    Type functions</li> <li>    Uri functions</li> <li>    Value functions</li> </ul> <p>Some basics about the language:</p> <p>A Power Query M formula language query is composed of formula expression steps that create a mashup query.<br /> A formula expression can be evaluated (computed), yielding a value.<br /> The <strong>let </strong>expression encapsulates a set of values to be computed, assigned names, and then used in a subsequent expression that follows the <strong>in </strong>statement.<br /> For example, a let expression could contain a <strong>Source </strong>variable that equals the value of <strong>Text.Proper</strong>() and yields a text value in proper case.</p> <pre> <code>let Source = Text.Proper("hello world") in Source</code></pre> <p>In this tutorial we wrote a formula to concatenate first name and last name:</p> <pre> <code>Text.Combine({[Firstname],[Lastname]}, " , ")</code></pre> <p>Note that function name (Combine) is prefixed by the category name (Text).<br /> For example : <em>Date.AddMonths()</em>, <em>Splitter.SplitTextByDelimiter()</em></p> <p>Below the full script of this tutorial:</p> <pre> <code>let Source = Csv.Document(Web.Contents("https://crm315857-my.sharepoint.com/personal/admin_crm315857_onmicrosoft_com/Documents/Apps/Microsoft Power Query/Uploaded Files/example1 8.csv"), [Delimiter = ";", Columns = 3, QuoteStyle = QuoteStyle.None]), #"Promoted headers" = Table.PromoteHeaders(Source, [PromoteAllScalars = true]), #"Removed duplicates" = Table.Distinct(#"Promoted headers", {"Lastname"}), #"Replaced value" = Table.ReplaceValue(#"Removed duplicates", "xxx", "", Replacer.ReplaceText, {"Firstname"}), #"Changed column type" = Table.TransformColumnTypes(#"Replaced value", {{"Age", Int64.Type}}), #"Replaced errors" = Table.ReplaceErrorValues(#"Changed column type", {{"Age", 99}}), #"Capitalized each word" = Table.TransformColumns(#"Replaced errors", {{"Firstname", each Text.Proper(_), type nullable text}}), #"Uppercased text" = Table.TransformColumns(#"Capitalized each word", {{"Lastname", each Text.Upper(_), type nullable text}}), #"Added custom" = Table.TransformColumnTypes(Table.AddColumn(#"Uppercased text", "Fullname", each Text.Combine({[Firstname], [Lastname]}, " , ")), {{"Fullname", type text}}), #"Inserted conditional column" = Table.AddColumn(#"Added custom", "Is too young", each if [Age] &lt; 18 then true else false), #"Changed column type 1" = Table.TransformColumnTypes(#"Inserted conditional column", {{"Is too young", type logical}}) in #"Changed column type 1"</code></pre> <p>A major drawback of Power Query editor :<br /> There is no intellisense/auto-completion when you type a formula (like in Microsoft Visual Studio or with Power-fx editor).<br /> This technology is very useful when you do not know the exact name of a function.<br /> And don't forget that code M language is case sensitive: so any case error in a function name and your code will not work.</p> <h2>Mass import</h2> <p>In order to evaluate the performance I have imported to Dataverse a CSV file with 100'000 rows.<br /> <br /> Format of each row:</p> <ul> <li><em>Id </em>: incremental number (unique value in order to perform updates)</li> <li><em>Firstname </em>: string</li> <li><em>Lastname</em>: string</li> <li><em>Age </em>: integer</li> </ul> <p>Transformations applied:</p> <ul> <li>Firstname : Capitalize Each Word</li> <li>Lastname : Uppercase</li> <li>Add new column :  Fullname = Firstname , Lastname</li> </ul> <p>The Dataverse custom table has a column <em>Id </em>as primary column and  alternate key to be able to perform updates.</p> <p>I performed the import first in creation mode : import of transformed data into an empty Dataverse table.<br /> Then I performed an import in update mode : I modified all data in the CSV file (firstname/lastname/age but not Id of course) and imported transformed data in the same Dataverse table.</p> <p>Creation mode : the 100'000 transformed rows have been imported in 58 minutes.<br /> Update mode : the 100'000 transformed rows have been imported in 52 minutes.</p> <h2>Licenses</h2> <p>To create dataflows in Power Apps a license is required (per-user or per-app).</p> <p>If you want to create analytical dataflows that store data in your organization's Azure Data Lake Storage Gen2 account, you or your administrator need access to an Azure subscription and an Azure Data Lake Storage Gen2 account.</p> <h2>Limitations</h2> <ul> <li>Maximum of 48 runs per day for a dataflow</li> <li>Only one owner is currently enabled. If another user wants to modify the dataflow you must change the owner</li> <li>Mapping to polymorphic lookup fields is currently not supported.</li> <li>Mapping to <em>Status </em>and <em>Status Reason</em> fields is currently not supported.</li> <li>Mapping data into multi-line text that includes line break characters isn't supported and the line breaks get removed. Instead, you could use the line break tag &lt;br&gt; to load and preserve multi-line text</li> <li>Mapping to <strong>Choice</strong> fields configured with the multiple select option enabled is only supported under certain conditions. The dataflow only loads data to <strong>Choice</strong> fields with the multiple select option enabled, and a comma-separated list of values (integers) of the labels are used.<br /> For example, if the labels are "Choice1, Choice2, Choice3" with corresponding integer values of "1, 2, 3", then the column values should be "1,3" to select the first and last choices.</li> </ul> <h2 class="title">Power Platform Dataflow Tutorial Deep Dive</h2> </div> </div> <div class="field field--name-field-image field--type-image field--label-above"> <div class="field__label">Image</div> <div class="images-container clearfix"> <div class="image-preview clearfix"> <div class="image-wrapper clearfix"> <div class="field field--name-field-image field--type-image field--label-above field__item">/sites/default/files/2024-06/Designer.jpeg</div> </div> </div> </div> </div> Mon, 17 Jun 2024 12:35:36 +0000 Stephane Pelhatre 785 at https://dynamics-chronicles.com Azure Peering Service for Dataverse https://dynamics-chronicles.com/article/azure-peering-service-dataverse <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">Azure Peering Service for Dataverse</span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/joaoneto" lang="" about="/user/joaoneto" typeof="schema:Person" property="schema:name" datatype="" class="username">joao.neto</a></span> <span property="schema:dateCreated" content="2024-04-03T12:43:58+00:00" class="field field--name-created field--type-created field--label-hidden">Wed, 04/03/2024 - 14:43</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><p><em>Azure Peering Service for Dataverse:</em></p> <h2><strong>Introduction</strong></h2> <p><span><span>Requirements for Enterprise cloud services access are constantly evolving in terms of number of connections/users, data payload, multi-region/multi-continent access, .... </span></span></p> <p><span><span>To overcome this different types of Enterprise architectures are often used : Geo-Partitioned/Hybrid-Cloud/Global load balancing/CDN architectures.</span></span></p> <p><span><span>Nonetheless one question remains, how to enhance and improve network performance between Enterprise office locations and Microsoft cloud services? </span></span></p> <img alt="Azure Peering Service for Dataverse" data-entity-type="file" data-entity-uuid="e3ad4c17-26b0-4cf7-8feb-193bb5223f1c" height="193" src="/sites/default/files/inline-images/MAPS_Problem.png" width="431" class="align-center" /> <p><span><span>Microsoft says that MAPS, Microsoft Azure Peering Service</span></span>, is one of the answers.</p> <h2>What is</h2> <blockquote>A straightforward and easy way to establish direct peering with Microsoft</blockquote> <p>MAPS is a service that enhances the connectivity to Microsoft cloud services such as Microsoft 365, Dynamics 365, software as a service (SaaS) services, Azure, or any Microsoft services accessible via the public internet.</p> <p>It uses a partnership between ISP's, IXP's and SDCI providers worldwide to provide optimal routing and high-performing connectivity between Enterprise office locations and Microsoft cloud services.</p> <img alt="Azure Peering Service for Dataverse" data-entity-type="file" data-entity-uuid="d79122bc-0b42-430e-81ad-ab537f127965" src="/sites/default/files/inline-images/MAPS.arch1_.png" class="align-center" /> <h4>How it works</h4> <p>Microsoft 365, Dynamics 365, and any other Microsoft SaaS services are hosted in multiple Microsoft datacenters and can be accessed from any geographic location.</p> <p>The Microsoft global network has Microsoft Edge point-of-presence (PoP) locations around the world where it can connect to an end user via their service providers.</p> <img alt="Azure Peering Service for Dataverse" data-entity-type="file" data-entity-uuid="7e3814d2-503b-49ff-a229-48ddd028b649" height="349" src="/sites/default/files/inline-images/peering-service-background-final.png" width="537" class="align-center" /> <p>Microsoft and partner service providers ensure that the traffic for the prefixes registered with a Peering Service connection enters and exits the nearest Microsoft Edge PoP locations on the Microsoft global network.</p> <p>Microsoft ensures that the networking traffic egressing from the prefixes registered with Peering Service connections takes the nearest Microsoft Edge PoP locations on the Microsoft global network (Cold-Potato routing).</p> <h2><span style="font-weight:bold">Why use it</span></h2> <ul> <li> <p>If Microsoft services performance are business critical to an Enterprise</p> </li> <li> <p>To provide the shortest path (optimal routing) to Microsoft SaaS products, including Dynamics 365, Microsoft 365, Azure and all Microsoft services accessible from the public Internet</p> </li> <li> <p>Avoid the enormous hops between Enterprise office locations and Microsoft</p> </li> <li> <p>Geo-Redundancy: Microsoft’s interconnected service providers across multiple metro locations allow traffic to reroute via alternate sites if an Edge node experiences performance degradation</p> </li> <li> <p>Monitoring Platform: Service monitoring analyzes user traffic and routing using Microsoft Telemetry</p> </li> <li> <p>Redundancy: With primary and secondary connections, redundancy ensures reliability</p> </li> <li> <p>Route Analytics: Events related to BGP route anomalies (leak or hijack detection) and suboptimal routing are tracked</p> </li> <li> <p>Often in the Peering service partners offer but not in the Microsoft Peering service:</p> <ul> <li> <p>Integrated distributed denial-of-service (DDos) protection</p> </li> <li> <p>Traffic isolated from the public Internet</p> </li> <li> <p>SLA's to ensure service availability</p> </li> </ul> </li> </ul> <h2><span style="font-weight:bold">How to use it</span></h2> <p>In what concerns the technical management of the Peering services Microsoft has services available on the following 3 platforms:</p> <ul> <li>Azure Portal</li> <li>Azure PowerShell</li> <li>Azure CLI</li> </ul> <p>Before getting started let's state the Requirements for creating a new Peering service connection using the Azure Portal:</p> <ul style="unicode-bidi:embed" type="disc"> <li style="vertical-align:middle"> <p>An Azure account with an active subscription</p> </li> <li style="vertical-align:middle">A connectivity provider from the Peering Service partners <ul> <li style="vertical-align:middle"> <p>The Peering provider partner should be the closest to each office location</p> </li> <li style="vertical-align:middle"> <p>A complete list of the Peering Service partners can be found here in this <a href="https://learn.microsoft.com/en-us/azure/peering-service/location-partners?tabs=partners">link</a></p> </li> </ul> </li> </ul> <img alt="Azure Peering Service for Dataverse" data-entity-type="file" data-entity-uuid="bb72764a-314e-4aeb-933b-bfbf8a958e1c" height="396" src="/sites/default/files/inline-images/ps_service_partners.png" width="456" class="align-center" /> <ol style="unicode-bidi:embed; font-weight:normal; font-style:normal" type="1"> <li style="vertical-align:middle" value="1"> <p><span style=""><span style="font-weight:normal"><span style="font-style:normal">In the Azure portal search box select Peering Services in the search results and then create</span></span></span></p> </li> <li style="vertical-align:middle"><span style="">On the Basics of Create a peering service connection, enter or select the following information:</span> <ul> <li style="vertical-align:middle"> <p><img alt="Azure Peering Service for Dataverse" data-entity-type="file" data-entity-uuid="71092adf-65ed-4dc7-8007-5fa4e6bd6ef2" height="315" src="/sites/default/files/inline-images/HowTo1_0.png" width="508" /></p> </li> </ul> </li> <li style="vertical-align:middle"><span style=""><span style="font-weight:normal"><span style="font-style:normal">Next, let's configure the Service connection:</span></span></span> <ol style="unicode-bidi:embed; font-weight:normal; font-style:normal" type="a"> <li style="vertical-align:middle" value="1"><span style=""><span style="font-weight:normal"><span style="font-style:normal">Will need to provide the country, State/Province the Provider (from the available Peering service partners)</span></span></span></li> <li style="vertical-align:middle"><span style="">Select the</span><span style=""> provider primary peering location</span><span style=""> the and ideally the closest one to the target Office network location to enhance</span></li> <li style="vertical-align:middle"><span style="">Select the provider backup peering location as the next closest to your network location. A peering service will be active via the backup peering location only in the event of failure of primary peering service location for disaster recovery. If None is selected, internet is the default failover route in the event of primary peering service location failure</span></li> <li style="vertical-align:middle"><span style="">Under the Prefixes section, select Create new prefix. In Name, enter a name for the prefix resource. Enter the prefixes that are associated with the service provider in Prefix. In Prefix key, enter the prefix key that was given to you by your provider (ISP or IXP). This key allows Microsoft to validate the prefix and provider who have allocated your IP prefix. If your provider is a Route Server partner, you can create all of your prefixes with the same Peering Service prefix key</span> <ul> <li style="vertical-align:middle"><img alt="Azure Peering Service for Dataverse" data-entity-type="file" data-entity-uuid="55f0e2dd-8466-4a2e-8f26-6579affe9ec5" height="306" src="/sites/default/files/inline-images/HowTo2.png" width="492" /></li> </ul> </li> <li style="vertical-align:middle"><span style="">Select Review + Create and after creating a Peering Service connection, additional validation is performed on the included prefixes. You can review the validation status under the Prefixes section of your Peering Service</span></li> </ol> </li> </ol> <p style="vertical-align:middle">Note: For multi-region Enterprise scenarios a unique Peering service connection should be created per office region</p> <h2 style="vertical-align: middle;"><span style="font-weight:bold">Conclusion</span></h2> <blockquote> <p>another piece of the puzzle</p> </blockquote> <p>With this offer Microsoft releases another piece of the puzzle regarding network latency performance optimization over cloud services (SaaS), however Peering services isn't the so wished silver bullet while architecturing new PowerApps/Dataverse solutions for complex multi-region Enterprise scenarios, and here's why:</p> <ul> <li>Peering services aren't accountable for establishing a private secure network to Microsoft services, though it uses the public infrastructure to route Microsoft services traffic</li> <li>Geographic Power Apps environment distribution will still affect network performance for end-users accessing Apps hover a far distant office location, despite of the overall network performance optimization</li> <li>Regarding custom Power Apps solutions and Apps, Peering services won't improve design patterns with performance and calculation problems</li> <li>Azure Peering Services aren't available as trial</li> </ul> <p>As a final word MAPS is a crucial service for Enterprises having business critical services over Microsoft with a multi-region office distribution and looking for network performance improvement and in solution architectural design.</p> <h2 class="title">Azure Peering Service for Dataverse</h2> </div> </div> <div class="field field--name-field-image field--type-image field--label-above"> <div class="field__label">Image</div> <div class="images-container clearfix"> <div class="image-preview clearfix"> <div class="image-wrapper clearfix"> <div class="field field--name-field-image field--type-image field--label-above field__item">/sites/default/files/2024-03/MAPS_logo.png</div> </div> </div> </div> </div> Wed, 03 Apr 2024 12:43:58 +0000 joao.neto 745 at https://dynamics-chronicles.com Create a service principal with Power Platform CLI https://dynamics-chronicles.com/article/create-service-principal-power-platform-cli <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">Create a service principal with Power Platform CLI</span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/stephane-pelhatre" lang="" about="/user/stephane-pelhatre" typeof="schema:Person" property="schema:name" datatype="" class="username">Stephane Pelhatre</a></span> <span property="schema:dateCreated" content="2024-03-28T13:46:41+00:00" class="field field--name-created field--type-created field--label-hidden">Thu, 03/28/2024 - 14:46</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><p><em>Create a service principal with Power Platform CLI</em></p> <h2>Introduction</h2> <p>To perform an integration with Dynamics 365 you typically need to set up a service principal in Azure.<br /> To achieve this goal you must complete several steps:</p> <ul> <li>Create an Azure App Registration</li> <li>Create a secret for that App Registration</li> <li>Set up API permissions for Dynamics 365</li> <li>Create an Application User in the Power Platform Admin Center</li> <li>Assign permissions to the Application User</li> </ul> <p>A tutorial to perform those actions : <a href="https://dynamics-chronicles.com/article/step-step-connect-d365-clientsecret-use-apis">https://dynamics-chronicles.com/article/step-step-connect-d365-clientsecret-use-apis</a></p> <p><span lang="en" xml:lang="en" xml:lang="en"><span><span>All these manual steps take time</span></span></span>. But you can perform them with a Powershell command (<em>pac admin create-service-principal</em>).</p> <h2>Create your service principal</h2> <p>First you have to install <span>Power Platform CLI<span> </span></span>on your machine.<br /> <span lang="EN-US" xml:lang="EN-US" xml:lang="EN-US">Power Platform CLI </span>is a command-line interface <span lang="EN-US" xml:lang="EN-US" xml:lang="EN-US">used to perform various operations in the Power Platform related to environment lifecycle, authentication, and work with Dataverse environments, solution packages, portals, code components.</span></p> <p><span lang="EN-US" xml:lang="EN-US" xml:lang="EN-US"></span>You can download the MSI file here : <a href="https://aka.ms/PowerAppsCLI">https://aka.ms/PowerAppsCLI</a><br /> Power Platform CLI reference guide : <a href="https://learn.microsoft.com/en-us/power-platform/developer/cli/reference/tool">https://learn.microsoft.com/en-us/power-platform/developer/cli/reference/tool</a></p> <p><span lang="en" xml:lang="en" xml:lang="en"><span><span>After installing Power Platform CLI open a Powershell command prompt and type the command <em>pac</em> to check that the installation was successful.</span></span></span></p> <p><img alt="Create a service principal with Power Platform CLI" data-entity-type="file" data-entity-uuid="1c6b5cff-e105-467f-9ed3-5cb06dd22543" src="/sites/default/files/inline-images/01.%20pac_0.png" /></p> <p>Then type the following command to update to the latest version.</p> <pre> <code> pac install latest</code></pre> <p>Next step is to connect to your Dataverse environment with an authentication profile.<br /> To get a list of all authentication profiles type the following command :</p> <pre> <code class="language-bash">pac auth list</code></pre> <p><img alt="Create a service principal with Power Platform CLI" data-entity-type="file" data-entity-uuid="95804576-ff78-4647-8c07-4cfcf26a3e5b" src="/sites/default/files/inline-images/02.%20pac%20list.png" /></p> <p>As you can see I have no authentication profile installed.<br /> To create a profile type the following command:</p> <pre> <code class="language-bash">pac auth create -env &lt;env id&gt;</code></pre> <p>&lt;env Id&gt; is the environment id of your organisation, which you will find in the Power Platform Admin Center.</p> <p><img alt="Create a service principal with Power Platform CLI" data-entity-type="file" data-entity-uuid="11f4d83f-d12d-4d17-84a9-86a22e8e02b6" src="/sites/default/files/inline-images/04.%20env%20id_0.png" /></p> <p>You will be asked to provide your credentials. Below the result :</p> <p><img alt="Create a service principal with Power Platform CLI" data-entity-type="file" data-entity-uuid="f72d03d4-a289-474e-9a21-f92f5404f321" src="/sites/default/files/inline-images/05.%20pac%20create_0.png" /></p> <p>The last step is to use the command below :</p> <pre> <code class="language-bash">pac admin create-service-principal --environment &lt;env id&gt;</code></pre> <p><img alt="Create a service principal with Power Platform CLI" data-entity-type="file" data-entity-uuid="731dfcdd-c9c8-4228-85bf-237601e5f6ef" src="/sites/default/files/inline-images/06.%20create%20principal.png" /></p> <p>Now you can check the result in your Azure Portal.<br /> As you can see below a new App Registration has been created.</p> <p><br /> <img alt="07" data-entity-type="file" data-entity-uuid="a9f0095e-6444-437a-a77f-6a3c2574b737" src="/sites/default/files/inline-images/07%20app%20reg.png" /></p> <p>A secret with one year validity has been created for the App Registration.</p> <p><br /> <img alt="08" data-entity-type="file" data-entity-uuid="127c27b9-dd25-48df-a372-d09803677642" src="/sites/default/files/inline-images/08%20secret.png" /></p> <p>And correct permissions have also be added.</p> <p><br /> <img alt="09" data-entity-type="file" data-entity-uuid="c543918b-b7cf-4331-9eaf-babf90770415" src="/sites/default/files/inline-images/09%20permissions.png" /></p> <p>You can see your new application user in the Power Platform Admin Center.</p> <p><br /> <img alt="10" data-entity-type="file" data-entity-uuid="71bb7043-ad4a-44ca-ada0-8b57c43b2107" src="/sites/default/files/inline-images/10%20app%20user.png" /><br /> The application user has the security role 'System administrator'.<br /> It is the default security role when you use the command <em>pac admin create-service-principal</em>.<br /> If you want to associate another security role you have to use the option <em>--role</em>.</p> <pre> <code class="language-bash">pac admin create-service-principal --environment &lt;env id&gt; --role &lt;role&gt;</code></pre> <p>Where <em>&lt;role&gt;</em> is the name or ID of security role to be applied to the application user.<br /> Below the command to create a service principal with security role 'Sales Manager' assigned to the application user.</p> <p><br /> <img alt="Create a service principal with Power Platform CLI" data-entity-type="file" data-entity-uuid="f30bc1a4-de9c-4c2a-9124-ee1a9b541acc" src="/sites/default/files/inline-images/11%20role.png" /></p> <h2 class="title">Create a service principal with Power Platform CLI</h2> </div> </div> Thu, 28 Mar 2024 13:46:41 +0000 Stephane Pelhatre 779 at https://dynamics-chronicles.com Dataverse Dynamics 365 Load testing for Model-driven app https://dynamics-chronicles.com/article/dataverse-dynamics-365-load-testing-model-driven-app <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">Dataverse Dynamics 365 Load testing for Model-driven app</span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/julienbiedermann" lang="" about="/user/julienbiedermann" typeof="schema:Person" property="schema:name" datatype="" class="username">julien.biedermann</a></span> <span property="schema:dateCreated" content="2024-01-19T15:00:24+00:00" class="field field--name-created field--type-created field--label-hidden">Fri, 01/19/2024 - 16:00</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><p>Dataverse Dynamics 365 Load testing for Model-driven app</p> <h2>Introduction</h2> <p>In today's digital landscape, where user expectations for seamless, high-performing applications are at an all-time high, ensuring the reliability and scalability of software systems is paramount. Performance testing emerges as a critical practice in the software development lifecycle, aimed at evaluating the responsiveness, stability, and scalability of applications under various conditions.</p> <p>Performance testing encompasses various types, each serving specific objectives in evaluating the performance characteristics of a system. Here are some common performance test types:</p> <ul> <li><strong>Load Testing:</strong> Determines how a system behaves under expected load conditions by subjecting it to a specific number of users or transactions, assessing its response times and resource utilization.</li> <li><strong>Stress Testing:</strong> Pushes the system beyond its normal operational capacity to identify its breaking point and understand how it behaves under extreme conditions, helping determine its resilience and stability.</li> <li><strong>Soak Testing (Endurance Testing):</strong> Evaluates the system's performance over an extended period under a consistent load to detect memory leaks, resource depletion, or degradation of performance over time.</li> <li><strong>Spike Testing:</strong> Assesses the system's ability to handle sudden increases or spikes in load, such as traffic surges, to ensure it can scale appropriately and maintain performance without crashing or slowing down.</li> <li><strong>Scalability Testing:</strong> Measures how well the system can scale up or down to accommodate changes in load or user demand, helping determine its capacity to handle growth or fluctuations in traffic.</li> </ul> <p>In this article, we will focus how to conduct a load testing of a Dynamics 365 Model-driven App.</p> <h2>What is Load Testing ?</h2> <p>Load testing is a crucial aspect of performance testing focused on evaluating how a system behaves under specific levels of concurrent user activity or workload. The primary objective of load testing is to assess the system's performance, reliability, and scalability by subjecting it to simulated loads that represent expected usage patterns in real-world scenarios.</p> <p>During load testing, the system is subjected to various levels of load, typically represented by a specific number of concurrent users, transactions, or requests per unit of time. By gradually increasing the load, testers can observe how the system responds and identify any performance issues, such as slow response times, errors, or system crashes.</p> <p>When performing a load test, several important factors should be considered to ensure its effectiveness and relevance to the application's performance goals. Here are some key considerations:</p> <ul> <li><strong>Define Clear Objectives:</strong> Clearly define the objectives and goals of the load test. Understand what aspects of the application's performance you are testing, such as response times, throughput, scalability, or resource utilization.</li> <li><strong>Identify Key Scenarios:</strong> Identify the critical user scenarios or workflows that are most representative of real-world usage patterns. Focus the load test on these scenarios to simulate realistic user behavior.</li> <li><strong>Set Realistic Load Levels:</strong> Determine the appropriate load levels based on expected traffic volumes, peak usage periods, and scalability requirements. Ensure that the load levels accurately reflect the anticipated production environment.</li> <li><strong>Simulate Production Environment:</strong> Mimic the production environment as closely as possible during the load test. Consider factors such as network latency, hardware configurations, and software dependencies to create a realistic testing environment.</li> <li><strong>Analyze Results:</strong> Analyze the results of the load test thoroughly to identify performance issues, bottlenecks, and areas for improvement. Look for patterns in system behavior and correlate performance metrics to identify root causes of performance degradation.</li> </ul> <h2>How to load test a model-driven app ?</h2> <p>Microsoft is providing the following documentation : <a href="https://learn.microsoft.com/en-us/dynamics365/guidance/resources/test-scale-dynamics-365-solution">https://learn.microsoft.com/en-us/dynamics365/guidance/resources/test-scale-dynamics-365-solution</a></p> <p>In this article, we're gonna walk through using those test samples from Microsoft, step by step.</p> <h2>Requirements</h2> <ul> <li>Microsoft Dynamics 365 Customer Service environment with Customer Service-Hub model-driven application</li> <li>At least one user account with multi-factor authentication disabled</li> <li>Sample data in Dataverse <ul> <li>Min. 10 active accounts</li> <li>Min. 10 active products</li> <li>Min. 10 active subjects</li> </ul> </li> <li>Azure subscription (optional): It's a requirement if you plan to load test in Azure Load Testing (<a href="https://azure.microsoft.com/en-us/products/load-testing">https://azure.microsoft.com/en-us/products/load-testing</a>).</li> </ul> <h3>1. Download samples files</h3> <p>You will find all the samples files here : <a href="https://github.com/microsoft/Dynamics-365-FastTrack-Implementation-Assets/tree/master/Customer%20Service/Testing/At%20Scale/Samples">https://github.com/microsoft/Dynamics-365-FastTrack-Implementation-Assets/tree/master/Customer%20Service/Testing/At%20Scale/Samples</a></p> <p>In this walkthrough, we will use the CreateCase sample. To start, you can download the following files :</p> <ul> <li>CaseCreate.csv</li> <li>CreateCase.docx</li> <li>CreateCase.jmx</li> </ul> <h3>2. Install Apache JMeter</h3> <p>First, you need to install Apache JMeter <a href="https://jmeter.apache.org/usermanual/get-started.html#lets_start">https://jmeter.apache.org/usermanual/get-started.html#lets_start</a>.</p> <p>Apache JMeter is an open-source, Java-based software designed for load testing, performance testing, and functional testing of web applications.</p> <div class="alert alert-primary" role="alert">JMeter is not a browser, it works at protocol level. As far as web-services and remote services are concerned, JMeter looks like a browser (or rather, multiple browsers); however JMeter does not perform all the actions supported by browsers. In particular, JMeter does not execute the Javascript found in HTML pages. Nor does it render the HTML pages as a browser does (it's possible to view the response as HTML etc., but the timings are not included in any samples, and only one sample in one thread is ever displayed at a time).</div> <p>Apache JMeter has two modes, GUI mode and CLI mode.</p> <ul> <li>Use GUI mode for test creation, editing, and debugging.</li> <li>Use CLI mode to run a load test.</li> </ul> <h3>3. Populate CSV file</h3> <p>The file CaseCreate.csv contains the test user's information (username and password). Open the file and add your test user's credentials.</p> <p>Be careful, if the passwords contain special characters like <strong>% or #,</strong> it can be misinterpreted during test execution and generate errors.</p> <p><img alt="Dataverse Dynamics 365 Load testing for Model-driven app" data-entity-type="file" data-entity-uuid="2031403a-9172-4e58-8f99-1d7e215286a7" src="/sites/default/files/inline-images/casecreate_csv.png" /></p> <h3>4. Edit load test script</h3> <p>Run Apache JMeter in GUI mode by opening jmeter.bat in the bin folder.</p> <p>Open the <strong>CreateCase.jmx</strong> file.</p> <ol> <li>In Apache JMeter, click File – Open</li> <li>Use the explorer window to navigate to file or repository containing the CreateCase.jmx file.</li> <li>Select the CreateCase.jmx file and click Open.</li> </ol> <p><img alt="Dataverse Dynamics 365 Load testing for Model-driven app" data-entity-type="file" data-entity-uuid="515fb8ae-e691-4f51-81f2-d000c3ac5f89" src="/sites/default/files/inline-images/jmeter-1.png" /></p> <p>Update <strong>User Defined Variables</strong></p> <ol> <li>Click on the User Defined Variables element</li> <li>Update the following values <ol> <li>host – your Microsoft Dataverse environment url (e.g., yourorg.crm.dynamics.com)</li> <li>tenantId - your Microsoft 365 tenantid.</li> <li>cshAppId - the GUID of your Customer Service Hub model-driven application</li> </ol> </li> </ol> <p>Update the <strong>Thread Group Properties</strong></p> <ol> <li>Click on the CreateCase element</li> <li>Update the following values <ol> <li>Number of Threads (users) – total concurrent users to simulate.</li> <li>Ramp up period (seconds) – duration to increase the threads to the total number of threads.</li> <li>Loop Count – number of times to execute a single thread.</li> </ol> </li> </ol> <p>Configure the <strong>CSV Data Source</strong></p> <ol> <li>Click on the CSV Data Set Config</li> <li>Update the filename value with your updated csv file</li> </ol> <h3>5. Execute in GUI mode</h3> <p>Test can be started in GUI mode using one of the following methods:</p> <ol> <li>In the Run menu, click Start</li> <li>Click the Start button in the toolbar</li> <li>Right-click on CreateCase element and click Start</li> </ol> <div class="alert alert-warning" role="alert">Before running the test in GUI mode, ensure to reduce the number of threads (users). GUI mode should only be used for test creation, editing and debugging.</div> <p>You can use the View Results Tree to monitor the progress of the test and to debug, checking the request and response of the calls.</p> <p><img alt="Dataverse Dynamics 365 Load testing for Model-driven app" data-entity-type="file" data-entity-uuid="faf64260-d9b8-4792-a205-fa1310476b8e" src="/sites/default/files/inline-images/jmeter-2.png" /></p> <h3>6. Execute in CLI mode</h3> <p>GUI mode has limitations that might impact the performance of a load test. Use CLI mode when executing a load test at full scale.</p> <p>Test can be started in CLI mode following the steps below:</p> <ol> <li>Open CMD and change the directory to the jmeter bin folder</li> <li>Enter the following command</li> </ol> <pre> <code>jmeter -n -t path\CreateCase.jmx -l path\testresults.csv -e -o path\Results</code></pre> <table border="1" cellpadding="1" cellspacing="1" style="width: 500px;"> <thead> <tr> <th scope="col">Option</th> <th scope="col">Definition</th> </tr> </thead> <tbody> <tr> <td>-n</td> <td>This specifies JMeter is to run in cli mode.</td> </tr> <tr> <td>-t</td> <td>Name of JMX file that contains the Test Plan</td> </tr> <tr> <td>-l</td> <td>Name of JTL or CSV file to log sample results to</td> </tr> <tr> <td>-e</td> <td>Generate report dashboard after load test</td> </tr> <tr> <td>-o</td> <td>Output folder where to generate the report dashboard after load test. The folder must not exist or be empty.</td> </tr> </tbody> </table> <p>Sometimes, JMeter throws a heap dump along with an ‘out of memory’ error while executing the load test. In this case, you need to increase the heap size by editing the jmeter.bat file. The size has been updated to 8 GB in the example below:</p> <pre> <code>if not defined HEAP ( rem See the unix startup file for the rationale of the following parameters, rem including some tuning recommendations set HEAP=-Xms1g -Xmx8g -XX:MaxMetaspaceSize=256m )</code></pre> <h4>6.1 Report</h4> <p>After running the load test using CLI mode with the command above, a HTML report is generated in the folder defined.</p> <p><img alt="Dataverse Dynamics 365 Load testing for Model-driven app" data-entity-type="file" data-entity-uuid="ae0cf0c7-fc50-439e-9244-943ce72a9997" src="/sites/default/files/inline-images/report.png" /></p> <p>This report offers valuable insights into all requests conducted during the testing phase, presenting a comprehensive overview of the test execution. Additionally, it includes a detailed table illustrating the APDEX.</p> <p>APDEX (Application Performance Index) is a metric used to evaluate the user satisfaction of an application based on its response times. APDEX is a standardized method for measuring and reporting the satisfaction level of users with the responsiveness of web applications or services.</p> <p>APDEX categorizes response times into three zones:</p> <ul> <li>Satisfied: Response times that meet or exceed the user's expectations.</li> <li>Tolerating: Response times that are acceptable but not ideal.</li> <li>Frustrated: Response times that are considered unacceptable by users.</li> </ul> <p>The APDEX score is calculated based on the following formula:</p> <p><img alt="Dataverse Dynamics 365 Load testing for Model-driven app" data-entity-type="file" data-entity-uuid="38b1c812-45ed-48ee-93ca-8c2312d30a44" src="/sites/default/files/inline-images/apdex.png" /></p> <p>In JMeter, APDEX can be calculated using the following steps:</p> <ol> <li>Define the thresholds for response times that determine whether a sample is categorized as satisfied, tolerating, or frustrated. These thresholds are typically defined based on the application's performance goals and user expectations.</li> <li>Configure JMeter to track the response times of requests during the test execution.</li> <li>After the test execution, JMeter calculates the APDEX score based on the collected response times and the defined thresholds.</li> <li>The APDEX score provides a standardized measure of user satisfaction with the application's performance, helping testers and developers assess whether the application meets its performance goals and user expectations.</li> </ol> <p>By using APDEX in JMeter, testers can quantitatively measure and report the user satisfaction level of web applications or services, allowing them to identify performance issues and prioritize improvements to enhance the overall user experience.</p> <h3>7. Execute in Azure Load Testing</h3> <p>First, you need to deploy Azure Load Testing using your Azure subscription.</p> <p>Now, before diving into creating a load test in Azure Load Testing with a JMeter script, there are a few configurations we need to tweak:</p> <h4>7.1 Update CSV Data Set Config</h4> <p>In Azure Load Testing the JMX file and all related files are uploaded in a single folder. When you reference an external file in your JMeter script, verify that you only use the file name and remove any file path references.</p> <ol> <li>Remove any file path and reference the filename only in the filename field</li> <li>Set "Ignore first line" to False</li> <li>Remove the header row (userName,password) from CreateCase.csv</li> </ol> <p><img alt="CSV Configuration Azure Load Testing" data-entity-type="file" data-entity-uuid="be1d0bce-e2ed-4eda-8e24-37960957cd83" src="/sites/default/files/inline-images/alt1_0.png" /></p> <h4>7.2 Update User Defined Variables</h4> <ol> <li>Replace User Defined Variables with the following values :</li> </ol> <pre> <code>${__BeanShell(System.getenv("host"))} ${__BeanShell(System.getenv("tenantId"))} ${__BeanShell(System.getenv("cshAppId"))}</code></pre> <p><img alt="Dataverse Dynamics 365 Load testing for Model-driven app" data-entity-type="file" data-entity-uuid="800d329d-28c1-4b5e-a28f-41ea50af0325" src="/sites/default/files/inline-images/alt2.png" /></p> <h4>7.3 Create and run the test in Azure Load Testing</h4> <ol> <li>In Microsoft Azure, navigate to and open your Azure Load Testing resource.</li> <li>From "Get started" dashboard, select "Create" with the option "Upload a JMeter script" or create it from Tests menu.</li> <li>On the Basic tab, enter a test name and description</li> <li>On the Test plan tab, upload both CreateCase.jmx (the one adapted for Azure Load Testing) and CreateCase.csv (without header row) <ol> <li>Uncheck "Run test after create" if you don't want to run it directly after creation</li> </ol> </li> <li>On the Parameters tab <ol> <li> Add the correct values for the variables <strong>host</strong>, <strong>tenantId </strong>and <strong>cshAppId</strong></li> </ol> </li> <li>On the Load tab <ol> <li>Configure the test engine instances to a meet the target load for the test. The number of threads specified in the jmx file represents the number of thread (virtual users) executed by one test engine instance.</li> <li>Network traffic to Power Platform applications will be routed through Public networks.</li> </ol> </li> <li>On the Test criteria tab <ol> <li>(Optional) Define the criteria to specify the performance expectations of the system under test. Use the defined criteria to determine the failure conditions for the test when the criteria evaluate to true.</li> </ol> </li> <li>On the Monitoring tab <ol> <li>(Optional) Configure application components to monitor server-side metrics during the test run.</li> </ol> </li> <li>Once all tabs completed, you can review and create your test.</li> <li>Then, if you have unchecked the box at point 4.1, you need to open and run your test manually</li> <li>Once the test is executed, you can open it to see the load test results</li> </ol> <p><img alt="Dataverse Dynamics 365 Load testing for Model-driven app" data-entity-type="file" data-entity-uuid="676179a3-f2cd-4b85-883a-46e6b063b861" src="/sites/default/files/inline-images/alt_setup1.png" /></p> <p><img alt="Upload files" data-entity-type="file" data-entity-uuid="7d47373a-d0e8-4c07-bf5b-34dd9c2c0101" src="/sites/default/files/inline-images/alt_setup2.png" /></p> <p><img alt="Azure Load Testing Parameters" data-entity-type="file" data-entity-uuid="27143bc3-8bbb-4258-be8d-38eafce28f00" src="/sites/default/files/inline-images/alt_setup3.png" /></p> <p><img alt="Dataverse Dynamics 365 Load testing for Model-driven app" data-entity-type="file" data-entity-uuid="104141ef-e259-4064-9d92-74af6cbc66d8" src="/sites/default/files/inline-images/alt_results.png" /></p> <div class="alert alert-warning" role="alert">I'd like to note that I conducted the load test within a trial environment. This could account for the observed performance not meeting expected standards.</div> <h2>Conclusion</h2> <p>I hope you enjoyed this tutorial on running a load test sample in a model-driven app. This article provided an overview of load testing using JMeter and Azure Load Testing, and perhaps it will inspire other bloggers to delve into topics such as:</p> <ul> <li>How to build his own test case in JMeter ?</li> <li>How to analyze the results ?</li> </ul> <p>In conclusion, it's crucial to recognize that JMeter has limitations when it comes to measuring user experience elements occurring at the client side, such as load time or page rendering. JMeter functions as a performance testing tool but does not emulate a real browser. If we aim to test the user interface (UI) using JMeter, we'd need to incorporate tools like the WebDriver Sampler. This component facilitates integration with the Selenium browser automation framework, enabling more comprehensive UI testing capabilities within the performance testing context. Essentially, JMeter, while proficient at server-side performance assessments, requires additional tools like WebDriver Sampler for thorough evaluation of user interface aspects.</p> <h2 class="title">Dataverse Dynamics 365 Load testing for Model-driven app</h2> </div> </div> <div class="field field--name-field-image field--type-image field--label-above"> <div class="field__label">Image</div> <div class="images-container clearfix"> <div class="image-preview clearfix"> <div class="image-wrapper clearfix"> <div class="field field--name-field-image field--type-image field--label-above field__item">/sites/default/files/2024-02/article1.png</div> </div> </div> </div> </div> Fri, 19 Jan 2024 15:00:24 +0000 julien.biedermann 742 at https://dynamics-chronicles.com PowerApps Model Driven UI Testing with Playwright https://dynamics-chronicles.com/article/powerapps-model-driven-ui-testing-playwright <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">PowerApps Model Driven UI Testing with Playwright</span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/zsoltzombik" lang="" about="/user/zsoltzombik" typeof="schema:Person" property="schema:name" datatype="" class="username">zsoltzombik</a></span> <span property="schema:dateCreated" content="2023-12-07T15:16:37+00:00" class="field field--name-created field--type-created field--label-hidden">Thu, 12/07/2023 - 16:16</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><p><em>PowerApps Model Driven UI Testing with Playwright</em></p> <h2>Introduction</h2> <p>In the ever-evolving landscape of software development, test automation has emerged as a pivotal trend, revolutionizing the way we build and deploy software. For businesses embracing Agile and DevOps methodologies, automated testing has become a cornerstone practice, enabling faster development and deployment cycles. In this article, we embark on a journey to explore the profound benefits of automated testing and why it holds such paramount importance in the context of software development, particularly within Dynamics 365 Model Driven Apps. We'll also touch upon the pivotal role of Playwright in automating UI testing within this environment. So, let’s discover the major benefits of automated testing and why automation in software testing matters:</p> <ul> <li><strong>Accelerated Development and Delivery:</strong> UI Test automation significantly reduces testing time, as automated tests can be executed rapidly and repeatedly. This results in shorter software development cycles, more frequent releases, quicker updates, and faster time-to-market delivery. The integration of automation, particularly with Playwright, expedites the testing process within Dynamics 365 Model Driven Apps, enhancing the development speed.</li> <li><strong>Enhanced Productivity:</strong> Automated tests operate without human intervention, enabling testing at any time, even during non-working hours. This autonomy minimizes the time software developers and quality assurance teams spend on testing, allowing them to focus on critical tasks. With automation, engineers can prioritize the creation of new features and improvements, ultimately boosting productivity.</li> <li><strong>Precision and Accuracy:</strong> Automated testing reduces the risk of human errors during the testing process. Unlike human testers who may make mistakes, automated tests execute precisely according to predefined criteria. This precision contributes to more reliable and error-free releases, minimizing the risk of failure.</li> <li><strong>Superior App Quality and Performance:</strong> Automated testing offers extensive test coverage, ensuring high-quality and high-performance applications. It allows for simultaneous testing of thousands of test cases across multiple platforms and devices, a feat difficult to achieve manually. With automation, complex and lengthy test cases can be created quickly, elevating the overall quality of applications.</li> <li><strong>Immediate Feedback:</strong> Automated testing provides instant feedback to developers, enabling quick response to failures. This immediate feedback accelerates the bug-fixing process and ensures a better user experience, leading to higher customer satisfaction. In contrast, manual testing can slow down the development and update process.</li> <li><strong>Enabling CI/CD and DevOps:</strong> Test automation is pivotal for implementing Continuous Integration (CI) and Continuous Delivery (CD) practices. In the CI/CD pipeline, every code commit needs to be tested swiftly and efficiently, a task perfectly suited for automation. Automation, including Playwright for UI testing, streamlines the transition to Continuous Testing and Delivery.</li> </ul> <p>Incorporating test automation, especially within the context of Dynamics 365 Model Driven Apps, is not just a trend; it's a necessity. The benefits of automated testing continue to expand as tools and testing frameworks evolve. Beyond traditional automated testing, new areas like model-based testing, predictive analysis, robotics automation, and API test-case automation are emerging. To stay at the forefront of technological evolution, implementing test automation is imperative. It accelerates development, enhances efficiency, accuracy, and productivity, all while maintaining the highest standards of app quality and performance. Partnering automation with a robust testing solution and integrating it with your CI/CD tools ensures that you harness its full potential efficiently on real devices, propelling your software development to new heights without compromising on quality or performance.</p> <ul> </ul> <h2>Setting Up Your Environment for Playwright in Dynamics 365</h2> <h3>Prerequisites for Playwright Setup</h3> <p>Before diving into using Playwright for UI testing, ensure you have the following prerequisites in place:</p> <h4><strong>Native Installation</strong></h4> <ul> <li>Playwright Test for Visual Studio Code: This is available on Visual Studio Marketplace. Make sure you have version 1.19 or newer to leverage the full capabilities of Playwright in Visual Studio Code.</li> </ul> <h4><strong>Playwright NPM Package</strong></h4> <ul> <li><strong>Cross Platform Support:</strong> Playwright is designed for versatility, supporting Windows, Linux, and macOS. It can be used for testing both locally and on Continuous Integration (CI) platforms such as Azure DevOps, GitHub. </li> <li><strong>Browser Testing Flexibility:</strong> It offers extensive testing capabilities, including both headless and headed modes. For mobile testing, Playwright provides native mobile emulation for Google Chrome on Android and Mobile Safari, ensuring comprehensive coverage across devices.</li> </ul> <h4><strong>Azure Subscription (Optional)</strong></h4> <ul> <li><strong>Enhanced Testing with Microsoft Azure:</strong> While not mandatory, an active Microsoft Azure subscription is recommended for a more robust testing framework. It becomes essential if you're planning to conduct automated tests within Azure or integrate load testing into your CI/CD pipelines. Utilizing Azure enhances your testing scope and efficiency, particularly for complex Dynamics 365 environments.</li> </ul> <p>Having these prerequisites in place sets a solid foundation for effective and efficient use of Playwright in your Dynamics 365 UI testing projects.</p> <h3>Installation and Configuration</h3> <p>Before you start, you will need install the following:</p> <ul> <li><strong>NodeJS </strong>- <a href="https://bit.ly/getnodejs">https://bit.ly/getnodejs</a></li> <li><strong>VSCode </strong>- <a href="https://bit.ly/downloadvscode">https://bit.ly/downloadvscode</a></li> </ul> <p>When installing Node, select the LTS version and accept the defaults.</p> <p>After installation, you should check you have Node installed correctly, at command line type:</p> <pre> <code class="language-javascript">npm</code></pre> <p><img alt="PowerApps Model Driven UI Testing with Playwright" data-entity-type="file" data-entity-uuid="1298b6e6-812f-451d-8d07-63fc3d4fc08c" src="/sites/default/files/inline-images/Playwright_extension0.png" /></p> <p>You should see the npm command help information displayed.</p> <p>To check you had the VSCode installed correctly, at the command line type:</p> <pre> <code class="language-javascript">Code .</code></pre> <p>This should open VSCode at the code folder location you are currently in.</p> <h3>UI Test Project folder setup</h3> <p>Playwright UI Test project do not have a project file like C# (.csproj)  so you can simply create a new folder with the name of your project. I will use UITest.</p> <p>At the command line, type:</p> <pre> <code class="language-javascript">Mkdir UITest Cd UITest</code></pre> <h3>Install Playwright Test for Visual Studio Code</h3> <p>Open Visual Studio Code.</p> <p>Select Extension, then search for Playwright Test for VSCode.</p> <p><img alt="Introduction to Dynamics 365 Model Driven Apps UI Testing with Playwright" data-entity-type="file" data-entity-uuid="6234db30-87a2-4e8e-ba5a-75b7bb7e60fd" src="/sites/default/files/inline-images/Playwright_extension1.png" /></p> <p>Then click on Install.</p> <p>Open the command panel (Ctrl + Shift + P), and then enter the following command: <strong>Install Playwright</strong>.</p> <p><img alt="PowerApps Model Driven UI Testing with Playwright" data-entity-type="file" data-entity-uuid="cd701b6a-de78-435f-92bd-4027e24a0191" src="/sites/default/files/inline-images/Playwright_extension2.png" /></p> <p>On the next screen, select the browser(s) you want to run your tests in. You can change the setting later in the <em>playwright.config</em> file.</p> <p>Finally you created your first Playwright test project.</p> <h3>Get a Test Environment</h3> <p>Next, you need a Dynamics 365 environment that you can run tests in. If you're finalizing an implementation project, you probably have a test environment already. If you don't, you can get a free 30-day trial (for this article, we provisioned a trial Dynamics 365 Customer Service Environment.</p> <h3>Setting up Test Environment</h3> <p>To optimize the test environment for automated testing, especially when using Playwright with a model driven app, follow these steps:</p> <h4>Disable Security Defaults</h4> <ul> <li><strong>Adjust Security Defaults:</strong> For the purpose of automated testing it's necessary to turn off security defaults. This ensures that the automated tests can run without unnecessary interruptions interruptions or blocks, which are typically in place for security reasons. Please follow this link: <a href="https://learn.microsoft.com/en-us/entra/fundamentals/security-defaults">https://learn.microsoft.com/en-us/entra/fundamentals/security-defaults</a></li> </ul> <h4>Create and Configure User Accounts</h4> <ul> <li><strong>Access Microsoft 365 Admin Center:</strong> Utilize the Microsoft 365 admin center to set up the required user account(s) for testing.</li> <li><strong>Assign Security Roles:</strong> Properly assign the necessary security roles to these accounts to ensure they have the appropriate access levels for testing.</li> </ul> <p>By carefully configuring the test environment as described, you create a more controlled and effective setting for conducting automated tests using Playwright in Dynamics 365.</p> <h3>First Playwright Test</h3> <p>Let's create our first test! Playwright provides convenient utilities for capturing your browser interactions and generating test scripts. To accomplish this, simply execute the Playwright Node command with the <em>codegen </em>argument. When you include the URL of your model-driven Power App as a parameter, it initiates a browser session that records the user's actions within the Playwright Inspector.</p> <p>To inititate the recording a new test, type this command on Visual Studio Code Terminal window:</p> <pre> <code class="language-javascript">npx playwright codegen https://&lt;you-crm-org&gt;.crm4.dynamics.com/main.aspx?appid=&lt;app guid&gt;</code></pre> <p>Playwright open a new browser instance and launch Playwright Inspector:</p> <p><img alt="PowerApps Model Driven UI Testing with Playwright" data-entity-type="file" data-entity-uuid="88710191-fcb5-4d9f-8fc3-5526f4f57302" src="/sites/default/files/inline-images/First%20Test.png" /></p> <p><img alt="Introduction to Dynamics 365 Model Driven Apps UI Testing with Playwright" data-entity-type="file" data-entity-uuid="61f95da0-e58e-4472-bb23-14bcd03eae3e" src="/sites/default/files/inline-images/First%20Test2.png" /></p> <p>Enter the credentials.</p> <p>Then select <strong>Service </strong>-&gt; <strong>Cases</strong>.</p> <p>Click on <strong>New Case</strong> button.</p> <p>Fill the form, then click on the <strong>Save</strong> button.</p> <p>Finally, take a look at the Playwright inspector window, it generated the code of our test.</p> <p>After the test script generated, we need to create a new test file under the tests folder such as and copy the code generated by Playwright Inspector.</p> <p> </p> <p><img alt="Introduction to Dynamics 365 Model Driven Apps UI Testing with Playwright" data-entity-type="file" data-entity-uuid="da431062-f6a9-447a-978f-9fa576746f59" src="/sites/default/files/inline-images/Runnimgtest_2.png" /></p> <p>Select the Test icon on Visual Studio Code.</p> <p>Find the test we created previously.</p> <p>Click in <strong>Debug Test</strong> button.</p> <p><img alt="PowerApps Model Driven UI Testing with Playwright" data-entity-type="file" data-entity-uuid="f0577589-e636-4f10-9a0e-e017f7137ff9" src="/sites/default/files/inline-images/Runnimgtest3.png" /></p> <p>It kicks off by running tests in debug mode, and eventually, you'll spot the test results right in the terminal window.</p> <p><img alt="Running Playwright Tests" data-entity-type="file" data-entity-uuid="afd50dc2-7238-4525-9e5f-d99facf81e61" src="/sites/default/files/inline-images/Runnimgfinal.png" /></p> <h2>Here's a small preview of the upcoming articles on Playwright.</h2> <ul> <li>The upcoming article, <strong>Writing Effective UI Tests with Playwright in Dynamics 365</strong> will focus on mastering Playwright's testing capabilities, including automated browser testing and managing dynamic content. It will provide a step-by-step guide to developing test scripts specifically tailored for Dynamics 365 UI, complete with example scripts and scenarios, and conclude with strategies for debugging and troubleshooting these tests.</li> <li>Third article <strong>Advanced Playwright Features for Dynamics 365 Testing</strong> will cover sophisticated techniques for working with multiple browsers and devices, including cross-browser and responsive testing. It will also delve into Playwright's advanced capabilities like network interception, mocking, and visual regression testing, along with their integration in CI/CD pipelines.</li> <li>Fourth article titled <strong>Best Practices and Optimizing Test Performance</strong> focuses on creating maintainable test code with well-organized structure and reusable components. It will discuss strategies to enhance test performance, such as parallel testing and methods to reduce test flakiness, and will conclude with approaches for monitoring and reporting test results.</li> </ul> <h2 class="title">PowerApps Model Driven UI Testing with Playwright</h2> </div> </div> <div class="field field--name-field-image field--type-image field--label-above"> <div class="field__label">Image</div> <div class="images-container clearfix"> <div class="image-preview clearfix"> <div class="image-wrapper clearfix"> <div class="field field--name-field-image field--type-image field--label-above field__item">/sites/default/files/2023-11/1970%27s%20sci%20robot%20testing%20software%2C%20studio%20light%2C%20on%20an%20emerald%20colored%20background.jpg</div> </div> </div> </div> </div> Thu, 07 Dec 2023 15:16:37 +0000 zsoltzombik 634 at https://dynamics-chronicles.com The User Name in D365 CRM is different from that in Office 365 https://dynamics-chronicles.com/article/user-name-d365-crm-different-office-365 <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">The User Name in D365 CRM is different from that in Office 365</span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/guowei" lang="" about="/user/guowei" typeof="schema:Person" property="schema:name" datatype="" class="username">Guowei</a></span> <span property="schema:dateCreated" content="2023-02-22T06:56:12+00:00" class="field field--name-created field--type-created field--label-hidden">Wed, 02/22/2023 - 07:56</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><p><em>The User Name in D365 CRM is different from that in Office 365</em></p> <p><strong>Table of Contents</strong></p> <ul> <li>Issue Description</li> <li>Root Cause</li> <li>More Information</li> </ul> <p>Today, I'd like to show a note about the <strong>User Name</strong> sync mechanism from <em><strong>AAD</strong></em>(Azure Active Directory ) to <em><strong>Dynamics 365 CRM.</strong></em></p> <h3><strong>Issue Description</strong></h3> <p>An end-user reported that her name was updated to "<strong>Dayana Andrade Zavala</strong>", however, in D365, it still shows <strong>Dayana <span style="color:#d35400;">Yamileth </span>Andrade Zavala</strong>.</p> <p><strong>In</strong> <strong>AAD:</strong></p> <p><strong><img alt="The User Name in D365 CRM is different from that in Office 365" data-entity-type="file" data-entity-uuid="297f9bc0-40f7-4578-8827-aa8c33bdb2f1" src="/sites/default/files/inline-images/AAD.png" /></strong></p> <p><strong>In O365:</strong></p> <p><strong><img alt="The User Name in D365 CRM is different from that in Office 365" data-entity-type="file" data-entity-uuid="afe35aab-a90f-474c-a953-1eb248cafee6" src="/sites/default/files/inline-images/O365.png" /></strong></p> <p><strong>In D365 CRM:</strong></p> <p><strong><img alt="The User Name in D365 CRM is different from that in Office 365" data-entity-type="file" data-entity-uuid="4bc4cd6d-9e6f-4794-bb44-b607a97bb909" src="/sites/default/files/inline-images/InCRM.png" /></strong></p> <h3><strong>Root Cause</strong></h3> <p>By further checking, we found she updated the user's <strong>Display Name</strong>, Not updated her <strong>first</strong> and <strong>last</strong> names in AAD.</p> <p>In AAD, we can see this user’s display name is “<strong>Dayana Andrade Zavala</strong>”, but her “First name + Last name” is still “<strong>Dayana <span style="color:#d35400;">Yamileth </span>Andrade Zavala</strong>”. </p> <p><strong>O365</strong> uses AAD's Display Name as Name.</p> <p>So, we change the <strong>First</strong> Name and <strong>Last</strong> name in <strong>AAD</strong>, then it will sync to D365 15 mins later.</p> <p><img alt="test" data-entity-type="file" data-entity-uuid="6ea2afe5-9e30-41b3-b315-e6273ce17bf4" src="/sites/default/files/inline-images/tes_newt.png" /></p> <h3><strong>More Information</strong></h3> <p>By default, the system users will be synced from <strong>AAD</strong>(for which settings are either managed in the <strong>Office 365</strong> or <strong>Azure portals</strong>) every 15 mins.</p> <p>In the default sync, only a static set of attributes is synced with Dynamics 365.</p> <p>For example, when the user is synchronized from <strong>AAD/O365 </strong>to <strong>D365 CRM</strong>, the <strong>manager </strong>property is not synchronized.</p> <p>For the details of the attributes please refer to the table below.</p> <table class="Table" style="font-family:&quot;Segoe UI&quot;; text-decoration-thickness:initial; text-decoration-style:initial; text-decoration-color:initial; border-collapse:collapse" title=""> <tbody> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:1px solid black; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><strong><span style="font-family:Calibri, sans-serif"><span style="color:black">CDS SystemUser Property</span></span></strong></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:1px solid black; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><strong><span style="font-family:Calibri, sans-serif"><span style="color:black">Azure AD Property</span></span></strong></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">DomainName</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">UserPrincipalName</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">WindowsLiveId</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">UserPrincipalName</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">FirstName</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">First Name</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">LastName</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:370px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Last Name</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Address1_Country</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Country</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Address1_City</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">City</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Address1_StateOrProvince</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">State</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Address1_Line1</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">StreetAddress</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Address1_PostalCode</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">PostalCode</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Address1_Telephone1</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">BusinessPhones</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">MobilePhone</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">MobilePhone</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Title</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">JobTitle</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:210px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">InternalEmailAddress</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:363px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">Mail</span></span></span></p> </td> </tr> <tr> <td style="border-bottom:1px solid black; width:212px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:1px solid black" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">azureactivedirectoryobjectid</span></span></span></p> </td> <td style="border-bottom:1px solid black; width:362px; padding:5px; background-color:white; border-top:none; border-right:1px solid black; border-left:none" valign="top"> <p><span style="font-size:11pt"><span style="font-family:Calibri, sans-serif"><span style="color:black">objectId</span></span></span></p> </td> </tr> </tbody> </table> <p> </p> <p><strong>The End.</strong></p> <p>Hope this is helpful.</p> <p>Thanks.</p> <h2 class="title">The User Name in D365 CRM is different from that in Office 365</h2> </div> </div> Wed, 22 Feb 2023 06:56:12 +0000 Guowei 626 at https://dynamics-chronicles.com Azure Integration https://dynamics-chronicles.com/article/user-name-d365-crm-different-office-365#comments Dataverse : Azure Functions .Net Framework vs .Net Core / Runtime 1 vs 4 - Migration Steps https://dynamics-chronicles.com/article/dataverse-azure-functions-net-framework-vs-net-core-runtime-1-vs-4-migration-steps <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">Dataverse : Azure Functions .Net Framework vs .Net Core / Runtime 1 vs 4 - Migration Steps</span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/lloyd-sebag" lang="" about="/user/lloyd-sebag" typeof="schema:Person" property="schema:name" datatype="" class="username">Lloyd Sebag</a></span> <span property="schema:dateCreated" content="2022-10-25T14:48:49+00:00" class="field field--name-created field--type-created field--label-hidden">Tue, 10/25/2022 - 16:48</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><p><em>Dataverse : Azure Functions .Net Framework vs .Net Core / Runtime 1 vs 4 - Migration Steps:</em></p> <p>Do you have a FunctionApp in Runtime 1 targeting a .Net Framework project and want to migrate it to a newer Runtime like 4?</p> <blockquote> <p>This is possible! But not so simple if you don't read this article! ;)</p> </blockquote> <h3>Azure Function Runtim 4 and .Net Framework?</h3> <p>First of all, we must clarify a gray area introduced by Microsoft. In the official Azure Function Runtime documentation, there is a table suggesting that Runtime 4 is natively compatible with the .Net Framework. It's partially true...</p> <p><img alt="Dataverse : Azure Functions .Net Framework vs .Net Core / Runtime 1 vs 4 - Migration Steps" data-entity-type="file" data-entity-uuid="57320e9c-469e-40ef-970b-e6fff8fef7ba" src="/sites/default/files/inline-images/Picture1_1.png" /></p> <p>In fact it seems possible but through the option to run the App in isolated process.<br /> <a href="https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide" target="_blank">Here is the doc.</a></p> <p>I have been able to try to follow the steps to do so, without success at the time of writing this article. Indeed, my version of Visual Studio doesn't seem to handle this correctly...<br /> <a href="https://github.com/Azure/azure-functions-dotnet-worker/issues/1045" target="_blank">Here's a GitHub thread speaking about it.</a></p> <p>So how to do?</p> <h3>The King is Dead, Long Live the King!</h3> <p>For years we have all used the Dynamics NuGet package allowing us to connect to the service and use the API. <a href="https://www.nuget.org/packages/Microsoft.CrmSdk.XrmTooling.CoreAssembly" target="_blank">Microsoft.CrmSdk.XrmTooling.CoreAssembly</a></p> <p>Except that this great package is <strong>only available from version 4.6.2 of the .Net Framework!</strong></p> <p>Until recently, there was no solution to use these DLLs with .Net Core...Then the <a href="https://www.nuget.org/packages/Microsoft.PowerPlatform.Dataverse.Client/#readme-body-tab" target="_blank">Microsoft.PowerPlatform.Dataverse.Client</a> project appeared. It's been in preview for a while, but it's now been in <a href="https://powerapps.microsoft.com/en-us/blog/dataverse-service-client-is-now-generally-available/" target="_blank">GA since June 2022!</a></p> <p>This package will not only allow you to retrieve your development habits but will also offer you new methods and others to come.</p> <p>Here is a sample code allowing you to connect to Dataverse and do a WhoAmI. You will notice that the code is not changing a lot between the old version CrmServiceClient and the new ServiceClient!</p> <pre> <code class="language-cs">var service = new ServiceClient($@"AuthType=ClientSecret;url=URL;ClientId=ID;ClientSecret=SECRET"); var userId = (WhoAmIResponse)service .Execute(new WhoAmIRequest()); log.LogTrace("UserId : " + userId.UserId);</code></pre> <p><strong>WARNING </strong>: <a href="https://dynamics-chronicles.com/article/microsoftpowerplatformdataverseclient-ifd-adfs-mode-not-supported">Check this article to know about the non support of IFD + ADFS</a></p> <h3>Ready for Azure Runtime 4!</h3> <p>Thanks to this, you can now fully consider migrating your FunctionApps from runtime 1 to 4 and thus be up to date in your PaaS.</p> <p>You will obviously have to consider skipping the following points:</p> <ul> <li>Change the Runtime on Azure Function. </li> <li>Modify your VS project to point to the correct framework and runtime version.</li> <li>Modify your NuGet packages to remove the old and reference the new.</li> <li>Modify the code to resolve the errors.</li> <li>And more... </li> </ul> <h3>Step by Step</h3> <p><strong>1. Change the Runtime on Azure Function. </strong></p> <ul> <li>Log in to your Azure Portal and navigate to your Function App.</li> <li>Go to the Configuration section and then to the Function Runtime Settings tab.</li> <li>Here you will have a drop-down list to choose the Runtime version.</li> </ul> <p><img alt="Dataverse : Azure Functions .Net Framework vs .Net Core / Runtime 1 vs 4 - Migration Steps" data-entity-type="file" data-entity-uuid="8b00ab7a-e0aa-43ff-a46a-2220ec303aff" height="280" src="/sites/default/files/inline-images/1_31.png" width="771" /></p> <ul> <li>If ever you cannot select version 4. Here is a procedure allowing you to carry out the modification by CLI script.</li> </ul> <pre> <code class="language-bash">az login az functionapp config set --net-framework-version v6.0 -g &lt;ResourceGroup&gt; -n &lt;FunctionAppName&gt; az functionapp config appsettings set --settings FUNCTIONS_EXTENSION_VERSION=~4 -g &lt;ResourceGroup&gt; -n &lt;FunctionAppName&gt;</code></pre> <p><strong>2. Modify your VS project to point to the correct framework and runtime version</strong></p> <ul> <li>Open your Visual Studio project and open the .csproj file.</li> <li>Modify these two nodes as follows.</li> </ul> <p><img alt="Dataverse : Migrate Azure Functions from .Net Framework (Runtime 1) to .Net Core (Runtime 4)" data-entity-type="file" data-entity-uuid="22c00873-d577-42fb-81b8-f34d150f5136" src="/sites/default/files/inline-images/2_29.png" /></p> <p><strong>3. Other steps </strong></p> <p>I think you know how to modify the NuGet packages and migrate your code. No trap here. :)</p> <p>Enjoy ! </p> <h2 class="title">Dataverse : Azure Functions .Net Framework vs .Net Core / Runtime 1 vs 4 - Migration Steps</h2> </div> </div> <div class="field field--name-field-image field--type-image field--label-above"> <div class="field__label">Image</div> <div class="images-container clearfix"> <div class="image-preview clearfix"> <div class="image-wrapper clearfix"> <div class="field field--name-field-image field--type-image field--label-above field__item">/sites/default/files/2022-10/chro.png</div> </div> </div> </div> </div> Tue, 25 Oct 2022 14:48:49 +0000 Lloyd Sebag 597 at https://dynamics-chronicles.com Azure Programming https://dynamics-chronicles.com/article/dataverse-azure-functions-net-framework-vs-net-core-runtime-1-vs-4-migration-steps#comments How to use Azure Table Storage with C# https://dynamics-chronicles.com/article/how-use-azure-table-storage-c <span property="schema:name" class="field field--name-title field--type-string field--label-hidden">How to use Azure Table Storage with C#</span> <span rel="schema:author" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/lloyd-sebag" lang="" about="/user/lloyd-sebag" typeof="schema:Person" property="schema:name" datatype="" class="username">Lloyd Sebag</a></span> <span property="schema:dateCreated" content="2022-09-14T08:32:50+00:00" class="field field--name-created field--type-created field--label-hidden">Wed, 09/14/2022 - 10:32</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-above"> <div class="field__label">Body</div> <div property="schema:text" class="field__item"><p>How to use Azure Table Storage with C#</p> <p>Azure Table Storage is a very useful solution present in the Azure Storage Account component. The service is a NoSQL datastore which accepts authenticated calls from inside and outside the Azure cloud. While remaining scalable and maintained by the Azure Cloud.<br /> It is therefore a real accelerator for projects that need to store unstructured data.</p> <p>You can obviously manipulate the data manually from the Azure portal, however, here I will show you that you can mainly use the API to manipulate the data from your C# code.</p> <p>The first thing to do is to go to your Azure Portal on your Storage Account to retrieve its name and AccessKey.</p> <p><img alt="How to use Azure Table Storage with C#" data-entity-type="file" data-entity-uuid="2cc5f55c-8c38-49cb-812b-043851393753" height="569" src="/sites/default/files/inline-images/storageazure.png" width="929" /></p> <p>Then you can go into your code to do the following CRUD: Don't forget to use the NuGet package : Microsoft.WindowsAzure.Storage.</p> <h4>Using and Auth : </h4> <pre> <code class="language-cs">using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.Table; // Get Storage Information var accountName = "YourAzureStorageAccountName"; var creds = "AccessKeyOfYourStorageAccount"; // Set Auth var creds = new StorageCredentials(accountName, accountKey); var account = new CloudStorageAccount(creds, useHttps: true); // Connect to Storage var client = account.CreateCloudTableClient(); var table = client.GetTableReference("YourAzureTableName"); </code></pre> <h4>Retrieve Data :</h4> <pre> <code class="language-cs">// RETRIEVE DATA FROM AZURE TABLE var condition = TableQuery.GenerateFilterCondition("ColumnA", QueryComparisons.Equal, "Something"); var condition2 = TableQuery.GenerateFilterCondition("ColumnB", QueryComparisons.Equal, "Anotherthing"); var finalFilter = TableQuery.CombineFilters(condition, TableOperators.And, condition2); var query = new TableQuery&lt;YourCustomClassThatRepresentTheObject&gt;().Where(condition).Where(finalFilter); var result = table.ExecuteQuery(query); var obj = result.FirstOrDefault(); obj.ColumnC;</code></pre> <h4>Create Data : </h4> <pre> <code class="language-cs">// INSERT DATA IN AZURE TABLE var obj = new YourCustomClassThatRepresentTheObject() { PartitionKey = Guid.NewGuid().ToString(), // Must be unique RowKey = Guid.NewGuid().ToString(), // Must be unique ColumnA = "ValueA", ColumnB = true, ColumnC = "ValueB" }; var insertOperation = TableOperation.Insert(obj); table.Execute(insertOperation);</code></pre> <h4>Update Data :</h4> <pre> <code class="language-cs">// UPDATE DATA IN AZURE TABLE var obj = new YourCustomClassThatRepresentTheObject() { PartitionKey = PartitionKeyValue, // Must be the one of the record you want to update. You can retrieve it before. RowKey = RowKeyValue, // Must be the one of the record you want to update. You can retrieve it before. ColumnA = "UpdateValueA", ColumnB = false, ColumnC = "UpdateValueB" ETag = "*" }; var mergeOperation = TableOperation.Merge(obj); table.Execute(mergeOperation);</code></pre> <h4>Class definition :</h4> <pre> <code class="language-cs">// YourCustomClassThatRepresentTheObject Class definition public class YourCustomClassThatRepresentTheObject : TableEntity { public string PartitionKey { get; set; } public string RowKey { get; set; } public string ColumnA { get; set; } public Boolean ColumnB { get; set; } public string ColumnC { get; set; } }</code></pre> <p>Voila ! Your code can now communicate with Azure Table and manipulate the data.</p> <h2 class="title">How to use Azure Table Storage with C#</h2> </div> </div> <div class="field field--name-field-image field--type-image field--label-above"> <div class="field__label">Image</div> <div class="images-container clearfix"> <div class="image-preview clearfix"> <div class="image-wrapper clearfix"> <div class="field field--name-field-image field--type-image field--label-above field__item">/sites/default/files/2022-09/How%20to%20use%20Azure%20Table%20Storage%20with%20C%23.jpg</div> </div> </div> </div> </div> Wed, 14 Sep 2022 08:32:50 +0000 Lloyd Sebag 586 at https://dynamics-chronicles.com Azure Data Manipulation Integration Programming https://dynamics-chronicles.com/article/how-use-azure-table-storage-c#comments