<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Stuff & Tacos]]></title><description><![CDATA[Random IT stuffs about powershell, C#, Visual Studio Team Service, Azure, Dynamics CRM, Sharepoint and even SAP]]></description><link>https://stuffandtacos.azurewebsites.net/</link><generator>Ghost 0.9</generator><lastBuildDate>Wed, 22 Apr 2026 06:00:49 GMT</lastBuildDate><atom:link href="https://stuffandtacos.azurewebsites.net/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Dynamics v9 (onprem) installation - Reporting Extensions Issue]]></title><description><![CDATA[<p>Hi guys,</p>

<p>I wanted to share with everyone a pretty bad surprise when I tried to install a brand new Dynamics v9.0 instance OnPremise for a client. <br>
I know that installing an OnPremise instance is not something you do everyday now but ...</p>

<p>Besides all steps which were fine, I</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2025/12/08/dynamics-v9-onprem-installation/</link><guid isPermaLink="false">3921a25f-d2df-4eb9-b796-094146d47b15</guid><category><![CDATA[Dynamics v9]]></category><category><![CDATA[Onpremise]]></category><category><![CDATA[Reporting Extensions]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Mon, 08 Dec 2025 11:49:58 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2025/12/2025_12_05_10-42-30_mstsc.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2025/12/2025_12_05_10-42-30_mstsc.png" alt="Dynamics v9 (onprem) installation - Reporting Extensions Issue"><p>Hi guys,</p>

<p>I wanted to share with everyone a pretty bad surprise when I tried to install a brand new Dynamics v9.0 instance OnPremise for a client. <br>
I know that installing an OnPremise instance is not something you do everyday now but ...</p>

<p>Besides all steps which were fine, I started to struggle when I had to install the <strong>Reporting Extensions</strong> (which is a requirement to full fil the installation).</p>

<p>Here is the issue : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2025/12/2025_12_05_09-41-38_mstsc.png" alt="Dynamics v9 (onprem) installation - Reporting Extensions Issue"></p>

<p>Don't get me wrong, I've tried to access the link, looked for the error message, it was all about the SSDT which was already installed along with the Visual Studio instance. <br>
And of course, before I installed the SSRS on the right server.</p>

<p>After discussing with a colleague who faced the issue with another client (this was a known issue by MS), we figured this out.</p>

<p>Here are the steps to fix the installation :</p>

<ol>
<li>You should have the installer from that url : <a href="https://www.microsoft.com/en-us/download/details.aspx?id=57478">https://www.microsoft.com/en-us/download/details.aspx?id=57478</a>  </li>
<li>Extract it using the following command line : <br>
<code>./CRM9.0-Server-ENU-amd64.exe /extract:C:\YourPath9.0</code>
This will create a folder with all necessary files.  </li>
<li>Next step is to download the 0.3 update here : <a href="https://www.microsoft.com/en-us/download/details.aspx?id=58153">https://www.microsoft.com/en-us/download/details.aspx?id=58153</a>  </li>
<li>Download the <em>CRM9.0-Srs-KB4490599-ENU-Amd64.exe</em> file  </li>
<li>Extract it using : <br>
<code>./CRM9.0-Srs-KB4490599-ENU-Amd64.exe extract:C:\YourPath0.3</code></li>
<li>Get back to your "C:\YourPath9.0" folder and edit the file install-config.xml in the SrsDataConnector directory  </li>
<li>Replace <code>&lt;patch update="false"&gt;&lt;/patch&gt;</code> by <code>&lt;patch update="true"&gt;C:\YourPath0.3\Srs_KB4490599_amd64_1033.msp&lt;/patch&gt;</code>  </li>
<li>Run the Reporting Extensions install again and this should be fine ! <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2025/12/2025_12_05_10-42-30_mstsc-1.png" alt="Dynamics v9 (onprem) installation - Reporting Extensions Issue"></li>
</ol>

<p>I hope this helped you. <br>
Cheers, <br>
Clément</p>

<p>PS : you do have several step by step guides : </p>

<ul>
<li><a href="https://butenko.pro/2019/01/09/d365ce_90_step_by_step_installation/">https://butenko.pro/2019/01/09/d365ce<em>90</em>step<em>by</em>step_installation/</a></li>
<li><a href="https://www.blog.allandecastro.com/installing-dynamics-365-v9-on-premise/">https://www.blog.allandecastro.com/installing-dynamics-365-v9-on-premise/</a></li>
<li><a href="https://learn.microsoft.com/en-us/dynamics365/customerengagement/on-premises/deploy/install-or-upgrade-microsoft-dynamics-365-server?view=op-9-0">https://learn.microsoft.com/en-us/dynamics365/customerengagement/on-premises/deploy/install-or-upgrade-microsoft-dynamics-365-server?view=op-9-0</a></li>
</ul>]]></content:encoded></item><item><title><![CDATA[What you need to know when building Autonomous Agent in Copilot Studio]]></title><description><![CDATA[<p>Hello everyone,</p>

<h4 id="intro">Intro</h4>

<p>Today, I want to share my findings regarding the creation of an autonomous agent in Copilot Studio (CS). <br>
What I missed and spent too much time figuring out, the pre-requisites and so on.</p>

<p>As you know, we can build agents in Copilot Studio using Topics, Generative Answers,</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2025/03/03/what-you-need-to-know-when-building-autonomous-agent-in-copilot-studio/</link><guid isPermaLink="false">4680e5c5-0b42-4e5c-9c6a-03617445505b</guid><category><![CDATA[copilot studio]]></category><category><![CDATA[agent]]></category><category><![CDATA[autonomous agent]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Mon, 03 Mar 2025 17:19:33 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2025/03/2025_03_02_20-51-28_msedge.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2025/03/2025_03_02_20-51-28_msedge.png" alt="What you need to know when building Autonomous Agent in Copilot Studio"><p>Hello everyone,</p>

<h4 id="intro">Intro</h4>

<p>Today, I want to share my findings regarding the creation of an autonomous agent in Copilot Studio (CS). <br>
What I missed and spent too much time figuring out, the pre-requisites and so on.</p>

<p>As you know, we can build agents in Copilot Studio using Topics, Generative Answers, Orchestration, Generative Actions. <br>
Those capabilities are awesome but this need to be used using a chat to discuss with the agent.</p>

<p>At the end of last year (October 2024), Microsoft announce the autonomous capability which can help to change the "agent game" (<a href="https://www.microsoft.com/en-us/microsoft-copilot/blog/copilot-studio/unlocking-autonomous-agent-capabilities-with-microsoft-copilot-studio/">details</a>).</p>

<h4 id="usecases">Use cases</h4>

<p>Basically in few words, an autonomous agent is an agent as you know it with the trigger to automatically trigger it with a cloud flow. <br>
Of course, this is way beyond a cloud flow.</p>

<p>From my point of view, the main difference and advantage of the autonomous agent compare to a cloud flow is the Orchestration side of the agent. <br>
Having the capability to automatically trigger the right topic or action based on an input is a must have. In a Cloud flow, you would need to define all branches of your processes to know where to route a request.</p>

<blockquote>
  <p>My very simple use case for the following was to leverage the capabilities of the autonomous agent, to grab the information from a devops ticket with a timeframe in order to reflect it in Outlook calendar automatically.</p>
</blockquote>

<p>I create a DevOps ticket assigned to me with the time slot, I want to see this in my outlook.</p>

<h4 id="howtoconfigureit">How to configure it</h4>

<p>Few steps : </p>

<ol>
<li>Activate the orchestration (for english agents only for now and in preview)  </li>
<li>Define your trigger with Power Automate  </li>
<li>Test your trigger and the orchestration in Copilot Studio  </li>
<li>Deploy</li>
</ol>

<p>I feel like there is no need to paraphrase the documentation, you can find details <a href="https://learn.microsoft.com/en-us/microsoft-copilot-studio/authoring-triggers-about">here</a></p>

<p>You have 2 ways to test your autonomous agent :</p>

<ul>
<li>Trigger at least once your trigger flow and reuse it in Copilot Studio using : <br>
<img src="https://carfupstorage.blob.core.windows.net/sharex/2025_03_02_20-41-22_msedge.png" alt="What you need to know when building Autonomous Agent in Copilot Studio"></li>
<li>Trigger the flow and "wait" for the automated run of the agent</li>
</ul>

<h4 id="howtodebug">How to debug !</h4>

<p>That's a real pain point for now on Copilot studio, the lack of information when building and debugging an agent.</p>

<p>To follow all run of your agent, you do have the "Activity tab", there you will find something like : <br>
<img src="https://carfupstorage.blob.core.windows.net/sharex/2025_03_02_20-45-44_POWERPNT.png" alt="What you need to know when building Autonomous Agent in Copilot Studio">
Quick explanation here : </p>

<ul>
<li>Complete : well done, all good !</li>
<li>Waiting for user : this relates mainly to the fact that connections are missing or need to be reconfigured</li>
<li>In Progress : something went wrong, argh ...</li>
</ul>

<h6 id="letsfocusontheinprogressmainlyfornow">Let's focus on the In Progress mainly for now.</h6>

<p>Something went wrong but where ? what ? how ? why ?</p>

<p>When tested the agent directly within Copilot Studio everything was fine !</p>

<p>You can click on each run in order to find more details : <br>
<img src="https://carfupstorage.blob.core.windows.net/sharex/2025_03_02_20-50-00_msedge.png" alt="What you need to know when building Autonomous Agent in Copilot Studio">
This displays the activity map of all actions / topics triggered automatically using the orchestration. <br>
By checking the screen, all seems fine, but no ! <br>
The golden ticket is not far away but you need to find it the first time : <br>
<img src="https://carfupstorage.blob.core.windows.net/sharex/2025_03_02_20-51-28_msedge.png" alt="What you need to know when building Autonomous Agent in Copilot Studio"></p>

<p>This will lead you with (obviously) the transcript of this run, and for example here, I can see that I do have a datetime format issue which prevent my Outlook creation of event fail. <br>
<img src="https://carfupstorage.blob.core.windows.net/sharex/2025_03_02_20-54-01_msedge.png" alt="What you need to know when building Autonomous Agent in Copilot Studio"></p>

<p>Therefore, I now know where to check and test in order to fix this.</p>

<h6 id="thebehaviorbetweenthetestincsandthedirecttriggeraredifferent">The behavior between the test in CS and the direct trigger are different</h6>

<p>One other point to be aware of is how the agent works between CS and autonomously. <br>
As soon as you know it, it makes perfect sens but ...</p>

<p>In Copilot Studio, every changes on your agent are directly reflected. <br>
However, when using it with the "real" trigger, this will trigger the latest version of the agent published.</p>

<p>Be sure to publish your agent as soon as you are done or fixed thing to prevent you some time wasted sadly (my story)</p>

<h6 id="connectionissueintheactions">Connection issue in the actions</h6>

<p>For now, make sure that all actions are using the Copilot Author connection, that's the only way it can work <strong>for now</strong>.</p>

<p>This means that if you go for an autonomous agent right now (besides the fact that it's in preview), you can't use ootb the context of the user who are using the agent.</p>

<h5 id="conclusion">Conclusion</h5>

<p>I have to admit that I struggled a bit with these 3 points and wanted to share it before people would waste time like I did because I missed important part.</p>

<p>Hope this can help you, <br>
Cheers,</p>]]></content:encoded></item><item><title><![CDATA[Properly define default items in a combobox (Canvas App)]]></title><description><![CDATA[<p>Hello everyone,</p>

<p>Today I'm going to discuss about a quick tips. <br>
The other I was building a canvas app for a client, nothing fancy so far. <br>
One need was around the usage of a multiselect Combo box control (old or modern one) <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2024/12/2024_12_09_09-43-06_msedge.png" alt=""></p>

<p>I struggled few minutes about the auto-selection of</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2024/12/09/properly-define-defaultitems-combobox-in-canvas-app/</link><guid isPermaLink="false">95b219a2-c2d1-4cef-a269-6234a798f436</guid><category><![CDATA[canvas app]]></category><category><![CDATA[dataverse]]></category><category><![CDATA[combobox]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Mon, 09 Dec 2024 14:14:11 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2024/12/2024_12_09_15-13-41_msedge.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2024/12/2024_12_09_15-13-41_msedge.png" alt="Properly define default items in a combobox (Canvas App)"><p>Hello everyone,</p>

<p>Today I'm going to discuss about a quick tips. <br>
The other I was building a canvas app for a client, nothing fancy so far. <br>
One need was around the usage of a multiselect Combo box control (old or modern one) <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2024/12/2024_12_09_09-43-06_msedge.png" alt="Properly define default items in a combobox (Canvas App)"></p>

<p>I struggled few minutes about the auto-selection of default value.</p>

<p>Let's explain the situation with an sample :</p>

<ul>
<li>I do have a list of items for this control, like : "Item 1; Item 2; Item 3; Item 4"</li>
<li>My data source record contains "Item 1;Item 4" as text value (yes I'm using a SharePoint List in this case !)</li>
</ul>

<p>In the first place, I will simply pass as input parameter in my <em>DefaultSelectedItems</em> (expecting an array of items) property the following :  </p>

<pre><code class="language-json">Split(First(colSource).val)  
</code></pre>

<p><em>(colSource being a local collection of my SharePoint list and the val property the column which contains the textual values of my combo box)</em></p>

<p>The result is the following : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2024/12/2024_12_09_09-48-32_msedge.png" alt="Properly define default items in a combobox (Canvas App)">
As you can see, the legacy and modern controls seem.</p>

<p>The main problem (let's say it this way), has yet to come. <br>
Visually speaking the values are selected but once I want to select manually, nothing seems to be mapped properly.</p>

<p>I'm still able to select the Item 1 and Item 4 from the list like nothing was already selected. <br>
This seems to be related to the fact that mapping using only the "text value" of the property doesn't seems to be enough. <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2024/12/2024_12_09_09-55-44_msedge.png" alt="Properly define default items in a combobox (Canvas App)"></p>

<p>The workaround that did it is to retrieve from the options list the related record such as :  </p>

<pre><code class="language-json">Filter(ComboBoxSample, Value1 in Split(First(colSource).val, ";"))  
</code></pre>

<p>The idea here is to retrieve the complete record related to a selected value in order to make the control aware of the data selected.</p>

<p>Result now is : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2024/12/2024_12_09_15-11-03_msedge.png" alt="Properly define default items in a combobox (Canvas App)"></p>

<p>Quick tip of the day !</p>

<p>Enjoy and have fun with your Canvas Apps !</p>]]></content:encoded></item><item><title><![CDATA[Extend a generated Word Template from Dataverse]]></title><description><![CDATA[<p>Hello everyone,</p>

<p>Today, I had an interesting challenge from one of my client. <br>
Here is the use case : </p>

<blockquote>
  <p><em>"We want to keep using the Word template provided by the Dataverse because it's easy to configure the data mapping between the Tables and the word template. <mark>But we also want to</mark></em></p></blockquote>]]></description><link>https://stuffandtacos.azurewebsites.net/2024/03/14/extend-a-generated-word-template-from-dataverse/</link><guid isPermaLink="false">963b4bae-ede9-4e86-ab72-84d86c942ef3</guid><category><![CDATA[dataverse]]></category><category><![CDATA[word template]]></category><category><![CDATA[dynamics 365]]></category><category><![CDATA[Custom Page]]></category><category><![CDATA[Power Automate]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Thu, 14 Mar 2024 10:08:30 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2024/03/2024_03_14_11-05-50_msedge.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2024/03/2024_03_14_11-05-50_msedge.png" alt="Extend a generated Word Template from Dataverse"><p>Hello everyone,</p>

<p>Today, I had an interesting challenge from one of my client. <br>
Here is the use case : </p>

<blockquote>
  <p><em>"We want to keep using the Word template provided by the Dataverse because it's easy to configure the data mapping between the Tables and the word template. <mark>But we also want to integrate values from another system</mark>", and the solution must be as integrated as it is today for the enduser.</em></p>
</blockquote>

<p>Basically, the challenge here is to "recreate" the selection screen of a template and use a Power Automate flow to make all the job. <br>
In details this will give something like : </p>

<ol>
<li>Create a custom page opened by a click in the ribbon (here is how to do it : <a href="https://learn.microsoft.com/en-us/power-apps/developer/model-driven-apps/clientapi/navigate-to-custom-page-examples?WT.mc_id=BA-MVP-5003014">https://learn.microsoft.com/en-us/power-apps/developer/model-driven-apps/clientapi/navigate-to-custom-page-examples?WT.mc_id=BA-MVP-5003014</a>)  </li>
<li>Retrieve all templates (word is the example) related to the selected record's table  </li>
<li>Select the whished Template  </li>
<li>Generate the document via Power Automate</li>
</ol>

<p>We will focus on the step 4 as this is the most fun part 🙂.</p>

<h3 id="prerequiste">Prerequiste :</h3>

<p>In order to make this work, you need upfront to add your extra tags in the word template which will be uploaded to the Dataverse.</p>

<h3 id="detailedschemaofstep4">Detailed Schema of step 4 :</h3>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2024/03/2024_03_14_10-33-48_POWERPNT.png" alt="Extend a generated Word Template from Dataverse"></p>

<p><strong>Step 2)</strong> I decided to use the HTTP with Microsoft Entra ID (preauthorized) connector to ease the POC. Of course for the step, you could go with a Custom connector on top of the Dataverse API. Reason for not using the standard Dataverse connector is that this action is not "exposed".</p>

<p>This will give you something like : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2024/03/2024_03_14_10-37-15_msedge.png" alt="Extend a generated Word Template from Dataverse"></p>

<pre><code class="language-json">URL : /api/data/v9.2/ExportWordDocument  
BODY :  
{
   "EntityTypeCode": 2
   },
   "SelectedTemplate": {
      "@odata.type": "Microsoft.Dynamics.CRM.documenttemplate",
      "documenttemplateid": "GUID HERE"
   },
   "SelectedRecords": "[\"GUID HERE\"]"
}
</code></pre>

<p><strong>Parameters :</strong></p>

<ul>
<li>You can find all <strong>EntityTypeCode</strong> <a href="https://www.thetindog.com/dynamics-as-we-go/object-type-codes-list">here</a>.</li>
<li>The <strong>SelectedTemplate</strong> corresponding to the Document Template ID selected.</li>
<li>The <strong>SelectedRecords</strong> corresponding to an array of the records you want to generate the word document for.</li>
</ul>

<p><strong>Step 3)</strong> Using a compose will allow you to prepare the file content we will use to create the document on SharePoint in the next step :
<img src="https://stuffandtacos.azurewebsites.net/content/images/2024/03/2024_03_14_10-47-51_msedge.png" alt="Extend a generated Word Template from Dataverse"></p>

<pre><code class="language-json">{
  "$content-type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  "$content": @{body('ExportWordDocument_Action')?['WordFile']}
}
</code></pre>

<p>Here we define the content type for a word file and keeping the property "WordFile" only from the ExportWordDocument action.</p>

<p><strong>Step 6)</strong> We now have our document generated from the dataverse in SharePoint, we can now fill it with the external data we retrieved from the previous step :
<img src="https://stuffandtacos.azurewebsites.net/content/images/2024/03/2024_03_14_10-54-28_msedge.png" alt="Extend a generated Word Template from Dataverse">
On the above screenshot, we can see the placeholder which are used by the Dataverse word template generation, our focus is about the ones in the red rectangle which will be used for our extra data. <br>
All you need to do here is to map those fields with the data you extracted.</p>

<p><strong>Step 7)</strong> 
<img src="https://stuffandtacos.azurewebsites.net/content/images/2024/03/2024_03_14_10-57-42_msedge.png" alt="Extend a generated Word Template from Dataverse">
Here the <em>File Content</em> property will be filled with the body of the previous action, ie <code>@{body('Populate_a_Microsoft_Word_template')}</code>.</p>

<h3 id="wrapup">Wrap up :</h3>

<p>We created a dedicated process to keep using the word template generation from Dataverse to ease the data mapping for the end user update. <br>
We extended it with external data and put the final file on SharePoint (it could be send by email, send back the file content to the Custom Page to directly download it or whatever way you want 😋).</p>

<p>Hope this can help you some times. <br>
Enjoy, <br>
Cheers</p>

<p>PS - Possible improvement on this POC : </p>

<ul>
<li>Use a Service Principal with the Entra ID connector otherwise your users will be lost or use a Custom Connector on the top of the Dataverse API or use a provided connection with the "Run only user" section of your flow.</li>
</ul>]]></content:encoded></item><item><title><![CDATA[Dynamics 365 CRM + AI & ML]]></title><description><![CDATA[<p>Hello everyone,</p>

<p>Let's see what can we do with Dynamics 365 CRM &amp; some AI/ML today.</p>

<h4 id="whatarewetalkingabout">What are we talking about ?</h4>

<p>Artificial intelligence (AI) and machine learning (ML) are revolutionizing the way organizations operate and interact with their customers. These technologies have the potential to greatly improve customer engagement,</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2023/02/06/dynamics365-ai-ml/</link><guid isPermaLink="false">4e6e473e-53ae-4e95-ae48-4b0ed64420f1</guid><category><![CDATA[dynamics 365]]></category><category><![CDATA[Customer Insights]]></category><category><![CDATA[AI]]></category><category><![CDATA[Azure Machine Learning]]></category><category><![CDATA[Sales Insights]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Mon, 06 Feb 2023 19:11:40 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2023/02/2023_02_06_10-42-29_POWERPNT-1.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2023/02/2023_02_06_10-42-29_POWERPNT-1.png" alt="Dynamics 365 CRM + AI & ML"><p>Hello everyone,</p>

<p>Let's see what can we do with Dynamics 365 CRM &amp; some AI/ML today.</p>

<h4 id="whatarewetalkingabout">What are we talking about ?</h4>

<p>Artificial intelligence (AI) and machine learning (ML) are revolutionizing the way organizations operate and interact with their customers. These technologies have the potential to greatly improve customer engagement, streamline operations, and provide valuable insights into customer behavior and preferences. Dynamics 365 CRM is one platform that is at the forefront of this revolution, offering a suite of AI and ML capabilities that are designed to help organizations better understand their customers and improve their overall customer experience.</p>

<p>In this blog post, we will explore the latest AI and ML capabilities in Dynamics 365 CRM, including how to implement these features in your organization and real-world use cases.</p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2023/02/2023_02_06_10-42-29_POWERPNT.png" alt="Dynamics 365 CRM + AI & ML"></p>

<p><strong>Understanding the AI and Machine Learning Capabilities in Dynamics 365 CRM :</strong>
Dynamics 365 CRM offers a variety of AI and ML capabilities that are designed to help organizations better understand their customers and improve their overall customer experience. Some of the key AI and ML capabilities in Dynamics 365 CRM include:</p>

<ul>
<li><p><mark>Customer insights</mark>: This feature uses AI to analyze customer behavior and preferences, providing valuable insights into customer behavior and preferences. This information can be used to create targeted marketing campaigns, personalize the customer experience, and improve customer engagement.</p></li>
<li><p><mark>Sales insights</mark>: This feature uses ML algorithms to analyze sales data, providing valuable insights into sales trends, customer behavior, and market trends. This information can be used to optimize sales processes, improve sales forecasting, and increase sales productivity.</p></li>
<li><p><mark>Customer service insights</mark>: This feature uses AI to analyze customer service data, providing valuable insights into customer behavior and preferences. This information can be used to improve customer service processes, optimize customer support, and increase customer satisfaction.</p></li>
</ul>

<h4 id="implementingaiandmachinelearningcapabilitiesindynamics365crm">Implementing AI and Machine Learning Capabilities in Dynamics 365 CRM</h4>

<p>Implementing AI and ML capabilities in Dynamics 365 CRM is a straightforward process that can be done in just a few steps. Here is a step-by-step guide to implementing these capabilities:</p>

<p>Determine your AI and ML needs: Before implementing AI and ML capabilities in Dynamics 365 CRM, it is important to determine your organization's specific needs. This will help you determine which capabilities are most relevant to your organization and which features are most important to prioritize.</p>

<p>Choose the right AI and ML capabilities: Once you have determined your AI and ML needs, you can choose the right capabilities to implement. For example, if you need to analyze customer behavior and preferences, you may choose to implement the customer insights feature.</p>

<p>Set up the AI and ML capabilities: Setting up the AI and ML capabilities in Dynamics 365 CRM is a straightforward process that involves configuring the relevant settings and connecting to the necessary data sources.</p>

<p>Use the AI and ML capabilities: Once you have set up the AI and ML capabilities in Dynamics 365 CRM, you can start using them to analyze customer behavior and preferences, improve sales processes, and optimize customer support.</p>

<h4 id="realworldusecasesforaiandmachinelearningcapabilitiesindynamics365crm">Real-World Use Cases for AI and Machine Learning Capabilities in Dynamics 365 CRM</h4>

<p>Here are a few real-world use cases for AI and ML capabilities in Dynamics 365 CRM:</p>

<ul>
<li><p>Customer insights: A retail organization uses customer insights to analyze customer behavior and preferences, providing valuable insights into customer behavior and preferences. This information is used to create targeted marketing campaigns, personalize the customer experience, and improve customer engagement.</p></li>
<li><p>Sales insights: A sales organization uses sales insights to analyze sales data, providing valuable insights into sales trends, customer behavior, and market trends. This information is used.</p></li>
</ul>

<p>Enjoy, <br>
Cheers</p>]]></content:encoded></item><item><title><![CDATA[Resize and host glideapps pictures into Google Drive]]></title><description><![CDATA[<blockquote>
  <p>disclaimer : storing pictures on external hosting might not scale. Depending on your usage.
  <a href="https://docs.glideapps.com/all/courses/quick-starts/getting-started/adding-images#external-hosting">https://docs.glideapps.com/all/courses/quick-starts/getting-started/adding-images#external-hosting</a></p>
</blockquote>

<p><strong>2021-nov-16 update</strong> : updated with data flushing preventing parallel execution creating duplicates.</p>

<p><a href="https://www.glideapps.com/">Glideapps</a> is really a convenient tool which I use for numerous personal usages: it uses google</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2021/10/13/resize-and-host-glideapps-pictures-into-google-drive/</link><guid isPermaLink="false">94eb81ce-f412-4fd9-9946-99e3725f7a20</guid><category><![CDATA[glideapps]]></category><category><![CDATA[googlesheet]]></category><dc:creator><![CDATA[Fabien Camous]]></dc:creator><pubDate>Wed, 13 Oct 2021 16:52:04 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2021/10/1_WQAJ-i-JK7tM0KgwbiRHzg.jpeg" medium="image"/><content:encoded><![CDATA[<blockquote>
  <img src="http://undefined.azurewebsites.net/content/images/2021/10/1_WQAJ-i-JK7tM0KgwbiRHzg.jpeg" alt="Resize and host glideapps pictures into Google Drive"><p>disclaimer : storing pictures on external hosting might not scale. Depending on your usage.
  <a href="https://docs.glideapps.com/all/courses/quick-starts/getting-started/adding-images#external-hosting">https://docs.glideapps.com/all/courses/quick-starts/getting-started/adding-images#external-hosting</a></p>
</blockquote>

<p><strong>2021-nov-16 update</strong> : updated with data flushing preventing parallel execution creating duplicates.</p>

<p><a href="https://www.glideapps.com/">Glideapps</a> is really a convenient tool which I use for numerous personal usages: it uses google sheets into mobile application in minutes. </p>

<p>Beside being a developer, I appreciate the ease and rapidity to make small mobile applications. Moveover, having a google sheet as a database allows this to be shared to other people and supports bulk operations.</p>

<p>I even use it for my cooking recipies :)</p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2021/10/chrome_hXVHeACjpn.png" alt="Resize and host glideapps pictures into Google Drive"></p>

<p>Free limitations are enough for personal recreative usages</p>

<ul>
<li>500 lines (shared accross all your sheets)</li>
<li>1000 sheet edits</li>
<li>100 MB of images &amp; files (if uploaded on glideapps)</li>
</ul>

<p>One incredible feature is the capacity to easily upload any pictures, files or <strong>mobile camera photos</strong> and store it in your app. <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2021/10/chrome_gYsrDcLQZS.png" alt="Resize and host glideapps pictures into Google Drive"></p>

<p>Incredible to upload pictures in 2021 from a mobile phone ? In 5 minutes effort and already published in your hand, yes.</p>

<p>Unfortunately this leads to one major limitation of glideapp free version. With recent phone pictures quality, each file around 3MB, 100MB limitation will be reached quickly. <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2021/10/chrome_Ok0JGNjkOD.png" alt="Resize and host glideapps pictures into Google Drive"></p>

<p>Hopefuly, there is a workaround</p>

<ul>
<li>glideapps calculates storage only for picture hosted on their infrastructure and linked in google sheet</li>
<li>glideapp supports pictures from anywhere on internet</li>
</ul>

<p>Writing an `apps script' tied to google sheet could </p>

<ol>
<li>download pictures  </li>
<li>resize it, for my needs, 3MB pictures aren't necessary and slow down loading time. (Done by <a href="https://github.com/tanaikech/ImgApp">https://github.com/tanaikech/ImgApp</a>, instructions for setup : <a href="https://github.com/tanaikech/ImgApp#how-to-install">https://github.com/tanaikech/ImgApp#how-to-install</a>)  </li>
<li>store them in a public google drive folder  </li>
<li>finally replace links into cells </li>
</ol>

<p>To be configured</p>

<ul>
<li>range where script should perform replaces</li>
<li>google drive folder id</li>
</ul>

<script src="https://gist.github.com/camous/d08327a82d53a0c98549550ca3bdef15.js"></script>

<p>Associated with a trigger <code>onChange</code>, it would be transparent.</p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2021/10/chrome_rJXTduBXMo.png" alt="Resize and host glideapps pictures into Google Drive"></p>

<p>Enjoy cooking.</p>]]></content:encoded></item><item><title><![CDATA[Dataverse views as Criteria's definitions]]></title><description><![CDATA[<p>Hello,</p>

<p>During project, we often have the need to implement some complex criteria's handling for approval processes for example. <br>
Redevelop this when we are talking about simple conditions if fine. <br>
As soon as we want to be able to manage criteria's like :</p>

<p><mark>Field1 = Value1 &amp;&amp; Field2 = Value2 || Field3 != Value3</mark></p>]]></description><link>https://stuffandtacos.azurewebsites.net/2020/12/10/dataverse-views-as-criterias-definitions/</link><guid isPermaLink="false">dea1580c-cd20-45c2-a78f-97d0a985dd20</guid><category><![CDATA[User Views]]></category><category><![CDATA[dataverse]]></category><category><![CDATA[matrix]]></category><category><![CDATA[criterias]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Thu, 10 Dec 2020 13:13:23 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2020/12/2020_12_10_14-12-57_POWERPNT.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2020/12/2020_12_10_14-12-57_POWERPNT.png" alt="Dataverse views as Criteria's definitions"><p>Hello,</p>

<p>During project, we often have the need to implement some complex criteria's handling for approval processes for example. <br>
Redevelop this when we are talking about simple conditions if fine. <br>
As soon as we want to be able to manage criteria's like :</p>

<p><mark>Field1 = Value1 &amp;&amp; Field2 = Value2 || Field3 != Value3</mark></p>

<p>This is starting to be funnier to develop and especially when you don't want to hardcode anything but keep it flexible. <br>
And if you don't want to rely on the developer as soon as you want to update those conditions, well ...</p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/12/2020_12_09_21-14-35_POWERPNT.png" alt="Dataverse views as Criteria's definitions"></p>

<h3 id="whydataverseviews">Why Dataverse Views ?</h3>

<p>A friend of mine told me once : <br>
<em>"Clément, what if we use the views definition to handle those criterias with a standard functionality of the Dataverse ?"</em>, Fabien Camous.</p>

<p>Sometimes when we have an idea in mind, we stick to it while there are really simpler solution in front of you. Developing the flexible criteria's matrix with json as input VS using the Dataverse Views was a quick choice. <br>
I started to dig into that direction and this was really the great idea.</p>

<p>You are already working with Dataverse so it's open to your usage without extra development and especially the capability of a functional consultant or a key user is "enough" to update the criterias.</p>

<h3 id="goal">Goal ?</h3>

<p>Our goal on that project and in the examples which follow was to make sure that a record was matching some criterias or not and based on that result set some fields values.</p>

<h3 id="howto">How to ?</h3>

<p>The first step will be obviously to create the view : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/12/2020_12_09_21-08-29_msedge.png" alt="Dataverse views as Criteria's definitions"></p>

<p>You can see with the following that we have several criteria's with AND / OR conditions which can be quite complex to implement programmatically from scratch but it took 2 min to do it be the view definition of Dataverse.</p>

<p>As you can see, we have a field called <strong>Opportunity ID</strong> in that sample, this allow use to make sure that we catch the unique Opportunity record, it's a dedicated field with autonumbering but the same thing could be done with the GUID field of the entity. <br>
This Opportunity ID value is set to 9999999 by default to easily replace it with the special record value you are targeting.</p>

<p>Then the next step will be to grab the view GUID in order to use it in your plugin / CWA or wherever you need it.</p>

<p>Here are the snippet code to perform the magic : </p>

<h6 id="1retrievetheviewdefinition">1- Retrieve the view definition</h6>

<p><strong>For one view at a time :</strong>
(savedquery for system views and userquery for personal views)</p>

<pre><code class="language-csharp">var fetchXmlQuery = _service.Retrieve("savedquery", new Guid("VIEWQGUID"), new ColumnSet("fetchxml"));  
</code></pre>

<p><strong>For multiple views at a time :</strong></p>

<pre><code class="language-csharp">var views = ["VIEWGUID1", "VIEWGUID2", "..."]; // could come from somewhere else

var fetchXmlQueries = _service.RetrieveMultiple(new QueryExpression()  
{
    EntityName = "savedquery",
    ColumnSet = new ColumnSet("fetchxml"),
    Criteria =
    {
        Conditions =
        {
            new ConditionExpression("savedqueryid", ConditionOperator.In, views)
        }
    }
});
</code></pre>

<h6 id="2usethefetchxmldefinitiontodynamicallyupdateitandexecuteit">2- Use the fetchXML definition to dynamically update it and execute it</h6>

<pre><code class="language-csharp">foreach (var view in fetchXmlQueries.Entities)  
{
    var fetchXML = view.GetAttributeValue&lt;string&gt;("fetchxml");

    fetchXML = fetchXML.Replace("999999999", oppId);
    var result = this._service.RetrieveMultiple(new FetchExpression(fetchXML)).Entities;

    if (result.Count &gt; 0)
    {
        // Record passing the criterias
        // Perform action
    }               
    else
    {
        // Record NOT passing the criterias
        // Perform action
    }
}
</code></pre>

<p>In that part, we modify the previous value we setup "9999999" into the value of the actual record we want to compare with. <br>
Then executing the updated fetchXML allows us to make sure that we do have a complex valid query.</p>

<p>If we do have a result, it means that the record match the criterias. <br>
If we do not have a result, the criterias are not matching the record value.</p>

<p>Based on the following result you can then perform a specific action and continue your record process.</p>

<h4 id="wheretouseit">Where to use it ?</h4>

<p>The above example is about plugin directly. <br>
You could imagine having the same approach with an Action which could be called via a Flow from a Canvas App. <br>
Using this in an Azure Function to get the return result then. <br>
There are a lot of possible scenario with it which is not "stick" to the classic plugin.</p>

<h4 id="conclusion">Conclusion</h4>

<p>As you can see, we defined a "complex" with its limits of the Dataverse views capacity (which are still quite good) and implemented the logic within a plugin in few minutes when with a complete new logic it could take hours or days !</p>

<p>One recommandation from my side, it is to at most try to execute this in async mode to make sure that you are not slowing the UI during the process if you have many records / views to check. This is a recommandation since we make sure to perform only one request to grab all views definition but you can't get rid of the RetrieveMultiple request for each fetchXML.</p>

<p>Let's say that in that particular project, it was clearly a quick win and hope that quick win can be useful to some of you :</p>

<p>Enjoy, <br>
Cheers</p>]]></content:encoded></item><item><title><![CDATA[Trigger Flow when user is added to access team]]></title><description><![CDATA[<p>Hello everyone,</p>

<p>Today's question is around the triggering a flow from an access team. <br>
Seems simple as it is but you need to dig a bit more to perform the full process.</p>

<h6 id="scenario">Scenario</h6>

<p>My business requirement was to send an email (without code) when user was added to an access</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2020/06/09/trigger-flow-when-user-is-added-to-access-team/</link><guid isPermaLink="false">30286ef1-832c-47bb-a567-828f57168392</guid><category><![CDATA[dynamics 365]]></category><category><![CDATA[Flow]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Tue, 09 Jun 2020 13:27:57 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2020/06/2020_06_08_22-07-33_POWERPNT-1.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2020/06/2020_06_08_22-07-33_POWERPNT-1.png" alt="Trigger Flow when user is added to access team"><p>Hello everyone,</p>

<p>Today's question is around the triggering a flow from an access team. <br>
Seems simple as it is but you need to dig a bit more to perform the full process.</p>

<h6 id="scenario">Scenario</h6>

<p>My business requirement was to send an email (without code) when user was added to an access team.</p>

<p>Main limitation/problem so far is the fact that a flow using the Trigger "When a record is created, updated or deleted" on the <strong>TeamMemberShip</strong> entity will never be fired. <br>
Reason ? Unknows so far ...</p>

<p>As I wanted / had to have the process working, after few research I ended up with the solution : </p>

<ol>
<li>Create your flow with a Http request trigger  </li>
<li>Create a WebHook from the CRM/CDS instance linked to your flow</li>
<li>Add a step on the <strong>AddUserToRecordTeam</strong> message (teamtemplate entity)</li>
<li>Configure the flow</li>
</ol>

<p>Process <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/06/2020_06_08_22-07-33_POWERPNT.png" alt="Trigger Flow when user is added to access team"></p>

<h5 id="flowcreationwebhookconfiguration">Flow creation + Webhook configuration</h5>

<p>It's not needed to rewrite what was nicely explained by other nice people, you can go to <a href="https://www.linkedin.com/in/stefanstrube365/">Stefan's</a> <a href="https://2die4it.com/2018/10/10/using-dynamics-365-webhooks-as-the-third-way-to-trigger-flow/">blog post and check this out</a></p>

<p><mark>And come back right after ! :)</mark></p>

<h5 id="stepconfigurationonthepluginregistrationtool">Step configuration on the Plugin Registration Tool</h5>

<p>Our goal was to trigger the workflow when user was added to an Access Team. <br>
Good point is that there is a dedicated message for that : <strong>AddUserToRecordTeam</strong> but this message can't be linked to the entity where the access team is used (ie : Opportunity or Account). <br>
Nevermind, we will deal with it later !</p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/06/2020_06_08_22-03-30.png" alt="Trigger Flow when user is added to access team"></p>

<h4 id="configuretheflow">Configure the Flow</h4>

<p>Here is the interesting part !</p>

<h5 id="firststep">First step:</h5>

<p>As the flow receive the Plugin context as JSON is to properly parse it. <br>
(This is the most tricky part or not).</p>

<p>What I needed in my use case as information were :</p>

<ul>
<li>GUID of added user</li>
<li>Record Id where the user was added (for the email content)</li>
<li>Entity LogicalName to make sure, the flow was processing a record I was interested in.</li>
</ul>

<p>As soon as you ran your first run of a flow, you will receive the payload of the Plugin Context you are familiar with, should look like that :</p>

<pre><code class="language-json">{
  "BusinessUnitId": "cdddddf5-1d81-ea11-a813-000d3a4b2ac6",
  "CorrelationId": "69b8ac32-688c-4c80-9c93-5d6342178db9",
  "Depth": 1,
  "InitiatingUserAzureActiveDirectoryObjectId": "00000000-0000-0000-0000-000000000000",
  "InitiatingUserId": "9b781be7-d176-404b-9d2f-1d830dae011f",
  "InputParameters": [
    {
      "key": "Record",
      "value": {
        "__type": "EntityReference:http://schemas.microsoft.com/xrm/2011/Contracts",
        "Id": "c6dd5426-XXXX-XXXX-XXXX-d40c7fac5a8e",
        "KeyAttributes": [],
        "LogicalName": "opportunity",
        "Name": null,
        "RowVersion": null
      }
    },
    {
      "key": "TeamTemplateId",
      "value": "d7c67ce4-XXXX-XXXX-XXXX-000d3a2109c9"
    },
    {
      "key": "SystemUserId",
      "value": "b5a6d14b-XXXX-XXXX-XXXX-000d3a210496"
    }
  ],
  "IsExecutingOffline": false,
  "IsInTransaction": true,
  "IsOfflinePlayback": false,
  "IsolationMode": 1,
  "MessageName": "AddUserToRecordTeam",
  "Mode": 0,
  "OperationCreatedOn": "/Date(1589897514394)/",
  "OperationId": "bf9e6242-XXXX-XXXX-XXXX-e052a4653443",
  "OrganizationId": "8f82a087-XXXX-XXXX-XXXX-dad71fee1361",
  "OrganizationName": "org6b6c11a7",
  "OutputParameters": [
    {
      "key": "AccessTeamId",
      "value": "db4e02ac-XXXX-XXXX-XXXX-000d3a2109c9"
    }
  ],
  "OwningExtension": {
    "Id": "813ac1d5-XXXX-XXXX-XXXX-000d3a2109c9",
    "KeyAttributes": [],
    "LogicalName": "sdkmessageprocessingstep",
    "Name": "Access Team: AddUserToRecordTeam of teamtemplate",
    "RowVersion": null
  },
  "ParentContext": null,
  "PostEntityImages": [],
  "PreEntityImages": [],
  "PrimaryEntityId": "00000000-0000-0000-0000-000000000000",
  "PrimaryEntityName": "teamtemplate",
  "RequestId": "bf9e6242-XXXX-XXXX-XXXX-e052a4653443",
  "SecondaryEntityName": "none",
  "SharedVariables": [
    {
      "key": "IsAutoTransact",
      "value": true
    },
    {
      "key": "ChangedEntityTypes",
      "value": [
        {
          "__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
          "key": "team",
          "value": "Update"
        },
        {
          "__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
          "key": "principalobjectaccess",
          "value": "Update"
        },
        {
          "__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
          "key": "teammembership",
          "value": "Update"
        },
        {
          "__type": "KeyValuePairOfstringstring:#System.Collections.Generic",
          "key": "systemuserprincipals",
          "value": "Create"
        }
      ]
    },
    {
      "key": "POADistributionChanged",
      "value": 10117
    }
  ],
  "Stage": 40,
  "UserAzureActiveDirectoryObjectId": "00000000-0000-0000-0000-000000000000",
  "UserId": "9b781be7-XXXX-XXXX-XXXX-1d830dae011f"
}
</code></pre>

<p>And from that JSON schema, I generated the following Parse schema :  </p>

<pre><code class="language-json">{
    "type": "object",
    "properties": {
        "BusinessUnitId": {
            "type": "string"
        },
        "CorrelationId": {
            "type": "string"
        },
        "Depth": {
            "type": "integer"
        },
        "InitiatingUserAzureActiveDirectoryObjectId": {
            "type": "string"
        },
        "InitiatingUserId": {
            "type": "string"
        },
        "InputParameters": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "key": {
                        "type": "string"
                    },
                    "value": {
                        "type": "object",
                        "properties": {
                            "__type": {
                                "type": "string"
                            },
                            "Id": {
                                "type": "string"
                            },
                            "KeyAttributes": {
                                "type": "array"
                            },
                            "LogicalName": {
                                "type": "string"
                            },
                            "Name": {},
                            "RowVersion": {}
                        }
                    }
                },
                "required": [
                    "key",
                    "value"
                ]
            }
        },
        "IsExecutingOffline": {
            "type": "boolean"
        },
        "IsInTransaction": {
            "type": "boolean"
        },
        "IsOfflinePlayback": {
            "type": "boolean"
        },
        "IsolationMode": {
            "type": "integer"
        },
        "MessageName": {
            "type": "string"
        },
        "Mode": {
            "type": "integer"
        },
        "OperationCreatedOn": {
            "type": "string"
        },
        "OperationId": {
            "type": "string"
        },
        "OrganizationId": {
            "type": "string"
        },
        "OrganizationName": {
            "type": "string"
        },
        "OutputParameters": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "key": {
                        "type": "string"
                    },
                    "value": {
                        "type": "string"
                    }
                },
                "required": [
                    "key",
                    "value"
                ]
            }
        },
        "OwningExtension": {
            "type": "object",
            "properties": {
                "Id": {
                    "type": "string"
                },
                "KeyAttributes": {
                    "type": "array"
                },
                "LogicalName": {
                    "type": "string"
                },
                "Name": {
                    "type": "string"
                },
                "RowVersion": {}
            }
        },
        "ParentContext": {},
        "PostEntityImages": {
            "type": "array"
        },
        "PreEntityImages": {
            "type": "array"
        },
        "PrimaryEntityId": {
            "type": "string"
        },
        "PrimaryEntityName": {
            "type": "string"
        },
        "RequestId": {
            "type": "string"
        },
        "SecondaryEntityName": {
            "type": "string"
        },
        "SharedVariables": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "key": {
                        "type": "string"
                    },
                    "value": {
                        "type": "boolean"
                    }
                },
                "required": [
                    "key",
                    "value"
                ]
            }
        },
        "Stage": {
            "type": "integer"
        },
        "UserAzureActiveDirectoryObjectId": {
            "type": "string"
        },
        "UserId": {
            "type": "string"
        }
    }
}
</code></pre>

<p>This will not work 100% of the time like it is, because based on the data you got when you generated the schema, the value properties of the <em>InputParameters</em> can vary. <br>
And of course, you can clean the properties you will never use to keep only the necessary !</p>

<p>The trick here is just to remove the types of those ones in order to tell the parser that they are not all mandatory and it should accept what he receives. No ideal in other cases but here we know what we receive anyway.</p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/06/2020_06_08_22-19-45_POWERPNT.png" alt="Trigger Flow when user is added to access team"></p>

<p>From that standpoint, we do have access to all properties of our PluginContext from the flow. Awesome !</p>

<h5 id="secondstep">Second step:</h5>

<p>Making sure that the flow is triggered for Opportunity entity : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/06/2020_06_08_22-21-43_msedge.png" alt="Trigger Flow when user is added to access team"></p>

<p><code>If LogicalName eq 'opportunity'</code> then we continue else we terminate the flow.</p>

<p>This step is not mandatory if you wish to create a webhook per entity for example and save Flow execution !</p>

<h5 id="thirdstep">Third step:</h5>

<p>Based on the properties of the InputParameters, grab what you need.</p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/06/2020_06_08_22-24-40_msedge.png" alt="Trigger Flow when user is added to access team">
You can see that here the idea is to loop on the InputParameters properties and use a simple switch to process the one you want. <br>
Again in my case, the Added User Id &amp; the Record Id placed in a variable to be used later on.</p>

<p>These are my 2 cents about the : <br>
 <strong>Triggering a flow when user is added to access team in order to send him an email</strong></p>

<p>Enjoy, <br>
Cheers</p>]]></content:encoded></item><item><title><![CDATA[PCF : Any Composite Fields]]></title><description><![CDATA[<p>Hello everyone,</p>

<p>Today's PCF control will be about the Composite Fields ! <br>
As you may saw, with the Unified Interface layout, the composite fields more or less disappeared. By this, I mean that if you add a composite field such as FullName or Address on your form, this will be replaced</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2020/05/19/pcf-any-composite-fields/</link><guid isPermaLink="false">e283d550-c555-4111-9794-3da5da9468c0</guid><category><![CDATA[PCF]]></category><category><![CDATA[ModelDrivenApp]]></category><category><![CDATA[dynamics 365]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Tue, 19 May 2020 11:28:38 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2020/05/2020_05_18_15-35-29_POWERPNT.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2020/05/2020_05_18_15-35-29_POWERPNT.png" alt="PCF : Any Composite Fields"><p>Hello everyone,</p>

<p>Today's PCF control will be about the Composite Fields ! <br>
As you may saw, with the Unified Interface layout, the composite fields more or less disappeared. By this, I mean that if you add a composite field such as FullName or Address on your form, this will be replaced by all fields which are in the composite field itself.</p>

<p><strong>Example:</strong> 
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/05/2020_05_18_13-23-03_POWERPNT.png" alt="PCF : Any Composite Fields"></p>

<p>For some user interface experience, it was really nice to have those composite fields available, that's why I've tried to develop one which is <em>flexible</em> !</p>

<h4 id="demo">Demo</h4>

<p><img src="https://carfupstorage.blob.core.windows.net/sharex/AnyCompositeFields_demo.gif" alt="PCF : Any Composite Fields" title=""> </p>

<h3 id="wherecanigetthatawesomecontrol">Where can I get that awesome control ?</h3>

<p>Jump to my <a href="https://github.com/carfup/PCFControls">github repo for the source code</a> or just use the below button to access the managed or unmanaged solutions : <br>
<a href="https://github.com/carfup/PCFControls/releases"><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/04/icons8-download-from-the-cloud-150.png" alt="PCF : Any Composite Fields" title=""></a></p>

<h4 id="listofcapabilities">List of capabilities :</h4>

<ul>
<li>You have the choice to return the composite value to the control field holder or not.</li>
<li>You can map up to 8 fields to compose whatever data you want. No limitation in terms of combination. Available fields to be mapped are text, email and phone ones.</li>
<li><p>You can define your own separator which will be displayed between each values of the composite field</p>

<p>A tiny special case has to be handled for the "space" as separator, a simple " " as parameter is not working so you will have to enter "%20" as separator in the configuration panel.</p></li>
<li><p>Locking the control <em>field holder</em> will set all fields as "Read Only" mode from the composite control
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/05/2020_05_18_13-32-01_POWERPNT.png" alt="PCF : Any Composite Fields"></p></li>
<li><p>Setting a mapped field as "Read Only" mode on your form will set independently as "Read Only" mode the field on the composite control while the others will be still available and editable.
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/05/2020_05_18_13-36-39_POWERPNT.png" alt="PCF : Any Composite Fields"></p></li>
<li><p>The control will get the latest value of any mapped field (even if it's updated outside of the control itself).</p></li>
</ul>

<h4 id="limitation">Limitation</h4>

<p>If you set fields to Read Only mode using Business Rules or JavaScript, it won't reflect into the PCF control. <br>
The control can't be attached to an existing Composite field (ie : fullname, address_composite,...) <br>
<del>To use address fields in the control as parameter, please check the <a href="https://www.magnetismsolutions.com/blog/jaredjohnson/2019/07/04/binding-to-address-fields-in-a-pcf-control">following blog post</a></del></p>

<h3 id="wrapup">Wrap-up</h3>

<p>By sharing this control, I hope it can help the user experience on the UCI. This can clearly save space on your form without loosing interesting data.</p>

<p>Enjoy this one ! <br>
Cheers,</p>]]></content:encoded></item><item><title><![CDATA[PCF : Quick Edit Form]]></title><description><![CDATA[<p>Hello everyone,</p>

<p>Today, I'm really pleased to announce my latest PCF control. <br>
You know the Quick View Form which are used to display data from a related lookup, but unfortunately, you can't handle the rendering and it's only a read-only rendering.</p>

<p>Those limitations are now <strong>OVER</strong> !</p>

<h3 id="whatisthequickeditform">What is the Quick</h3>]]></description><link>https://stuffandtacos.azurewebsites.net/2020/04/15/pcf-quick-edit-form/</link><guid isPermaLink="false">9208353d-16d1-4790-84b2-c5814a0f37dc</guid><category><![CDATA[PCF]]></category><category><![CDATA[ModelDrivenApp]]></category><category><![CDATA[dynamics 365]]></category><category><![CDATA[QuickEditForm]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Wed, 15 Apr 2020 12:09:39 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2020/04/2020_04_12_22-10-00_msedge-1.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2020/04/2020_04_12_22-10-00_msedge-1.png" alt="PCF : Quick Edit Form"><p>Hello everyone,</p>

<p>Today, I'm really pleased to announce my latest PCF control. <br>
You know the Quick View Form which are used to display data from a related lookup, but unfortunately, you can't handle the rendering and it's only a read-only rendering.</p>

<p>Those limitations are now <strong>OVER</strong> !</p>

<h3 id="whatisthequickeditform">What is the Quick Edit Form ?</h3>

<p>The Quick Edit Form PCF control will allow you to reuse a Quick View Form definition to display the related form and allow you or your user to edit this related record directly within the parent one.</p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/04/2020_04_12_22-10-00_msedge.png" alt="PCF : Quick Edit Form"></p>

<h3 id="wherecanigetthatawesomecontrol">Where can I get that awesome control ?</h3>

<p>Jump to my <a href="https://github.com/carfup/PCFControls">github repo for the source code</a> or just use the below button to access the managed or unmanaged solutions : <br>
<a href="https://github.com/carfup/PCFControls/releases"><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/04/icons8-download-from-the-cloud-150.png" alt="PCF : Quick Edit Form" title=""></a></p>

<h3 id="listofcapabilities">List of capabilities :</h3>

<ul>
<li><a href="https://stuffandtacos.azurewebsites.net/2020/04/15/pcf-quick-edit-form/#savedatafromyourlookup">Save Data from your Lookup</a></li>
<li><a href="https://stuffandtacos.azurewebsites.net/2020/04/15/pcf-quick-edit-form/#handlinglanguages">Handling 12 languages so far</a></li>
<li><a href="https://stuffandtacos.azurewebsites.net/2020/04/15/pcf-quick-edit-form/#emptylookupmessage">Display dedicated message while the mapped Lookup field is empty</a></li>
<li><a href="https://stuffandtacos.azurewebsites.net/2020/04/15/pcf-quick-edit-form/#recordinreadonlymode">Display the form even if the record is in read only mode</a></li>
<li><a href="https://stuffandtacos.azurewebsites.net/2020/04/15/pcf-quick-edit-form/#reloaddynamicallytherecordwithguidrecord">Advised Users, when enabling the option "UseTextFieldAsLookup" and displaying the binded field, you can reload the record on the fly</a></li>
</ul>

<h5 id="savedatafromyourlookup">Save Data from your Lookup</h5>

<p>Of course, this is the most important capability of the PCF control. <br>
Giving you the ability to modify the values from the mapped lookup record. <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/04/2020_04_09_17-31-41.gif" alt="PCF : Quick Edit Form"></p>

<h5 id="handlinglanguages">Handling languages</h5>

<p>So far, we are dealing with two languages in the PCF for the "static" display such as : Refresh, Save, the messages, ... <br>
It's open to any languages you want, I would just need some help for the translation in the others :) <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/04/2020_04_09_17-34-05.gif" alt="PCF : Quick Edit Form"></p>

<p>Available translations so far : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/04/2020_04_30_15-58-43_POWERPNT.png" alt="PCF : Quick Edit Form"></p>

<h5 id="emptylookupmessage">Empty Lookup message</h5>

<p>When the lookup field which is mapped to the PCF control is empty, we display a message explaining why nothing is rendered. That way, the user is aware that it's not an issue with the control but a missing data on the record. <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/04/2020_04_09_17-32-53.gif" alt="PCF : Quick Edit Form"></p>

<h5 id="recordinreadonlymode">Record in Read Only mode</h5>

<p>It can happen that the record mapped with the PCF can be deactivated or in any other state than "active". In this case, the control is still able to render the data but in a read only mode. This will allow the users to at least see the related data. <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/04/2020_04_09_17-44-08.gif" alt="PCF : Quick Edit Form"></p>

<h5 id="reloaddynamicallytherecordwithguidrecord">Reload dynamically the record with GUID record</h5>

<p>The primary use of the control is to render the data from a related lookup field on the record. But for easier rendering or even data check as example, it's also possible to load dynamically records based on their GUIDs. <br>
By enabling a property in the PCF control configuration, you can use the text field which the PCF control is attached to and just copy/paste the guid of the record you want to display in it. <br>
Of course all the capabilities explained above are still working. <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2020/04/2020_04_09_17-56-02.gif" alt="PCF : Quick Edit Form"></p>

<p><strong>Fields supported :</strong></p>

<ul>
<li>Text field</li>
<li>Money field</li>
<li>Textarea field</li>
<li>Lookup field</li>
<li>Boolean field</li>
<li>Date/datetime field</li>
<li>Optionset field</li>
<li>Multiselect-optionset field</li>
<li>Customer field</li>
<li>Regarding field</li>
<li>Owner Field</li>
<li>StatusCode / StateCode Field</li>
</ul>

<h3 id="configurationandparameters">Configuration and parameters</h3>

<ul>
<li><strong>FieldToAttachControl</strong> : Field to attach the control (required)</li>
<li><strong>QuickVIewFormId</strong> : Guid of the Quick View Form you want to use to display the fields (<em>required</em>)</li>
<li><strong>LookupFieldMapped</strong> : This is the technical name of the lookup field used as reference - ex : <em>_primarycontactid_value</em> (for a contact from an account) (<em>required</em>)</li>
<li><strong>UseTextFieldAsLookup</strong> : Give the ability to the control to dynamically load data based on the GUID put in the mapped field, skipping the value from the lookup except if the field value is empty (<em>required</em>)</li>
</ul>

<h3 id="limitation">Limitation</h3>

<p>You have to know one thing using this control. There will be no "extra logic" applied to the fields displayed. <br>
By Extra logics, I mean Javascripts, Business Rules (form level).</p>

<h3 id="wrapup">Wrap-up</h3>

<p>I really hope that control can be useful for anyone. I know that it can be frustrating to see related data on a form and not having the possibility to edit it in an other way than opening the record. <br>
It was a great challenge for me as well to develop that PCF as I'm quite new with the Power Apps component Framework and it allowed me to discover the real use of Fluent UI controls (UI Fabric) and the react technology to interact with those, which is amazing!</p>

<p><em>A next blog post will come later on with the technical details of that control.</em></p>

<p>Enjoy this one ! <br>
Cheers,</p>]]></content:encoded></item><item><title><![CDATA[Unit test Azure Service Bus routing]]></title><description><![CDATA[<h1 id="mockservicebus">MockServiceBus</h1>

<p>Supporting &amp; maintaining <a href="https://docs.microsoft.com/en-us/azure/service-bus-messaging/topic-filters">Azure Service Bus routing rules</a> could be tricky to design without regressions and unexpected behaviors.</p>

<p><code>MockServiceBus</code> with help of <a href="https://www.nuget.org/packages/TSQL.Parser/">TSQL.Parser</a> provides solution to unit test your subscriptions routing.</p>

<p><a href="https://www.nuget.org/packages/MockServiceBus"><img src="https://img.shields.io/nuget/v/MockServiceBus.svg" alt="Nuget" title=""></a></p>

<blockquote>
  <p>Install-Package MockServiceBus</p>
</blockquote>

<h2 id="basicexample">Basic example</h2>

<p>A brokered message with custom property <code>flag=1</code> to be correctly <code>transfered</code> for</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2020/03/21/unit-test-azure-service-bus-routing/</link><guid isPermaLink="false">e82f8d8d-2811-4975-9c08-fd28858b30f0</guid><dc:creator><![CDATA[Fabien Camous]]></dc:creator><pubDate>Sat, 21 Mar 2020 19:14:05 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2020/03/dots_public_domain_crop_0.jpg" medium="image"/><content:encoded><![CDATA[<h1 id="mockservicebus">MockServiceBus</h1>

<img src="http://undefined.azurewebsites.net/content/images/2020/03/dots_public_domain_crop_0.jpg" alt="Unit test Azure Service Bus routing"><p>Supporting &amp; maintaining <a href="https://docs.microsoft.com/en-us/azure/service-bus-messaging/topic-filters">Azure Service Bus routing rules</a> could be tricky to design without regressions and unexpected behaviors.</p>

<p><code>MockServiceBus</code> with help of <a href="https://www.nuget.org/packages/TSQL.Parser/">TSQL.Parser</a> provides solution to unit test your subscriptions routing.</p>

<p><a href="https://www.nuget.org/packages/MockServiceBus"><img src="https://img.shields.io/nuget/v/MockServiceBus.svg" alt="Unit test Azure Service Bus routing" title=""></a></p>

<blockquote>
  <p>Install-Package MockServiceBus</p>
</blockquote>

<h2 id="basicexample">Basic example</h2>

<p>A brokered message with custom property <code>flag=1</code> to be correctly <code>transfered</code> for subscription1 and <code>ignored</code> for subscription2.</p>

<p><code>NameSpace.AssertRouting(String topicname, Message message, Dictionary expectedResults)</code></p>

<script src="https://gist.github.com/camous/45ed510cc14e1b0d9fba4e02b62bdbca.js"></script>  

<p>will return green test result</p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/03/2020-03-21-19-34-31.png" alt="Unit test Azure Service Bus routing"></p>

<ul>
<li>changing the flag value without changing expected outcome</li>
</ul>

<pre><code>            var message = new Message
            {
                CustomProperties = new Dictionary&lt;string, object&gt;
                {
                    { "flag", "2" },
                }
            };
</code></pre>

<blockquote>
<pre><code>Assert.AreEqual failed. Expected:&lt;Transfered&gt;. Actual:&lt;Ignored&gt;. subscription1
</code></pre>
  
  <p><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/03/2020-03-21-19-29-22.png" alt="Unit test Azure Service Bus routing"></p>
</blockquote>

<ul>
<li>not declaring expected output for a specific subscription</li>
</ul>

<pre><code>            servicebus.AssertRouting("topic", message, new Dictionary&lt;string, MessageState&gt; {
                { "subscription1", MessageState.Transfered }
            });
</code></pre>

<blockquote>
  <p>Assert.Fail failed. unexpected subscribers subscription2</p>
</blockquote>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2020/03/2020-03-21-19-32-12.png" alt="Unit test Azure Service Bus routing"></p>

<h2 id="castingnumbers">Casting numbers</h2>

<p>MockServiceBus needs a litle help for <code>number</code> types with prefixing with <code>{Int32} fieldname</code>. <strong>space is important</strong></p>

<p>Switching from <code>flag='1'</code> to <code>flag=1</code>  </p>

<pre><code>            var subscription1 = new Subscription { Name = "subscription1", Rules = new List&lt;Rule&gt; { new Rule { Filter = "{Int32} flag=1" } } };

            var message = new Message
            {
                CustomProperties = new Dictionary&lt;string, object&gt;
                {
                    { "flag", 1 },
                }
            };
</code></pre>

<h2 id="supportedfeatures">Supported features</h2>

<p>Full list not available now, but complex queries are supported</p>

<blockquote>
  <p>NOT EXISTS([forcedestination]) AND NOT EXISTS([subitem]) AND [fromsystem] != '{system}' AND [reference.crmguid] != 'null' AND {Int32} [contract.active] = 1  AND (NOT EXISTS([startdelta]) OR {Int32} [startdelta] >= 0) AND ([fromsystem] != 'sap'</p>
</blockquote>

<h2 id="next">Next ?</h2>

<ul>
<li>whole structure of topics and subscriptions (+ rules) can be loaded from json file</li>
<li>re-using same structure files &amp; unit test for automatically updating subscriptions rules in Azure Service Bus</li>
</ul>]]></content:encoded></item><item><title><![CDATA[File field Manager for Model driven App !]]></title><description><![CDATA[<p>Hello everyone,</p>

<p>As you may know, Microsoft is currently deploying a new type of field on your favorite CDS environments : the Files ! </p>

<p>Currently, you have the possibility to create the fields and use them on Flow or Canvas App, there is no current possibility to use them on a model</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2019/12/27/file-field-manager-for-model-driven-app/</link><guid isPermaLink="false">00ab852c-9d41-4d90-bf49-0d5eef9f19e2</guid><category><![CDATA[dynamics 365]]></category><category><![CDATA[PCF]]></category><category><![CDATA[ModelDrivenApp]]></category><category><![CDATA[File Field]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Fri, 27 Dec 2019 10:44:11 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2019/12/2019-12-27_11-23-35_chrome.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2019/12/2019-12-27_11-23-35_chrome.png" alt="File field Manager for Model driven App !"><p>Hello everyone,</p>

<p>As you may know, Microsoft is currently deploying a new type of field on your favorite CDS environments : the Files ! </p>

<p>Currently, you have the possibility to create the fields and use them on Flow or Canvas App, there is no current possibility to use them on a model driven app form. That's where this control comes into the light !</p>

<p>There are 2 possibilities to use the control :</p>

<ul>
<li>with fields on the same entity (you can upload one file per field) - <em>Left side on the demo</em></li>
<li>with fields which are on a sub entity (you can upload as many files as you want !) - <em>Right side on the demo</em></li>
</ul>

<h4 id="demo">Demo :</h4>

<p><img src="https://carfupstorage.blob.core.windows.net/sharex/2019-12-26_15-12-25.gif" alt="File field Manager for Model driven App !"></p>

<h4 id="details">Details</h4>

<p>You can find the source code and the details of the control on my <a href="https://github.com/carfup/PCFControls/">GitHub repo</a> <br>
You have the <a href="https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/file-attributes">WebApi available calls</a> to manage files.</p>

<p>In quick words, here is the process to upload the files to the File Field : </p>

<ol>
<li>Create the record hosting the file(s) (if it's not done yet)  </li>
<li>Choose the File from the input button  </li>
<li>Convert this file into Base64 format  </li>
<li>To Patch the record with the file, you need : FileName + FileContent into an ArrayBuffer  </li>
<li>Your data is available !</li>
</ol>

<h3 id="configurationsample">Configuration sample :</h3>

<ol>
<li>For file in the same entity :</li>
</ol>

<p>In that sample, my entity is <code>carfup_entitywithfile</code> and my file field name is : <code>carfup_primaryfile</code> <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/12/2019-12-27_11-34-23_POWERPNT.png" alt="File field Manager for Model driven App !"></p>

<ol>
<li>For files in a sub entity: <br>
In that sample, my parent entity is <code>carfup_entitywithfile</code>, my sub entity hosting the files is <code>carfup_customattachment</code> and my file field name is : <code>carfup_file</code></li>
</ol>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2019/12/2019-12-27_11-40-25_POWERPNT.png" alt="File field Manager for Model driven App !"></p>

<h3 id="download">Download</h3>

<p>In order to download the package, you can go to <a href="https://github.com/carfup/PCFControls/releases/tag/1.1.0.0">the release</a> tab of the repo. <br>
You will find the unmanaged/managed version of the solution and the source code too if you want to improve the control !</p>

<p>I hope you will like it and enjoy the work. <br>
I wish you a great end of the year 2019.</p>

<p>Cheers, <br>
Clément</p>]]></content:encoded></item><item><title><![CDATA[Canvas apps and Offline tips and tricks]]></title><description><![CDATA[<p>Hello everyone,</p>

<p>Let's talk about quite complex/surprising subjects around Canvas apps. <br>
The main one will be around offline management in canvas apps, for a client we have a requirement to manage offline capabilities on our latest PowerApps Canvas application. But I will talk about other things which are good</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2019/11/05/canvas-apps-and-offline-tips-and-tricks/</link><guid isPermaLink="false">d2c610d0-5230-40c0-951d-dcb6bdd8f2a3</guid><category><![CDATA[canvas app]]></category><category><![CDATA[cds]]></category><category><![CDATA[offline]]></category><category><![CDATA[power apps]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Tue, 05 Nov 2019 12:47:46 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2019/11/2019-11-05_13-44-25_POWERPNT-1.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2019/11/2019-11-05_13-44-25_POWERPNT-1.png" alt="Canvas apps and Offline tips and tricks"><p>Hello everyone,</p>

<p>Let's talk about quite complex/surprising subjects around Canvas apps. <br>
The main one will be around offline management in canvas apps, for a client we have a requirement to manage offline capabilities on our latest PowerApps Canvas application. But I will talk about other things which are good to know when you create your projects around that application.</p>

<p>We know that the offline capability exist on canvas apps : <a href="https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/offline-apps?WT.mc_id=BA-MVP-5003014">offline documentation</a>, so what's the big deal you would say ?</p>

<p>Unfortunately we faced some unexpected issues and found out some interesting tips and tricks to have in mind when you will have to implement such a thing.</p>

<p>Here is the offline scenario we had to build with offline possibilites : </p>

<ul>
<li>Usage of the entire app offline with possibility to load/save data from/to the CDS instance on the first and last screen.</li>
<li>Manage records with local collections</li>
<li>Link records from various collection between them</li>
<li>Load all data from an entity (not only the basic fields such as : text, int, date, ...) ie : Lookups</li>
</ul>

<p>Let's give you some tips &amp; tricks around the Canvas apps and also Offline capabilities</p>

<h2 id="tipsandtricks">Tips and tricks :</h2>

<p>For the following points, let's use this entities structure in the CDS: <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/10/2019-10-28_14-15-45_POWERPNT.png" alt="Canvas apps and Offline tips and tricks"></p>

<h4 id="1loadrelatedlookupvaluesinlocalcollectionoffline">1. Load related lookup values in local collection (offline)</h4>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2019/10/2019-10-08_23-49-16_chrome.png" alt="Canvas apps and Offline tips and tricks">
Starting from the fact that you have a Car records with N Wheel records linked to a car.</p>

<p>When working on local collections, you have to be aware that a simple : <br>
<code>ClearCollect(WheelCollection, Wheels);</code> won't load all related records (ie : car lookup) by default.</p>

<p>In order to make sure that you have loaded these data when you retrieve everything from the CDS, you have to make sure that at least one screen is using the attribute. <br>
Using the attribute in a query won't be enough.</p>

<p>Quite <em>dirty</em> but efficient solution I used : <br>
Create a dummy screen with label controls using the lookups i'm looking for such as <code>First(WheelCollection).Car.Name</code>. That line will make sure that when you retrieve the Wheel collection, the Car lookup will be loaded by default as well.</p>

<p>Last point here, make sure that the "core" entity and the related entities are connected to the same environment. If you have the entity Car on the CDS (current environment) and the Wheels on the CDS Dev instance, it won't work.</p>

<h4 id="2multiplelevelsofexpansionarenotsupported">2. Multiple levels of expansion are not supported</h4>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2019/10/2019-10-08_23-41-32_chrome.png" alt="Canvas apps and Offline tips and tricks">
It's possible that you face that Notification error while using the application on your mobile or tablet device.</p>

<p>This would simply be caused by a call on a screen control like : <br>
<code>First(BrandCollection).Car.Wheel.Name</code> this will use 2 levels of linked entity which is not allowed when querying data from the WebApi (which is doing the canvas app in the background when querying data).</p>

<p><mark>To spot it</mark></p>

<p>You can simply follow the application scenario from your favorite browser with a develop tool opened. When you will end on the screen with the issue, you can see the network call with the exact webapi call which is falling and in the details you can see the entity and field causing the issue in it.</p>

<p><mark>To fix it</mark></p>

<p>In that case, you have to use the <code>Lookup</code> function to load the first row of data then retrieving the wanted attribute.</p>

<p>IE : <code>Lookup(Cars, Car.Car = First(WheelCollection).Car, Brand).Name</code> <br>
This will return the brand name of a car which is filtered by a wheel property.</p>

<h4 id="3creatingnewrecordsonlocalcollectionoffline">3. Creating new records on local Collection <em>(offline)</em></h4>

<p>When using local collections to manage your data (without internet in our case), you will use collections and add/update/remove record actions in it.</p>

<p>I will focus on the <strong>add</strong> action here. <br>
Here is our process : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/10/2019-10-09_00-07-30_POWERPNT.png" alt="Canvas apps and Offline tips and tricks"></p>

<p>As you can see based on the picture above, when creating a record with specified fields, each fields not included on the creation <strong>CAN'T</strong> be updated later on. You have to be carefull to initialize the record with all data needed in the first place.</p>

<p>In this example, you would make sure that during the creation you specify the name <strong>AND</strong> the Car lookup even if it's with a blank value.</p>

<p>Solution : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/10/2019-10-09_00-17-34_POWERPNT.png" alt="Canvas apps and Offline tips and tricks"></p>

<h4 id="4optimizethescreensloading">4. Optimize the screens loading</h4>

<p>When opening a screen from an other, you have several options. <br>
Indeed, opening a screen with heavy logic or a lot of controls can take a while and this is not user friendly.</p>

<p>To optimize that you have an easy improvement : <mark>the screen LoadingSpinner property</mark></p>

<ul>
<li>LoadingSpinner.Controls : show a loader while all controls are loading properly</li>
<li>LoadingSpinner.Data : show a loader while all data are loaded properly</li>
</ul>

<p>Here is a sample in video : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/10/0.gif" alt="Canvas apps and Offline tips and tricks">
<em>credit : Nicolas Kirrmann</em></p>

<h4 id="5localcollectionswithlookupstocdsoffline">5. Local collections (with lookups) to CDS <em>(offline)</em></h4>

<p>When exclusively working with local collections (including lookups) in your app you have to deal with an issue : <br>
How will you link the new records without the generated GUID from your data source ?.</p>

<p>In order to link our records : Cars and Wheels, we need to have the Car GUID to link a wheel with a car obviously.</p>

<p>Good point is that when you use the Patch function, you can specify any property added to the object you are creating using the <code>Defaults(entity)</code> function.</p>

<p>Here is a sample to illustrate the above explanation  </p>

<pre><code>// Preparing our 2 collections
ClearCollect(CarCollection, Cars);  
ClearCollect(WheelCollection, Wheels);

/* Create a new Car record in the collection locally (only) 
   forcing the GUID of the record */
Patch(CarCollection, Defaults(Cars), {  
    carfup_carid : GUID(),
    carfup_name : "New Car"
});

/* Create a new Wheel record in the collection locally (only)
   forcing the GUID of the record and using the forced
   car GUID to link them together. */
Patch(WheelCollection, Defaults(Wheels), {  
    carfup_wheelid : GUID(),
    carfup_name : "New Wheel",
    carfup_Car: Last(CarCollection)
});
</code></pre>

<p>Result : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/10/2019-10-16_01-41-45_POWERPNT.png" alt="Canvas apps and Offline tips and tricks"></p>

<p>So far, we have records on our local collection with links between the Cars and the Wheels.</p>

<p>The next step would be to Patch the datasource with our local collections.</p>

<h6 id="auploadthecorerecords">a. Upload the "core" records</h6>

<p>By "core" records, I mean the records which are used as parent in your entity architecture (ie : brands or cars here).</p>

<p>For Entities with no lookups you can simply use the following line of code : <code>Patch(Cars, CarCollection);</code> the good thing with that is that it will generate a new record in the CDS with the forced GUID. That way you have the possibility to keep the local GUID which match the CDS GUID. </p>

<p><mark>! Attention !</mark> : this works as seen but according to Microsoft, they do not recommand to force the GUID and use it to push the value to your datasource. At your own risk !</p>

<p>Indeed the fact that you could force the GUID when it's supposed to be the datasource can break the GUID generation logic and the indexes on your datasource.</p>

<h6 id="buploadtherelatedrecords">b. Upload the "related" records</h6>

<p>By "related" records, I mean the records which contains lookups with your "core" records.</p>

<p>The above way to create records won't work when you have to specify custom lookups within your patch. <br>
You will get the following as answer from the server : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/10/2019-10-24_21-47-38_chrome.png" alt="Canvas apps and Offline tips and tricks"></p>

<p>The following error message tells you that the Patch function tries to update an existing record while you are trying to create one. Since the record doesn't exist in the target source yet, the messsage makes sense. <br>
Also one really important thing you need to make sure before trying to push related records to your CDS, you HAVE TO load your core records in the datasource before even if you have those locally. <br>
Of course when you will push the related records to CDS, it will try to link an existing core records in the CDS with your newly created related record.</p>

<p>In order to create your related records, you will have to avoid the forced GUID and then retrieve it from your datasource to have consistent data in your local app.</p>

<p>Here is our approach on that scenario : <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/11/2019-11-22_14-25-38_POWERPNT.png" alt="Canvas apps and Offline tips and tricks"></p>

<p>Regarding the steps 1, 2 and 3, follow the instructions detailled above.</p>

<p>We will now focus the point 4 on the scenario, here is a piece of code :  </p>

<pre><code>// Get the wheels from the CDS
Collect(WheelCollection, Wheels);

// Add 2 new records to our local collection of wheels (with lookup to a Car)
Patch(WheelCollection, Defaults(Wheels),  
    {
        Wheel : GUID(),
        Name: "New local Wheel",
        Car: Last(CarCollection)
    }
);
Patch(WheelCollection, Defaults(Wheels),  
    {
        Wheel : GUID(),
        Name: "New local Wheel 2",
        Car: Last(CarCollection)
    }
);
// For each wheel in the collection, we push it to the CDS without forced GUID
// We removed the Wheel : GUID() line here.
ForAll(  
    WheelCollection,
    Patch(Wheels, Defaults(Wheels),
        {
            Name: WheelCollection[@Name],
            Car: WheelCollection[@Car]
        }
    )
);

// We refresh our local collection with the new values from the CDS
ClearCollect(WheelCollection, Wheels);  
</code></pre>

<p>To clear what we've just done with the code above : </p>

<ol>
<li>We get the values from our CDS instance for the wheels entity into a local collection  </li>
<li>We add 2 records on our local collection with forced GUID which could be use to link records or query it.  </li>
<li>For each record with forced GUID in our collection, we Patch it to our CDS instance without the GUID (as we want the CDS to generate it).  </li>
<li>We retrieve the values from CDS in our local collection so we have the latest data in our collection.</li>
</ol>

<p>And tada, you're now able to manage local collections with local records and push them to your datasource without bad surprises.</p>

<p>I hope all these will help you create the best apps for your customer.</p>

<p>Happy Power Platform'in, <br>
Clément</p>

<p><em>Thanks to <a href="https://www.linkedin.com/in/michel-kanaan-4b053916a/">Michel</a> for his help on that topic !</em></p>]]></content:encoded></item><item><title><![CDATA[Test json files & schema within Microsoft devops build pipeline]]></title><description><![CDATA[<p>We use several pure json file git repositories in devops for storing &amp; tracking configuration. <br>
Some of these files are directly used by underlying systems (not critical mission tools, but still painful when failing) by web services querying git json files through devops <a href="https://docs.microsoft.com/en-us/rest/api/azure/devops/git/items/">API</a></p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2019/05/chrome_L7FUyAvMtb.png" alt=""></p>

<p>Beside taking care of what we</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2019/05/30/test-json-files/</link><guid isPermaLink="false">17701fb3-db34-4db2-bbb2-11086956eecb</guid><dc:creator><![CDATA[Fabien Camous]]></dc:creator><pubDate>Thu, 30 May 2019 20:54:43 GMT</pubDate><media:content url="http://undefined.azurewebsites.net/content/images/2019/06/chrome_8ezOzp5utC.png" medium="image"/><content:encoded><![CDATA[<img src="http://undefined.azurewebsites.net/content/images/2019/06/chrome_8ezOzp5utC.png" alt="Test json files & schema within Microsoft devops build pipeline"><p>We use several pure json file git repositories in devops for storing &amp; tracking configuration. <br>
Some of these files are directly used by underlying systems (not critical mission tools, but still painful when failing) by web services querying git json files through devops <a href="https://docs.microsoft.com/en-us/rest/api/azure/devops/git/items/">API</a></p>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2019/05/chrome_L7FUyAvMtb.png" alt="Test json files & schema within Microsoft devops build pipeline"></p>

<p>Beside taking care of what we commit, <code>error is human</code>, without an automatic check, you can't ensure that there was no typo or incorrect schema used for pushed json. Even worse, you realize later bringing un-necessary stress &amp; confusion.</p>

<p>Addressing this point shouldn't be un-doable, plenty solutions for validating json &amp; jsonschema exists, and pre-commit hook are supported by git, sounds good, as described in this good <a href="https://jakebinstein.com/blog/validating-json-against-a-schema-on-commit/">article</a>. </p>

<p>Unfortunately, I try to bring json file edition to poweruser (and not IT people) and this solution seems overkill and server side hook in <code>devops</code> aren't supported. </p>

<p><a href="https://stackoverflow.com/questions/54213052/azure-devops-server-side-git-hooks">stackoverflow</a> suggests using branch policy and external validation service, but again overkill for my needs.</p>

<p>OK ! let's do it in devops build pipeline. Ok, what should we used for being as simple as possible to setup &amp; maintains and where I had some experience.</p>

<ul>
<li>nodejs/javascript <a href="https://www.npmjs.com/package/ajv">ajv</a> package, but will require extra work to create &amp; build a project</li>
<li>C# <a href="https://www.nuget.org/packages/NJsonSchema/">NjsonSchema</a> for C# ecosystem, but same situation as nodejs one</li>
</ul>

<p>Seeing the amount of extra work &amp; possible future maintenance, I tried another approach on something already supported by devops pipeline : typed <code>json schema powershell</code> in a search engine. And it was a pretty good idea.</p>

<p><a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/test-json">Test-Json</a> cmdlet introduced in powershel core 6.1 allows schema validation. As Microsoft devops supports inline powershell, seems the best no brainer approach
.</p>

<p>My pre-requisites</p>

<ul>
<li>All json files are in the same folder</li>
<li>Schema file (one for all) is located in the same folder</li>
<li>Validation should scan all json files per default &amp; support exclusion</li>
<li>All errors should be printed out and not stopped on first one</li>
</ul>

<p>In a devops build task, add a <code>powershell</code> task and ensure to select <code>Use PowerShell Core</code>. If you are managing yourself, your build agent, you might have to install powershell core binaries for supporting <code>Test-Json</code> cmdlet. <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/05/chrome_QzoYVD309Y.png" alt="Test json files & schema within Microsoft devops build pipeline"></p>

<p>Below script supports 2 environment variables</p>

<ul>
<li><code>schema</code> : filename of json schema file</li>
<li><code>exclude_json</code> (comma separated array) : json file excluded from validation </li>
</ul>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2019/05/chrome_k3wx4veDg8.png" alt="Test json files & schema within Microsoft devops build pipeline"></p>

<script src="https://gist.github.com/camous/d4e134d717fd786069b0f88a200736b6.js"></script>

<h3 id="outputifvalidationfails">output if validation fails</h3>

<p>pure json parsing error <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/05/chrome_8ezOzp5utC.png" alt="Test json files & schema within Microsoft devops build pipeline">
schema error <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/05/chrome_mieHMWpS18.png" alt="Test json files & schema within Microsoft devops build pipeline"></p>

<h3 id="msteamsnotification">msteams notification</h3>

<p>using msteams devops connector on a channel, close to real time, you could notify of a build failure <br>
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/05/Teams_897wm1OeaY.png" alt="Test json files & schema within Microsoft devops build pipeline">
<img src="https://stuffandtacos.azurewebsites.net/content/images/2019/05/Teams_6CCXr5OWih.png" alt="Test json files & schema within Microsoft devops build pipeline"></p>]]></content:encoded></item><item><title><![CDATA[Business Process Flow migration]]></title><description><![CDATA[<p>Hello everyone,</p>

<p>Today, I'd like to focus on the Business Process flow part of the Dynamics 365 CRM.</p>

<p>A little bit of context here, 2 weeks ago, I had the huge chance to attend the Global MVP Summit in Seattle/Redmond, and during some exchanges with other CRM MVPs, I</p>]]></description><link>https://stuffandtacos.azurewebsites.net/2019/04/25/business-process-flow-migration/</link><guid isPermaLink="false">911f6480-2727-436e-b48c-2c800b7c9d8f</guid><category><![CDATA[dynamics 365]]></category><category><![CDATA[MIGRATION]]></category><category><![CDATA[business process flow]]></category><dc:creator><![CDATA[Clement]]></dc:creator><pubDate>Thu, 25 Apr 2019 08:39:57 GMT</pubDate><content:encoded><![CDATA[<p>Hello everyone,</p>

<p>Today, I'd like to focus on the Business Process flow part of the Dynamics 365 CRM.</p>

<p>A little bit of context here, 2 weeks ago, I had the huge chance to attend the Global MVP Summit in Seattle/Redmond, and during some exchanges with other CRM MVPs, I heard a great idea coming from <a href="https://www.linkedin.com/in/ggonzalez2/">Gus Gonzalez</a> : "What if we could create a tool to migrate records to the same BPF but different stage or to another BPF and selected stage ?". <br>
I didn't wait long before I initiated the Visual Studio project on my laptop and started to investigate the possibilities ! :-)</p>

<p>That said, I've the pleasure to introduce you our latest XrmToolBox plugin :  </p>

<h4 id="bpfmanager">BPF Manager</h4>

<p><img src="https://stuffandtacos.azurewebsites.net/content/images/2019/04/2019-04-03_14-39-11_POWERPNT.png" alt=""></p>

<h5 id="whatcandothepluginfornow">What can do the plugin ? (for now!)</h5>

<p>For now there are 2 major possibilities :</p>

<ul>
<li>Migrate records to the same BPF but different stage</li>
<li>Migrate records to a different BPF and selected stage</li>
</ul>

<p>Sounds easy, but since the version 8.2 (it's been a while now but it can't hurt to remind the current process), the way BPF are handled with records and users was modified heavily. <br>
The interesting functional part here is that a BPF instance is created for each record and user. <br>
Let's do some maths : <em>100 users for 400 records = 40 000 BPF instances to manage.</em></p>

<h4 id="technicalside">Technical side</h4>

<p>As said above, each user have an instance specific of the BPF for each records. (as explained here : <a href="https://blogs.msdn.microsoft.com/crm/2017/07/30/how-to-determine-which-business-process-flow-bpf-instance-is-shown-when-a-record-is-opened-2/">Link</a>)</p>

<p>Example : <br>
I just created my latest opportunity and out of my 150 users, only 10 accessed the record. At this point, in the BPF instances, we  will have only 10 rows out of the 150. Until user access the specific record, the BPF will not show up on the database.</p>

<p>As we want to "force" the operation to be done programmatically here, we will focus on the two main parts of the process:</p>

<ol>
<li>SetProcessRequest which will allow you to instanciate the BPF for any users.  </li>
<li>Update the BPF row linked to the wanted record to specify the <em>active stage</em> and the <em>traversedpath</em></li>
</ol>

<h4 id="instanciatethenewbpf">Instanciate the new BPF</h4>

<p>In order to instanciate a new business process flow, we will need to use the SetProcessRequest message from the SDK. <br>
Here is a sample of the code :</p>

<pre><code class="language-csharp">// Create the instance of the BPF on the record
SetProcessRequest setProcReq = new SetProcessRequest  
{
    Target = record.ToEntityReference(),
    NewProcess = new EntityReference(BPF.LogicalName, BPF.Id)
};
</code></pre>

<p>This message will create a new instance of the BPF for the user who is used during the Execute of that request.</p>

<ul>
<li><strong>Target</strong> is the EntityReference of the record you want to affect (opportunity, lead or any other record entity with BPF's)</li>
<li><strong>NewProcess</strong> will allow the CRM to create a new instance of the BPF (if not existing) for the specified record.</li>
</ul>

<p>Once our BPF is created properly on our records, we now want to choose which is the targeted stage, by default when you instanciate a new BPF, it will be set to the first stage (which make sense !).</p>

<h4 id="chooseyourtargetedstage">Choose your targeted stage</h4>

<p>In order to have the choice about the stage you want to enable during the BPF instanciation, you have the possibility to configure 2 attributes which will make the trick.</p>

<p><strong>traversedpath</strong> and <strong>activestageid</strong> are the ones.</p>

<ul>
<li><strong>ActiveStageId</strong> is a the EntityReference to the stage of the previously instance BPF you want the record to be set to.</li>
<li><strong>TraversedPath</strong> is a string variable which contains all stages guid's needed to access the wanted one (ex : GuidStage1,GuidStage2 for a target of stage 2), you will see how to get it below.</li>
</ul>

<p>Once you have those 2 parameters, a simple Update message will do the job :  </p>

<pre><code class="language-csharp">// Update stage of a record
var bpfInstance = new Entity()  
{
    LogicalName = targetedBPF.LogicalName,
    Id = targetedBPF.Id
};
bpfInstance["activestageid"] = new EntityReference(stageId.LogicalName, stageId.Id);  
bpfInstance["traversedpath"] = traversedpath;

_service.Update(bpfInstance);  
</code></pre>

<p>Let's have a closer look to the traversedpath variable. <br>
As said, we want here to retrieve all stage guids which are before the targeted one on the BPF definition.</p>

<pre><code class="language-csharp">List&lt;string&gt; traversedpath = new List&lt;string&gt;();  
var activePathRequest = new RetrieveActivePathRequest  
{
    ProcessInstanceId = targetedBPF.Id
};

var activePathResponse = (RetrieveActivePathResponse)this.Service.Execute(activePathRequest);

var stageDefinitions =  
    ((EntityCollection)activePathResponse.Results.Values.FirstOrDefault())?.Entities;

foreach (var path in stageDefinitions)  
{
    traversedpath.Add(path.Id.ToString());

    if (path.Attributes["stagename"].ToString() == targetStage)
        break;
}

// Desired result : 
var resultTraversedPath = String.Join(",",traversedpath);  
</code></pre>

<p>Here is what it is done here :</p>

<ol>
<li>Query a record which have the wanted BPF instanced (mandatory to have at least one, since from querying the BPF directly, you can't know what is the stage order)  </li>
<li>Loop through all stage of the BPF and store them in a list  </li>
<li>As soon as I reached my targeted stage, I can't break the loop (no need to use extra resources for nothing).</li>
</ol>

<h5 id="letsroll">Let's roll</h5>

<p>Now that you have the method to set a BPF instance and a way to set the wanted stage, you can now run your script. <br>
One more thing, we mentioned that it was based on user scope. <br>
The last needed trick here is to execute the 2  steps for each users of your instance so they are all aligned. <br>
If you just run the script with your credentials, you will be the only one to see the new BPF instance on your record.</p>

<h6 id="knownlimit">Known limit</h6>

<p>Unfortunately, I'm facing one <em>major</em> limit with that method. <br>
If you have a BPF A already instanced but not active, and a BPF B active, the current process won't allow the BPF A to be shown on the form.</p>

<p>Hope this help, <br>
Happy CRM'in !</p>]]></content:encoded></item></channel></rss>