2022 release wave 1 plan

Some of the features released as part of 2022 release wave plan 1.

1. Explore data through modern advanced find

New entry point

Advance table picker

Enhanced view selector.

2. Build forms entirely using features available in the modern form designer

Web client form designer will be depreciated.

3. Power Apps grid control support for editable scenarios in model-driven apps

Infinite Scrolling and inline editing within views and subgrid

Power apps Grid Control

4. Enable model-driven app redirect from Internet Explorer to Microsoft Edge

5. Model-driven app in-app notifications reach general availability

6. Easy Record sharing

Copy Link button introduced.

This feature is currently available for the Account, Case, Opportunity, and Contact tables.

7. Appointment description supports rich text

The new rich text editor is supported for all model-driven apps and is the default standard editor for appointments and email activities

8. Create and join Teams meetings from in-app appointments

Option to join meeting will be highlighted in the appointment form.

9. New activity dropdown to show only relevant activities

Activities that are not included in the app metadata now are hidden from the New Activity
command.

10. The New Power Apps read-only grid control released in 2021 release wave 2 will be the
default read-only grid experience for model-driven apps in 2022 release wave 1.

11. UI improvement for business process flows

The color contrast in the path-line between each stage in the business
process flow to a slightly darker shade. This will help users easily identify and follow each
stage in a business process flow when working with data on a form in a model-drive app.

12. Co-presence in records

Now you can see who’s currently working on a record including their online status. You can
also start a chat or send them an email and take collaboration to the next level.
This feature is currently available on the Account, Case, Opportunity, and Contact tables.

13. Owner field has improved on-line presence indicator and contact card

This feature is currently available for the Account, Case, Opportunity, and Contact tables.

14. Lobe E2E to Power Apps

Power Platform VS Code Extension

Public preview of the Power Platform Extension to VS Code was launched recently. In this blog will see some basic commands like

  1. Creating an authentication profile
  2. To see list of solutions
  3. Export Solution
  4. Import Solution

Lets get started

Install the extension from Visual studio Code

Once install type pac you will see the list of command

Create Authentication Profile

Sign in from the sign in popup window

To get Information about the organization use Command : pac org who it will display information

about the current Dataverse organizations.

To get the list of all the solution of your current environment

Command: pac solution list

Export a solution

Command : pac solution export –path c:\Users\sanke\DebugVsRelease.zip –name DebugVsRelease –async –managed false –targetversion 1.0.0.03 –include general

Import Solution

Command : pac solution import –path c:\Users\sanke\DebugVsRelease.zip –async –publish-changes –activate-plugins

Thank you for reading 🙂 . I am still exploring all the options will try to write more on it.

Debug vs Release Mode

So when I started plugin development I referred some blogs and videos then quickly started building plugins. Easy Peasy !! 🙂

In most of the blogs and videos on plugin development I haven’t found any one focusing on debug vs release part.

Every time I would write a plugin I would see two folder while trying to Register the plugin Debug and Release . But I didn’t care less. One day it just hit me what is this release folder and why is this even present as it always used to be empty after building the project.

Microsoft be Like – Seriously?? why it’s present ??? We have named it Release it cannot be more obvious than this. It for Release (Deployment) you dumb**s 🤦‍♂️🤦‍♂️🤬

I know people from .NET background or the people who have learnt this in early stage of their plugin development would be like Hey this like 101 of Development.

But for the folks on the other side who are like me. Lets get Started will explore what is difference between the two with some live example.

In short bin\debug is for development and bin\release is for deployment

Navigate to Visual studio -> Properties . You will see the below window. If You click on Configuration Drop Down there will be two option debug and release

If you select Release -> Ok and Build the plugin. You will be able to see the dll in the release folder.

This image has an empty alt attribute; its file name is image-28.png

Release builds are optimized for speed and debug builds are optimized for well debug-ability.

Let’s prove this.

Consider the below code. In this program Execute Invoke A the A calls B, which calls C, which calls badMethod which throws an exception. So far, makes sense right?

If you will check the trace of the plugin in Debug mode and Release mode you will notice the difference.

using Microsoft.Xrm.Sdk;
using System;

namespace MicrosoftLearn
{
    public class DebugVsRelease : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                try
                {
                    methodA();
                }
                catch (System.Exception e)
                {
                    tracingService.Trace(e.ToString());
                }
            }
        }
        static void methodA() { methodB(); }
        static void methodB() { methodC(); }
        static void methodC() { badMethod();}
        static void badMethod() { 
                 throw new ApplicationException("Error Occured in plugin in badMethod"); 
       }
    }
}

Debug Mode : Complete Stack Trace

Now build the same plugin in release mode and deploy it to CRM from the release folder.

Our call stack has been “collapsed”?

What you write isn’t exactly what runs, especially when things are optimized. In Release version our code gets optimized. Not every method got their own local stack frame as they were optimized into fewer methods. This technique used by Just-In-Time compiler(JIT) to optimize the code is called Method Inling.

If you want to check if JITER (Just in time compiler) is really doing inling or not. Use [MethodImpl(MethodImplOptions.NoInlining)] for every method it will tell the Just in time compiler not to inline the method. But it’s beating the whole purpose of JITTER optimization.

As you can see after using [MethodImpl(MethodImplOptions.NoInlining)] inling by JITER (Just in time compiler) is suppressed and we call see the entire call stack similar to debug mode.

So far so so good

Now let’s decompile both the debug dll and release dll to see the difference if any?

How to decompile dll: Download dotPeek and use it to open the dll.

First Release dll

Now Debug dll :

You can see debugging mode is default and most important is DisableOptimization. So in debug mode optimization of the code is disable where as in release mode code is optimized.

Some optimizations performed by JIT compiler are as below. Details can be found here https://flylib.com/books/en/4.453.1.45/1/ https://www.codeproject.com/Articles/25801/JIT-Optimizations

•  CPU register allocation

• Array index checking elimination

• Loop unrolling – Short loops (up to 4) with small bodies are eliminated by repeating the code in the loop body.

• Dead code elimination – A statement like if (false) { /…/ } gets completely eliminated.

• Code hoisting- Code inside a loop that is not affected by the loop can be moved out of the loop.

• Common sub-expression elimination. x = y + 4; z = y + 4; becomes z = x

So now we know some bit of info about release and debug mode.

Its very clearly written in Microsoft docs to use release configuration for deployment

I have personally seen many enterprise level projects deployed in debug mode.

Credits : Internet

Thank you for reading through 🙂

How to Register your App in Azure Active Directory and create Application user

Need to register the app and application user is required for server-to-server authentication

An enterprise can create a web application or service to connect to any Dataverse environments associated with a single Azure Active Directory (Azure AD) tenant.

Navigate to https://portal.azure.com . Open Manage Azure Active Directory

Under the manage tab locate App Registration

Click on App Registration

Click on New Registration

Provide the details such as APP name , who can use this application and redirect uri is optional you can leave it as blank

After you have Clicked Register. Your App would be created. Copy the application (client id) mention as below and save it somewhere will need it to create application user

Go API Permission

Click on Add Permission

Select Dynamics CRM

Click on Grant Admin Consent

Click Yes

Now got Certificate & Secrets

Click New client secret. Provide Description and Expires in

Client secrets will be generated. Copy those values and save it. Will need it in future.

Now you need to Register the Application user in Dynamics CRM

Navigate to Setting -> Security -> Users. Change the view to application user.

Create New Application user

Switch Form to Application user

Enter the application ID of your app created in Azure and click save.

If there goes well all others fields will be populated

Before exiting the user form, choose MANAGE ROLES and assign a security role to this application user so that the application user can access the desired organization data.

At this stage we are done with registering the app in azure AD and creating the application user for same.

Note : In an environment, only one application user for each Azure AD registered application is supported. You will not be able to change the primary email address or username once the application user is created.

Why do we need to encode fetchXml

FetchXml are most commonly used to retrieve records and their attributes. But if we have just used plain fetchXml there are some test cases that we are over looking .

There are some special characters for which your xml will become invalid xml.

Special characters  & “ ‘  < > + ; 

& will be a very common character in the production data particularly for name of account or products records

Let see the example below

// Retrieve all products with name Wheel & Tube.

var productName = “Wheel & Tube”

string xml = @”<fetch version=’1.0′ output-format=’xml-platform’ mapping=’logical’ distinct=’false’>” +

              “<entity name=’product’>” +

              “<attribute name=’name’ />” +

              “<order attribute=’name’ descending=’false’ />” +

              “<filter type=’and’>” +

“<condition attribute=’name’ operator=’eq’ value='” + productName + “‘ />”+

              “</filter>” +

              “</entity>” +

              “</fetch>”;

This will result in InvalidXML.

But why this results in InvalidXML?

To the XML parser, the ampersand indicates that what follows is an entity that needs to be parsed into some other piece of data.

When the XML parser finds an ampersand in the XML data, it expects to find a symbol name and a semicolon following it. The symbol name provides a symbolic reference to another entity or character such as the ampersand

How to solve the above problem of & or special chararcters?

Use WebUtility.HtmlEncode(value), you need to add reference for WebUtility System.Net.

Now see the above example with WebUtility.HtmlEncode(value) this will encode the special characters in your fetchXML.

Example & will be converted to &amp;

var productName = “Wheel & Tube”

string xml = @”<fetch version=’1.0′ output-format=’xml-platform’ mapping=’logical’ distinct=’false’>” +

              “<entity name=’product’>” +

              “<attribute name=’name’ />” +

              “<order attribute=’name’ descending=’false’ />” +

              “<filter type=’and’>” +

“<condition attribute=’name’ operator=’eq’ value='” + WebUtility.HtmlEncode(productName) + “‘ />”+

              “</filter>” +

              “</entity>” +

              “</fetch>”;

So always use WebUtility.HtmlEncode(value) to encode your XML for Text fields

Thanks 🙂

Breaking Down CRM Rest builder Query.

Basic but neededIn this blog post i will break down the CRM rest builder query code line by line to help you understand what exactly happening in the piece of code.

This post is basically for the the people who are getting started with Dynamics 365 and also for those who did not care too much about what happening inside the code as long as it serve their purpose of retrieve/update/create etc.

Let’s get started. So I have generated a simple piece of code for retrieve request

var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v9.1/accounts(475b158c-541c-e511-80d3-3863bb347ba8)", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
req.onreadystatechange = function() {
    if (this.readyState === 4) {
        req.onreadystatechange = null;
        if (this.status === 200) {
            var result = JSON.parse(this.response);
            var accountid = result["accountid"];
        } else {
            Xrm.Utility.alertDialog(this.statusText);
        }
    }
};
req.send();

XMLHttpRequest (XHR) objects are used to interact with servers. Here we are interacting Dynamics 365 servers.

1. XMLHttpRequest

 // Here we first create object of XMLHttpRequest
var req = new XMLHttpRequest();
 
2. Syntax : XMLHttpRequest.open(method, url,async)
XMLHttpRequest method open() initializes a 
newly-created request

GET - is a http reqeust method used to get data
url - the URL to send the request to the server
So here we are sending request to service root url
 [org name + /api/data/v9.1/]
Example
https://azuredevfordev.crm8.dynamics.com/api/data/v9.1/

You can find the service root URL in developer 
resources
This image has an empty alt attribute; its file name is capture.jpg

aync- optional Boolean parameter, defaulting to true,
indicating whether or not to perform the operation asynchronously. 

If not provide or set to true ->
 Code executes synchronously 

otherwise code will execute asynchronously
/* So here method is GET,
 url is 
https://azuredevfordev.crm8.dynamics.com/api/data/v9.1/
 async - is true i.e synchronous
*/ 

req.open("GET", Xrm.Page.context.getClientUrl() + 

"/api/data/v9.1/accounts(475b158c-541c-e511-80d3-3863bb347ba8)", true);
 

req.setRequestHeader

Okay got it so far but what’s happening here in req.setRequestHeader , I see a bunch of them

Here we are setting the HTTP request headers. But what are HTTP headers actually?

HTTP headers let the client and the server pass additional information with an HTTP request or response. An HTTP header consists of its case-insensitive name followed by a colon (:), then by its value.

Syntax 
XMLHttpRequest.setRequestHeader(header, value)

header - name of HTTP header
value - value of HTTP header

 setRequestHeader() sets the value of an HTTP request header. When using setRequestHeader(), you must call it after calling open(), but before calling send()

req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");

OData-MaxVersion – Clients SHOULD specify an OData-MaxVersion request header. If specified the service MUST generate a response with an OData-Version less than or equal to the specified OData-MaxVersion.
Header value states the maximum version of the protocol the client can accept in a response.

OData-Version -to specify the exact data service version. If both headers are present, precedence is given to OData-MaxVersion.

3. Content Negotiation Now we will talk about Content Negotiation

req.setRequestHeader("Accept", "application/json");

Generally, resources can have multiple presentations, mostly because there may be multiple different clients expecting different representations. Asking for a suitable presentation by a client, is referred as content negotiation.

Accept”, “application/json”

SyntaxAccept: <MIME_type>/<MIME_subtype>

application – Any kind of binary data that doesn’t fall explicitly into one of the other types

json – mime_subtype which specifies that client is excepting response in json format.

You can specify the other format like html,xml, etc

To determine what type of representation is desired at client side, HTTP header ACCEPT is used. For example here ,it simply means client is requesting data in Json format.

req.setRequestHeader("Accept", "application/json");

4. “Content-Type”, “application/json; charset=utf-8”

So Content-Type and Accept seems to be doing the
same thing. Is it so? 
No, let see how they are different
Accept: is what client is expecting.
Content-Type: is what format the actual data is in 
it's primarily
meant for put or post request However, strictly
speaking the specs 
itself does not rule out the possibility of HTTP GET
contains a payload 
https://tools.ietf.org/html/rfc7231#section-4.3.1

Content - type is Representation header field which
provide metadata about the representation.
When a message includes a payload body, 
the representation header fields describe
how to interpret the representation data enclosed
in the payload body

Also what does charset=utf-8  doing here?

Content-type: application/json; charset=utf-8 designates the content to be in JSON format, encoded in the UTF-8 character encoding.

5. “Prefer”, “odata.include-annotations=\”*\””

The Prefer request header field is used to 
indicate that particular server behaviors 
are preferred by the client but are not
required for successful completion of the request

What does odata.include-annotations=\”*\”” is doing here?

*” – represent all annotations

What happens when you retrieve a lookup field? You get a bunch of other values along with Guid

This is because we have include all annotations in the code. Now try with “-*”. You will get only Guid. This is because “-*” indicates no annotation.

Example of annotations

6. this.readyState

While we debug we get multiple values for this.readyState like 0,1,2,3,4 but have we tried to figure out what they actually represent?

this.readyState – property returns the state an XMLHttpRequest client is in

When it’s 4 state is DONE.

7. req.onreadystatechange

property defines a function to be executed when the readyState changes.

XMLHttpRequest.onreadystatechange = callback; callback is the function to be executed when the readyState changes.

8. this.state

HTTP response status codes indicate whether a specific HTTP request has been successfully completed.

9. this.response

response property returns the response’s body content as an ArrayBufferBlobDocument, JSON, or DOMString

10. req.send()

send() sends the request to the server. If the request is asynchronous (which is the default), this method returns as soon as the request is sent.

If the request is synchronous, this method doesn’t return until the response has arrived.

send() accepts an optional parameter which lets you specify the request’s body; this is primarily used for requests such as PUT.

References

  1. https://developer.mozilla.org/en-US/
  2. https://docs.microsoft.com/en-us/odata/webapi/include-annotations
  3. https://tools.ietf.org/html/rfc7231#section-4.3.1
  4. https://www.odata.org/documentation/

Impersonation while calling Action using JavaScript

Unlike workflows Actions always executes in user context by default.

If you want to impersonate and execute action from service account . Use below line in you code to call the action

  1. request.setRequestHeader(“MSCRMCallerID”, “214b236e-2970-ea11-a811-000d3a2c57ba”); // here pass the Guid of the service account or any user.
  2. Note : User should have act on behalf privilege.

// Call action sample code
function callAction(primaryControl,teamId,queueID,ActionName){
var parameters = {};
var queue = {};
queue.queueid = queueID; //Delete if creating new record
queue[“@odata.type”] = “Microsoft.Dynamics.CRM.queue”;
parameters.Queue = queue;
var team = {};
team.teamid = teamId; //Delete if creating new record
team[“@odata.type”] = “Microsoft.Dynamics.CRM.team”;
parameters.Team = team;
var globalContext = Xrm.Utility.getGlobalContext(); // get global context
var request = new XMLHttpRequest();
request.open(“POST”, globalContext.getClientUrl() + “/api/data/v9.1/opportunities(“+ OpportunityId +”)/Microsoft.Dynamics.CRM.dss_” + ActionName, true);
request.setRequestHeader(“OData-MaxVersion”, “4.0”);
request.setRequestHeader(“OData-Version”, “4.0”);
request.setRequestHeader(“Accept”, “application/json”);
request.setRequestHeader(“Content-Type”, “application/json; charset=utf-8”);
request.setRequestHeader(“MSCRMCallerID”, “214b236e-2970-ea11-a811-000d3a2c57ba”);
request.onreadystatechange = function() {
if (this.readyState === 4) {
request.onreadystatechange = null;
// alert(this.status);
if (this.status === 204) {
Xrm.Utility.openEntityForm(“opportunity”,OpportunityId);
//Success – No Return Data – Do Something
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
request.send(JSON.stringify(parameters));
}

Hope this helps 🙂

Auto Calculate Roll up field In Dynamics 365

Recently we came across a scenario in which we need to force roll up field calculation. We did not wanted to wait for roll up calculation by CRM system.

More info on roll up fields : https://docs.microsoft.com/en-us/dynamics365/customer-engagement/customize/define-rollup-fields

This can be achieved by using CalculateRollupFieldRequest class.

https://docs.microsoft.com/en-us/dotnet/api
/microsoft.crm.sdk.messages
.calculaterollupfieldrequest?view=dynamics
-general-ce-9

using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample Plugin
{
public class Update RollUp Field : Plugin
{
public void Execute(IServiceProvider
service Provider)
{
//Extract the tracing service for use in
debugging sandboxed plug-ins.
ITracingService tracingService =
(ITracingService)service Provider.GetService
(typeof(ITracingService));
// Obtain the execution context from the service provider.

IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// To create organization service
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
// The InputParameters collection contains all the data passed in the message request.
#region On Create
if (context.MessageName == “Create” && context.InputParameters.Contains(“Target”) && context.InputParameters[“Target”] is Entity)
{
Entity Insured = (Entity)context.InputParameters[“Target”];
EntityReference Quote = (EntityReference)Insured[“zh_quote”]; //retrieving quote from custom entity
CalculateRollupFieldRequest crfr = new CalculateRollupFieldRequest
{
Target = new EntityReference(“quote”, Quote.Id), //Entity on which rollup is present
FieldName = “zh_totalpremium” // rollup field name
};
CalculateRollupFieldResponse response = (CalculateRollupFieldResponse)service.Execute(crfr);
Entity QuoteEntity = response.Entity; // this will contain the entity with updated rollup value
var totalPremium = ((Money)QuoteEntity.Attributes[“zh_totalpremium”]).Value;
Entity QuoteEntity = new Entity(“quote”);
QuoteEntity.Id = Quote.Id;
QuoteEntity[“zh_totalpremium”] = new Money((decimal)totalPremium);
service.Update(QuoteEntity); //Update the rollup field
}
#endregion

}

}

}