Tuesday, November 19, 2019

Paging in Dynamic 365 CRM using JavaScript


The paging works differently depending on whether you’re performing a straight Rest API query or using FetchXML in the request.

Paging Rest API Queries example.
Item count per page is specified using odata.maxpagesize=x when setting Request Header.
It is ideally used when showing result in a GRID and using pagination to display next set of records.
If odata.maxpagesize is not mentioned Dynamic CRM default maxpagesize is 5000 records.
odata.maxpagesize Does NOT work for Fetch XML request

httpRequest.setRequestHeader("Prefer", "odata.maxpagesize=10");

To fetch next set of record we need to open a new request specified in @odata.nextLink attribute
@odata.nextLink does not applies when request is of Fetch Xml

JSON.parse(httpRequest.responseText)["@odata.nextLink"]

CODE EXAMPLE for Select Clause

var serverUrl = Xrm.Page.context.getClientUrl(); 

// sample function to return all the leads
function GetAllLeadsViaSelectQuery()
{
  var selectLeadQuery = "$select=fullname,leadid";
  var leadsQueryUrl = serverUrl + "/api/data/v9.1/leads?" + selectLeadQuery;

  // call our new method
  var retrievedLeads = getallRecords(leadsQueryUrl);

  alert(retrievedLeads.results.length);

  alert(retrievedLeads.results[0].fullname);   
}


function getallRecords(OriginalQueryUrl)
{
// we return an object with a similar structure
var allRecords = new Object();
allRecords.results = new Array();

// we loop until we have an url to query
var queryUrl = OriginalQueryUrl;
while (queryUrl != null)
{
    // we build the request
    var httpRequest = new XMLHttpRequest();
    httpRequest.open("GET", queryUrl, false); // false = synchronous request
    httpRequest.setRequestHeader("Accept", "application/json");
    httpRequest.setRequestHeader("OData-MaxVersion", "4.0");
    httpRequest.setRequestHeader("OData-Version", "4.0");
    httpRequest.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    httpRequest.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");

   httpRequest.setRequestHeader("Prefer", "odata.maxpagesize=500");

    httpRequest.send();

    if (httpRequest.status === 200) {
        var parsedResults = JSON.parse(httpRequest.responseText);

        if (parsedResults != null && parsedResults.value != null)
        {
            // we add the results to our object
            for (var i = 0; i < parsedResults.value.length; i++)
            {
                allRecords.results.push(parsedResults.value[i]);
            }

            //JSON.parse(httpRequest.responseText)["@odata.nextLink"]

            // check if there are more records and set the new url, otherwise we set to null the url
            if (parsedResults["@odata.nextLink"] != null && parsedResults["@odata.nextLink"] != 'undefined') {
                queryUrl = parsedResults["@odata.nextLink"];
            }
            else {
                queryUrl = null;
            }
        }
    }
    else
    {
        // if the request has errors we stop and return a null result
        queryUrl = null;
        allRecords = null;
    }
}
return allRecords;
}

Friday, November 15, 2019

Microsoft Flow for Twitter Sentiment Analytics


Here, I am going to share my recent learning about Microsoft Flow which showcase how to do sentiment analysis using Twitter and Microsoft Cognitive service.





Pre-Requisite
Microsoft Cognitive – Text Analytics Endpoints and Subscription Keys.
This is also available for 7 days trail from Microsoft




Some formula's used in Flows are

1) Compose action – to get last row of the table

last(body('List_rows_present_in_a_table')?['value'])

2) Fetch TweetId or SinceId as Columns value from Compose output

Outputs(‘Compose’)?[‘Original Tweet Id’]

3) Excel Header Columns
  • Original Tweet ID
  • UserName
  • Original Tweet
  • Transalated Tweet
  • Followers Count
  • Sentiment Score
  • Location
  • ReTweet Count
  • Favourite Count 

Wednesday, September 11, 2019

Cautiously changing logic of existing workflow in Dynamic CRM


How to deal with Old workflow instances that are in waiting state with old Logic?

We can accept that we are blessed with the Wait Condition in Dynamic CRM. It could be used in many simple to complex tasks such as to send a friendly reminders/email after certain duration.

There could be many workflow sessions running in a waiting state considering a typical Live (Production) environment.

Re-Defining Workflow

Now imagine for some reason your business logic got changed and you need to redefine the logic in a workflow.

Newly added logic for a respective workflow will not be applicable for workflows instances which are already in a waiting or running state and your business may complaint that notifications to customer are still going on even though you have already roll-out new changes to the workflow.

Solution

To overcome such a problem, I did follow below steps.
Step 1) Get workflow sessions which are still going ON (WAITING STATE) with OLD LOGIC
Step 2) Cancel Old workflow session with OLD LOGIC
Step 3) Trigger New Workflow Session for those records whose process got cancelled.

.Net Code for above outline steps 

public class SwitchToNewWorkflowProcess
{
IOrganizationService _orgService;

const string regardingEntityType = "invoice";
Guid workflowId = new Guid("1E99FA9F-3708-4107-A110-38191CC2BE59");     //  (Email) License has Expired


public SwitchToNewWorkflowProcess(IOrganizationService _orgService)
{
    this._orgService = _orgService;
}

public void executionPlan()
{
    // Step 1) Get workflow sessions which are still going ON (WAITING STATE) with OLD LOGIC
    EntityCollection oldWorkflowsCollection = getOldWorkflows();

    foreach (Entity sessions in oldWorkflowsCollection.Entities)
    {
        if (sessions.Contains("regardingobjectid"))
        {
            Guid invoiceId = ((EntityReference)sessions["regardingobjectid"]).Id;
                           
            //Step 2) Cancel workflow with OLD LOGIC
            cancelOldWorkflow(sessions.Id);

            // Step 3) Trigger New Workflow Session for those records whose process got cancelled.
            instantiateNewWorkflow(invoiceId);                 
        }
        else
            Console.WriteLine("Process Session where Regarding is not Set : " + sessions.Id.ToString());
    }
    Console.WriteLine("End of Execution Plan");
}


// You need to change condition clauses in below fetch XML to get specific workflow sessions
private EntityCollection getOldWorkflows()
{
    string fetchXmlOldSystemJob =            

    EntityCollection oldWorkflowsCollection = _orgService.RetrieveMultiple(new FetchExpression(fetchXmlOldSystemJob));
    return oldWorkflowsCollection;
}

private void cancelOldWorkflow(Guid workflowInstanceId)
{
    Entity operation = new Entity("asyncoperation")
    {
        Id = workflowInstanceId    //
    };

    operation["statecode"] = new OptionSetValue(3);
    operation["statuscode"] = new OptionSetValue(32);

    _orgService.Update(operation);
}     

private void instantiateNewWorkflow(Guid entityId)
{
    var executeWorkflowRequest = new ExecuteWorkflowRequest()
    {
        WorkflowId = workflowId,      // Guid of workflow 
        EntityId = entityId           // Guid of record 
    };
    var executeWorkflowResponse = (ExecuteWorkflowResponse)_orgService.Execute(executeWorkflowRequest);
}
}

From you main method just invoke the executionPlan() method.

IOrganizationService _orgService;
_orgService = getOrgService();

SwitchToNewWorkflowProcess obj = new SwitchToNewWorkflowProcess(_orgService);
obj.executionPlan();






Unable to initialize the native configuration support external to the web worker process


Unable to initialize the native configuration support external to the web worker process (HRESULT=0x80040154). nativerd.dll must be in %windir%\system32\inetsrv.



I received such an error (during run-time) when I was trying to connect to Dynamic CRM using CrmServiceClient.

This error is not related to Dynamic CRM, instead it is something to do with our machine configuration, I look over the internet and find the below solution.

Open Program and Features from Control Panel and navigate to windows feature turn on/off.

Here you need to enable (Tick) HTTP Activation for your respective .Net Framework either 6/7/8.



Once enabled, try to re-run your .Net Code and it should be able to connect to dynamic CRM without any problem.


Tuesday, September 3, 2019

Dynamic CRM data migration tool


Recently, one of my clients wanted to move from one tenant to another tenant. There was a version dependency of dynamic CRM. Microsoft denied copying CRM DB from one to another and quickly start using the new dynamic CRM on a new domain as it is not possible due o version dependency.

So, as an implementation partner we used Microsoft Dynamics CRM Configuration Migration Utility to do manual migration.

Here are some steps to showcase how to use and migrate records using CRM Configuration Migration Utility.




You can either choose a solution where you have all the entities you wish to migrate.


Or you can select specific entities and selected attributes as well.




Schema denote the various selected entities and respective field if any and further we are suppose to save the data file which contains the actual data records in the CRM system.




Schema denote the various selected entities and respective field if any and further we are suppose to save the data file which contains the actual data records in the CRM system.