Unexpected error (SQL Timeout error) while trying to delete Audit Log


Unexpected error (SQL Timeout error) while trying to delete Audit Log

We had around 200 GB of Audit Log data in our Production Environment (Online), but while trying to delete it through Audit Log Management resulted into unexpected error.

The only option is to raise the support ticket with Microsoft. We also raised the same but it unfortunately resulted in our Production Server being down for brief period of time because of time out issue while performing the operation in Audit Base.

So, in short if we are facing issue while deleting log ourselves, we need to raise the support ticket and also the plan the same during downtime or weekends when users are not using the system.

Hope it helps..

Microsoft.Crm.CrmException: GetAssemblyMetadata: expected mdtAssemblyRef or mdtAssembly while registering plugin assembly in Dynamics 365


While registering a plugin assembly through plugin registration tool we got the below error

The reason being we were using MSBuild.ILMerge.Task Nuget package and there were few assemblies being referenced in the plugin project that had copy local set as true.

https://nishantrana.me/2017/05/17/using-ilmerge-for-plugin-in-crm/

So eventually the single plugin assembly that was getting build had these assemblies also being merged in it, which led to the above error.

Setting Copy Local as False for those assemblies fixed the issue.

Hope it helps.

Configure Session Timeout and Inactivity Timeout – Dynamics 365


In Dynamics 365, we can now define Session timeout and Inactivity timeout.

We need to go Settings à Administration à System Settings à General Tab

By default, the session timeout is set to 24 hours along with 20 minutes for warning the user.

We can set our custom values there.

Enter maximum session length 60 – 1440 minutes. ( 1 to 24 hour)
How long before the session expires do you want to show a timeout warning? 20 – 1440 minutes. Must be less than maximum session length.

We can also set the timeout based on inactivity. By default, this setting is not enabled. Below are the values that we can set for inactivity timeout.

Enable session timeout due to inactivity 5 – 1440 minutes. (5 minutes to 24 hours) – Must be less than the maximum session length.
How long before the session expires do you want to show an inactivity warning? Less than Session timeout due to inactivity

Session Timeout warning à

Session expired à

Inactivity warning à

Inactivity Session expiration à

More details.

https://docs.microsoft.com/en-in/dynamics365/customer-engagement/admin/user-session-management

Hope it helps..

Sample code to retrieve more than 5000 records using FetchXML in CRM


Hi,

Sharing a sample code to retrieve more than 5000 records using the Fetch XML.

Version 1 :


private List<Entity> GetTotalRecordsfromFetch(string fetchXML, IOrganizationService orgService)
{
List<Entity> lstEntity = new List<Entity>();

int fetchCount = 5000;
int pageNumber = 1;
string pagingCookie = null;

while (true)
{
// Build fetchXml string with the placeholders.
string xml = this.CreateXml(fetchXML, pagingCookie, pageNumber, fetchCount);
RetrieveMultipleRequest fetchRequest = new RetrieveMultipleRequest
{
Query = new FetchExpression(xml)
};

var returnCollections = ((RetrieveMultipleResponse)orgService.Execute(fetchRequest)).EntityCollection;

if (returnCollections.Entities.Count >= 1)
{
lstEntity.AddRange(returnCollections.Entities);
}

if (returnCollections.MoreRecords)
{
pageNumber++;

results.pagingCookie = returnCollections.PagingCookie;
}
else
{
// If no more records in the result nodes, exit the loop.
break;
}
}

return lstEntity;
}

public string CreateXml(string xml, string cookie, int page, int count)
{
StringReader stringReader = new StringReader(xml);
XmlTextReader reader = new XmlTextReader(stringReader);

XmlDocument doc = new XmlDocument();
doc.Load(reader);

XmlAttributeCollection attrs = doc.DocumentElement.Attributes;

if (cookie != null)
{
XmlAttribute pagingAttr = doc.CreateAttribute("paging-cookie");
pagingAttr.Value = cookie;
attrs.Append(pagingAttr);
}

XmlAttribute pageAttr = doc.CreateAttribute("page");
pageAttr.Value = System.Convert.ToString(page);
attrs.Append(pageAttr);

XmlAttribute countAttr = doc.CreateAttribute("count");
countAttr.Value = System.Convert.ToString(count);
attrs.Append(countAttr);

StringBuilder sb = new StringBuilder(1024);
StringWriter stringWriter = new StringWriter(sb);

XmlTextWriter writer = new XmlTextWriter(stringWriter);
doc.WriteTo(writer);
writer.Close();

return sb.ToString();
}

Version 2 :


private static List<Entity> GetTotalRecordsFetchXML(OrganizationServiceProxy orgProxy, string fetchXML)
{
XDocument xDocument = XDocument.Parse(fetchXML);
var fetchXmlEntity = xDocument.Root.Element("entity").ToString();

EntityCollection entityColl = new EntityCollection();
List<Entity> lstEntity = new List<Entity>();
int page = 1;
do
{

entityColl = orgProxy.RetrieveMultiple(new FetchExpression(
string.Format("<fetch version='1.0' page='{1}' paging-cookie='{0}'>" + fetchXmlEntity + "</fetch>",
SecurityElement.Escape(entityColl.PagingCookie), page++)));

lstEntity.AddRange(entityColl.Entities);
}
while (entityColl.MoreRecords);

return lstEntity;
}

Hope it helps..

Using Shared Mailbox and Queue in CRM for implementing generic email address in Dynamics 365 and Exchange Online.


Recently, we had a requirement to send email to customers using a generic email address like donotreply@domain.com from Dynamics CRM (& Exchange Online).

The way we can implement this is through Shared Mailbox and Queue in CRM Online.

Log in to the Administration Portal

https://portal.office.com/adminportal/home#/homepage

Select Shared mailboxes

Members can be added to the Shared Mailbox

Now back in CRM assign the email id to a particular queue.

Now sending an email activity with From as Queue and to as one of the user inside CRM.

Open the user’s mail box.

Make sure we have done Test and Enabled Mailbox for the Shared Email Box and have set Incoming and Outgoing Email as Server-Side Synchronization.

Hope it helps..

Status not getting updated using SetStateRequest in Dynamics 365.


Hi,

We were recently facing issue while trying to update status for Campaign Entity using SetStateRequest in Dynamics 365. The value for were not getting updated.

Eventually we realized that it could be because of SetStateRequest being deprecated now in Dynamics 365 (online).

Updating the code to use UpdateRequest fixed the issue.

Hope it helps..

LINQ: GroupBy, Sum and EntityCollection in CRM


Just sharing a sample code that could be used for group by and sum operation on EntityCollection.

Suppose below is the output that we want

We can use the below code for that.


// select categoryid, final forecast, final awards from SubCategory Entity
// category id is lookup in SubCategory Entity

EntityCollection result = orgProxy.RetrieveMultiple(new FetchExpression(fetch));

var details = from r in result.Entities.AsEnumerable()
group r by new
{
groupByCategoryID = ((EntityReference)r.Attributes["categoryId"]).Id.ToString()
}
into g
select new
{
sumFinalForecast = g.Sum(x => Convert.ToInt32(x.Attributes["finalforecast"])),
sumFinalAwards = g.Sum(x => Convert.ToInt32(x.Attributes["finalawards"])),
categoryId = g.Key.groupByCategoryID
};

// update the parent record
foreach(var detail in details)
{
Entity entityUpdate = new Entity("category");
entityUpdate.Id = new Guid(detail.categoryId);
entityUpdate.Attributes["totalfinalforecast"] = detail.sumFinalForecast;
entityUpdate.Attributes["totalfinalawards"] = detail.sumFinalAwards;
orgProxy.Update(entityUpdate);
}

Hope it helps..

Sample code to call Action using Web API in CRM


Just sharing a sample code to call an Action through Web API.

Suppose below is our Action with one input parameter.

JavaScript code :-


function CallAction() {

// get the id of the record and remove the curly bracket part
// id will be used in Web API url
var Id = Xrm.Page.data.entity.getId().replace('{', '').replace('}', '');

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

// pass the id as inpurt parameter
var data = {

"recordid": Id
};

var req = new XMLHttpRequest();

// specify name of the entity, record id and name of the action in the Wen API Url
req.open("POST", serverURL + "/api/data/v8.2/sab_costmanagements(" + Id + ")/Microsoft.Dynamics.CRM.sab_Recalculate", true);

req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.onreadystatechange = function () {
if (this.readyState == 4 /* complete */) {
req.onreadystatechange = null;
if (this.status == 200) {
var data = JSON.parse(this.response);
alert(data);
} else {
var error = JSON.parse(this.response).error;
alert(error.message);
}
}
};

// send the request with the data for the input parameter
req.send(window.JSON.stringify(data));
}

Basically we need to pass name of the Entity Set with id of the record followed by name of the action appended with Microsoft.Dynamics.CRM.

In case of global action, we just need the Microsoft.Dynamics.CRM.<<ActionName>>.

More details here

https://www.inogic.com/blog/2016/10/execute-the-global-action-using-web-api-in-dynamics-crm/

Hope it helps..

Missing Action (message) in Plugin Registration Tool


Recently we created a new created Action and it twas not showing up in Plugin Registration Tool.

Closing and restarting the Plugin Registration tool fixed it.

Hope it helps..

Filter SubGrid in Dynamics 365 (with New Form Rendering or Turbo Form)


Recently we had a requirement wherein we wanted to see all the child records of a record in a SubGrid .

We had self-referential (hierarchical relationship) enabled for that entity.

Configuring the Sub Grid on the form.

We have also enabled the Editable grid for the Sub Grid.

The JavaScript code


function filterSubGrid()
{
// get the current record's guid
var entityId = Xrm.Page.data.entity.getId();

// refer the subgrid
var testGrid = window.parent.document.getElementById("Test");

if (testGrid == null)
{
setTimeout(function () {filterSubGrid(); }, 2000);
return;
}

// fetch xml code using User operator
var fetchXml = "<fetch distinct='false' no-lock='false' mapping='logical'>" +
"<entity name='new_test' >" +
"<attribute name='new_name' />" +
" <attribute name='new_testname' />" +
"<order attribute='new_name' descending='true' />" +
"<filter type='and'>" +
"<condition attribute='new_testid' operator='under' value='"+entityId+"'"+"/>" +
"</filter>" +
"</entity>" +
"</fetch>";

if (testGrid.control != null)
{
testGrid.control.SetParameter("fetchXml", fetchXml);
testGrid.control.refresh();
}
else
{
setTimeout(filterSubGrid, 500);
}
}

The filtered Sub Grid (editable)

Note :- The JavaScript code is unsupported as we are making use of getElementById instead of Xrm library to access subgrid.

Hope it helps..

Using ILMerge for Plugin in CRM


If we make use of external assembly in our Plugin (sandboxed) we will get the exception of FileNotFound.

So here we can make use of ILMerge which basically merges the assembly referenced and the plugin into a single assembly.

Install the following NuGet Package.

This adds the following files in our Plugin project.

We need to set Copy Local as true for all our referenced assembly that we want to merge with our plugin.

We need to set Copy Local as false for all other assemblies that we do not want to be merged with plugin.

Just build the project and we are done.

The assembly inside Reflector: –

Hope it helps.

Using tpc.identity to get the logged in user details in JavaScript in The Portal Connector (TPC)


Recently while working in TPC, we had a requirement to get the details of the logged in user (which is basically a contact record in CRM).

To do so we can make use tpc.identity object in Client Side.

For e.g. contactId

Hope it helps..

Fixed – Workflow must be in Published State error while converting Case to Work Order in CRM


Recently, while trying to convert a case to work order we got the below error.

The immediate thought was to check all the workflow associated to work order and case and see if they all are published, which in fact they were.

Then as suggested here

http://ms-crm-2011-beta.blogspot.ae/2016/11/workflow-must-be-in-published-state.html

we deactivated and activated one of our SLA written against the Work Order entity and it fixed the issue.

Hope it helps..

Sample code to upload file to Azure Blob Storage from CRM Online Plugin


Sharing a sample code which we can use to upload files to Azure Blog Storage from within a CRM Online Plugin. Here we’d be making use of the REST API to simplify things (instead of using Windows Azure Storage library) in our Plugin.

First, we will be creating a storage account of type blob storage and a container inside it.

Log in to Azure Portal

https://portal.azure.com

Click on Add to add a new storage account.



Create a new container in it to store the blob files



In Azure Portal – Storage Account, go to Access Keys and copy the key


And also note down the storage account name and container name which will be used to construct the URL.


We can also go to container, select its properties and copy the url.


Here we have written the plugin on Create of Annotation, which then retrieves the attachment and uploads its content to the container.

Let us first see it in action.

We have created a new note and attached a text file to it.


Going back to our portal, we can see the file in our container.


The sample code for the plugin.

using Microsoft.Xrm.Sdk;
using System;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
namespace MyTestPlugin
{

public class UploadFile : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
try
{
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parameters.
Entity noteEntity = (Entity)context.InputParameters["Target"];
byte[] doumentBody = Convert.FromBase64String(noteEntity.Attributes["documentbody"].ToString());
string content = Encoding.UTF8.GetString(doumentBody);
string fileName = noteEntity.Attributes["filename"].ToString();

// Upload the attached text file to Azure Blog Container
UploadFileToAzureBlobStorage(content, fileName);

}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message);
}
}

void UploadFileToAzureBlobStorage(string content, string fileName)
{

string storageKey = "storagekey";
string storageAccount = "storageaccountname";
string containerName = "strogaecontaninername";
string blobName = fileName;

string method = "PUT";
string sampleContent = content;
int contentLength = Encoding.UTF8.GetByteCount(sampleContent);

string requestUri = $"https://{storageAccount}.blob.core.windows.net/{containerName}/{blobName}";

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);

string now = DateTime.UtcNow.ToString("R");

request.Method = method;
request.ContentType = "text/plain; charset=UTF-8";
request.ContentLength = contentLength;

request.Headers.Add("x-ms-version", "2015-12-11");
request.Headers.Add("x-ms-date", now);
request.Headers.Add("x-ms-blob-type", "BlockBlob");
request.Headers.Add("Authorization", AuthorizationHeader(method, now, request, storageAccount, storageKey, containerName, blobName));

using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(Encoding.UTF8.GetBytes(sampleContent), 0, contentLength);
}

using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
{
if(resp.StatusCode == HttpStatusCode.OK)
{
// successfully uploaded
}
}

}

public string AuthorizationHeader(string method, string now, HttpWebRequest request, string storageAccount, string storageKey, string containerName, string blobName)
{
string headerResource = $"x-ms-blob-type:BlockBlob\nx-ms-date:{now}\nx-ms-version:2015-12-11";
string urlResource = $"/{storageAccount}/{containerName}/{blobName}";
string stringToSign = $"{method}\n\n\n{request.ContentLength}\n\n{request.ContentType}\n\n\n\n\n\n\n{headerResource}\n{urlResource}";

HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(storageKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));

String AuthorizationHeader = String.Format("{0} {1}:{2}", "SharedKey", storageAccount, signature);
return AuthorizationHeader;
}
}

}

Hope it helps.

Call Dynamics CRM from Azure Functions


Update -26 – Sep- 2018

https://nishantrana.me/2018/09/26/changing-the-target-runtime-version-of-azure-functions/

https://nishantrana.me/2018/09/25/the-type-or-namespace-name-xrm-could-not-be-found-are-you-missing-a-using-directive-or-an-assembly-reference-error-while-using-azure-functions-2-x/

 

Let us take a look at a simple Azure Function that refers our CRM assemblies and creates contact record in CRM.

Log in to Azure Portal, search for Function App and create a Function App.

Here we have specified WebHook + API and CSharp Template. Click on Create this function.

Select the function app, go to Platform features tab and click on App Service Editor.

Right click the function and add a new file named project.json. It is within this file we will refer our Nuget Packages that we need in our function.

https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp

Here we will reference the following Nuget Package for CRM

https://www.nuget.org/packages/Microsoft.CrmSdk.CoreAssemblies/


{
"frameworks": {
"net46":{
"dependencies": {
"Microsoft.CrmSdk.CoreAssemblies": "8.2.0.2"
}
}
}
}

Back in our Function when we click on Save or Run, we can see the required assemblies being installed in our Log.

The sample code for the Azure Function (just for simplicity the values are all hardcoded)


using System.Net;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;

public static async Task Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");

// parse query parameter
string firstname = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "firstname", true) == 0)
.Value;

string lastname = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "lastname", true) == 0)
.Value;

IServiceManagement orgServiceManagement = ServiceConfigurationFactory.CreateManagement(new Uri("https://nishutrial.crm.dynamics.com/XRMServices/2011/Organization.svc"));

AuthenticationCredentials authCredentials = new AuthenticationCredentials();
authCredentials.ClientCredentials.UserName.UserName = "abc@abc.onmicrosoft.com";
authCredentials.ClientCredentials.UserName.Password = "*****";
AuthenticationCredentials tokenCredentials = orgServiceManagement.Authenticate(authCredentials);

OrganizationServiceProxy organizationProxy = new OrganizationServiceProxy(orgServiceManagement, tokenCredentials.SecurityTokenResponse);
Entity contact = new Entity("contact");
contact.Attributes["firstname"] = firstname;
contact.Attributes["lastname"] = lastname;
var contactId = organizationProxy.Create(contact);
// Get request body
dynamic data = await req.Content.ReadAsAsync();

string fullname = "";
return fullname == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
: req.CreateResponse(HttpStatusCode.OK, "Contact created in CRM " + contactId.ToString());
}

Let us now test our function.

The function expects 2 query string parameter firstname and lastname and creates the contact record in CRM.

In our CRM, we can see the contact record created.

Hope it helps..

 

A simple implementation using Azure Functions, Microsoft Flow, Microsoft PowerApps, Dynamics CRM and SendGrid


Let us  implement a simple scenario where we create a lead record in CRM which then talks with Flow (and Power App).

The Flow calls an Azure Function (Custom API) that sends mail to the lead’s email address using SendGrid

1) Let us create an Azure Function that uses SendGrid to send email to the lead’s email address.

Login to Azure Portal and create a new Function App.

https://portal.azure.com

Let us create a Function using Generic Web Hook CSharp template

To keep it simple let us only enable GET method. Go to Integrate tab and in Allowed HTTP Methods Select Selected Methods and check GET.

Also set mode as Standard and Authorization Level as anonymous, which means we do not need a API Key to be passed as query parameter to talk with the function.

Now let us add a new Output

Select SendGrid as the template

Click on Save.

Here we would need to define SendGridApiKey.

Go to SendGrid portal and create a free account over there

https://sendgrid.com

Create and API Key and copy it’s value.

Now go to Application Settings of the Function App and set this key value with SendGridApiKey as the key name.

Now let us go back to our code and update it to work with lead object and Mail class which would be used for sending email using SendGrid API.

Here first we are referring the SendGrid assembly, then getting fullname and email from query string and then creating Mail object.

Save and check the log if the compilation succeeded or not.

Testing our Function.

We can see the mail in the mail box.

This completes our first part.

2) Now let us create the Swagger definition for it which we will use in Power Apps and Microsoft Flows for using this Azure Function as Custom API.

Select our function and click on API definition.

Click on Function.

Update the generated API Definition Template with query parameter details and also test it.

As it is running successfully, click on Export to Power Apps + Flow

This opens up the new section that details the steps we need to follow for using our Azure Function with Power Apps and Microsoft Flow.

There click on Download button.

Click on Go to PowerApps

It opens up the PowerApps portal (asks for log in) and opens the New Connection page.

https://web.powerapps.com

Upload the JSON Definition file for our Azure Function, provide name and description and click on Next.

Click on Create.

Let us quickly test our new connection.

Click on New App in our PowerApps web portal.

Select PowerApps Studio for Web. Let us create a Blank App Phone.

Add a new Data Source and select our Azure Function there.

To get the API Key go to our function and expand API Definition Key.

It works properly.

3) Now let us move to our last step, wherein we use it inside Microsoft Flow and integrate it with Dynamics CRM.

The good thing is to configure the same for Microsoft Flow, we do not have to do any extra step as both Microsoft Flow and PowerApps share the same connection infra.

Go to Microsoft Flow portal

https://flow.microsoft.com/

We can find our Custom API already added there.

Let us create a new flow. Start with Dynamics 365.

When a record is created. Select Organization Name and Leads as the entity and click on Add an Action.

Search for our Custom API.

Select LastName and Email as Dynamic Content from the lead record created.

Click on Create Flow to create the flow.

Unfortunately, we get the below error

Let us go back to our Swagger Definition and update it.

We have updated it as following

Let us quickly test it, import it in Power Apps as new connection and come back to our Flow.

Edit the connection there and specify the API Key as we had done earlier inside Power Apps and update it.

Open Flow and quickly add the required steps and click on Create Flow.

We have successfully created our flow. Now let us test it.

Let us create a new lead record

Our flow runs and sends the mail

That’s it we are done with our simple implementation. The main purpose of this post was to show the integration possibilities which could help us design and implement real world complex scenarios.

Hope it helps..

Using WebClient to call external service from CRM Online Sandboxed Plugin (HTTP POST and JSON)


Sharing a sample code that can be used to send JSON data using POST to an external service inside CRM Online Plugin. As plugin runs in sandbox mode we cannot reference Newtonsoft’s JSON.NET library http://www.newtonsoft.com/json. The other option could be to use ILMerge, which isn’t that elegant.

Here, basically we are passing some information related to lead to an external service on Post Create of it.


using Microsoft.Xrm.Sdk;
using System;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;

namespace MyTestPlugin
{

 public class Lead
 {
 public string Topic { get; set; }
 public string FullName { get; set; }
 public string Email { get; set; }
 }

 public class MyPluginClass : IPlugin
 {
 public void Execute(IServiceProvider serviceProvider)
 {
 try
 {
 // Obtain the execution context from the service provider.
 IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

 // The InputParameters collection contains all the data passed in the message request.
 if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
 {
 // Obtain the target entity from the input parameters.
 Entity entity = (Entity)context.InputParameters["Target"];

 using (WebClient client = new WebClient())
 {
 var myLead = new Lead();
 myLead.Topic = entity.Attributes["subject"].ToString();
 myLead.FullName = entity.Attributes["fullname"].ToString();
 myLead.Email = entity.Attributes["emailaddress1"].ToString();

 DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Lead));
 MemoryStream memoryStream = new MemoryStream();
 serializer.WriteObject(memoryStream, myLead);
 var jsonObject = Encoding.Default.GetString(memoryStream.ToArray());


 var webClient = new WebClient();
 webClient.Headers[HttpRequestHeader.ContentType] = "application/json";
 var code = "key";
 var serviceUrl = "https://xyz.azurewebsites.net/api/mylead?code=" + code;

 // upload the data using Post mehtod
 string response = webClient.UploadString(serviceUrl, jsonObject);
 }
 }
 }
 catch (Exception ex)
 {
 throw new InvalidPluginExecutionException(ex.Message);
 }
 }
 }
}

Hope it helps..


Configuring Live Assist (Preview) for Dynamics 365.


Let us see how we can configure Live Assist step by step.

First, go to Applications tab of the Dynamics 365 Administration Center.

Select Live Assist for Dynamics 365 and click on Manage.

Click on Accept to give permission to the app.

Select the Dynamics 365 Instance and provide your email id, accept the terms and conditions and click on Submit.

This configures the Live Assist on the specified Dynamics 365 Instance and also sends the email to the email id specified.

Once the configuration is done, we can see the new Live Assist section added in our Settings area.

There we can click on Admin URL of Live Assist for further configuration.

Clicking on it opens the Admin Center.

Click on Confirm and Authorize.

The Dashboard of the admin center.

The Get Started page.

Code Snippet that we can use to enable Live Assist in web site.

Live Assist adds a new panel on the right inside CRM.

To test it we can make use of Demo Site provided along with Live Assist.

The agent within CRM can click on Conversation Icon and “Grab a chat” to start conversation.

Now suppose we want to configure our CRM Portal to use it. For this we need to copy the code snippet provided earlier. Go to the Header web template of our Web Site and paste the JavaScript code to our Header’s source code.

This enables Live Assist in the portal.

Communication between the CRM user and the Portal user.

The helpful links and video

https://neilparkhurst.com/2017/04/09/cafex-live-assist-my-initial-install-with-usd/

https://blogs.technet.microsoft.com/lystavlen/2017/03/16/live-assist-for-dynamics-365-first-look/

Hope it helps..

Setting Regarding of a record in Automatic Record Creation and Update Rules in Dynamics 365


Hi,

While implementing a scenario i.e. automatic case creation on phone call create using Automatic Record Creation and Updating Rules, we found that whenever we were setting the Regarding Object in the Phone Call activity, the case record was not getting created.

Create Case Rule Item –

Creating a Phone Call record using Case as Regarding object.

Workflow ran but the case record was not created.

Then we created phone call activity record without setting the regarding object. This time workflow ran and created the case record.

Basically, the workflow creates the case record and updates the Regarding Object in the Phone call record with this newly created case record.

However, if we check the Official documentation

https://www.microsoft.com/en-us/dynamics/crm-customer-center/set-up-rules-to-automatically-create-or-update-records-in-dynamics-365-customer-service.aspx#bkmk_RuleAndQueues

we have this mentioned

However, in our case we created a phone call record with case as regarding object and had case as the entity selected in the Create Record step, in this case also the Action were not executed.

Hope it helps..

List of all blog posts on CRM and Azure Integration



Configure Product Recommendations using Recommendations API in Dynamics 365


For configuring Product Recommendations first we need to enable the preview –

Go to Settings – Administration – System Settings – Previews

Select Yes and Click on OK.

As a next step, we need to create Cognitive Services for Recommendation API and connect it to CRM.

Go to Portal

https://portal.azure.com

Search and select Cognitive Services Accounts

Click on Add

Select Recommendation API and provide other details and click on Create.

From Overview, note down the Endpoint which will be used to configure the connection in CRM.

From Keys, copy value of the Key which will be used for configuring connection to CRM.

In CRM, go to Settings – Administration and click on Azure Machine Learning Recommendation Service Configuration.

Specify the value for the URL and Key we had noted down earlier, save the record and click on Test Connection to test the connection.

On Successful connection, we’d see Success message for Last Connection Status. Click on Activate to enable the connection.

Now we need to define\build the model for recommendations. For this go to Settings – Product Catalog and click on Product Recommendations.

We’d see a recommendation model with default values

The model will have Basked Data Entities already defined. We can edit\add new\ delete these existing configuration records for Basked Data Entities. Basked Data Entities recommendations are based on which products appear together.

For e.g. in below Opportunity record we can see 27 inch and 12 inch monitor opportunity products appearing together. It will look for all such line items records.

Similarly we have recommendation entities records configured which we can update.

Once done with the configuration, we need to click on Build Model Version to build the model.

It will create a corresponding model version record.

We can check its progress by refreshing it.

Here the model that we had defined has successfully build and it took around 6 minutes.

We can click on the Model Version to open the record to get the further details.

Next step would be to check the recommendations. For this click on Test Recommendations.

Pop up opens wherein we can select the Products and model version and click on Show Result to see what are the product recommendations.

Once satisfied with the test result, click on Activate to enable the recommendations.

We might get the below message in case we do not have good enough data in our system.

To see it in action, open an existing opportunity record , go to product sub grid and select a product and select Suggest Products.

A dialog box opens up that shows the Cross-Sell products and other details.

Get all the details here

https://technet.microsoft.com/library/56b35229-72f8-46ca-bebf-eae023f633c2.aspx

Hope it helps..

Configure Automatically suggest knowledge articles using Cognitive Services Text Analytics (Preview) in Dynamics 365 (online)


As a first step, we need to set up Text Analytics Service and connect it to our CRM Online. Follow the below post for that

https://nishantrana.me/2017/03/24/configure-case-topic-analysis-using-cognitive-services-text-analytics-preview-in-dynamics-365-online/

Next, we need to set up Knowledge Search field settings

For this go to Settings – Service Management and click on Knowledge Search field Settings

There click on New to create a new Search Model record.

Below we have specified case as our source entity. Click on Save.

Next, we need to define Keyword fields for our model, click on + to create a new text analytics entity mapping record.

To keep things simple, we have selected entity as Case and Field as Case Title based on which suggestions will be made. Save the record.

Click on Activate to activate the model.

Next, we need to modify the Case form to include knowledge base suggestions

Open the Conversation Tabs, go to Knowledge Base Search and select Text Analytics for Give Knowledge base suggestions as described below and publish the form

Open any of the case record, go to KB Records. Here based on the Case Title, the text analytics picks up the keyword “Delay” and shows/suggests the corresponding KB Articles matching that keyword.

Get all the details here

https://technet.microsoft.com/en-us/library/mt703319.aspx

Hope it helps..

Configure Document Suggestions using Cognitive Services Text Analytics (Preview) in Dynamics 365 (online)


Let us take a simple example to understand how to configure Document Suggestion preview feature.

To do so first we need to enable Text Analytics Service, Connect it to our CRM Online and configure similar record suggestions. Please follow the below post for all the details.

https://nishantrana.me/2017/03/27/configure-similar-record-suggestion-using-cognitive-services-text-analytics-preview-in-dynamics-365-online/

Go to Settings – Document Management – Manage Document Suggetions

Select the entity for which we want to enable it, as we had our similar record suggestions enabled for Case we select the Case entity here.

Click on Apply.

Now as we already have Similar Record Suggestions configured for Case entity, for a case record with Delay keyword in its title we get the below suggestions

So, for Delay in Dispatch record we are getting Delay in service, delivery and shipment as suggestions as similar cases.

Now what we have done over here next is that we have attached document(s) to each of these case records.

For Delay in Dispatch case record –

For Delay in Service case record –

For Delay in Shipment record we have 2 document attached.

For Dispatch in Delivery case record we do not have any document attached yet.

Now let us open case with title “Dispatch in Delivery” and go to its Documents related records and click on Show Suggestions button

A dialog opens which list all the documents that are associated to the case records similar to the Delay in Delivery record i.e. all the remaining case records having delay keyword in its title.

Select documents and click on Copy.

Documents Copied to the Delay in Delivery record.

Hope it helps..

Configure Similar Record Suggestion using Cognitive Services Text Analytics (Preview) in Dynamics 365 (online)


As a first step, we need to enable text analytics and connect it to CRM.

Follow the below post for enabling text analytics, connecting CRM online to Text Analytics service.

https://nishantrana.me/2017/03/24/configure-case-topic-analysis-using-cognitive-services-text-analytics-preview-in-dynamics-365-online/

As a next step, we need to configure Similar Records Suggestions, for that go to

Settings – Data Management – Similar Records Suggestions settings

Click on New to create a new similarity rule record

Below we have created rule with Case as source entity and specified Yes for “Use Text Analytics for Target Match”

After we have created the similarity rule, we need to define the fields based on which matching will be done and suggestions will be made.

Here we have specified Criteria as Text Match, which would match the Text for the field Case Title of the Case Entity.

Save the above record and click on Activate to run the similarity rule.

Open any of the existing case, in our below scenario we have opened the case with title “Delay in Shipment” and click on +

This opens up the dialog that shows similar cases (with title having Delay word in it) using Text Analytics Service configured.

What happens if we deactivate the Similarity Rule?

We get the below error –

Checking the metric in the Text Analytics API.

Get all the details here

https://technet.microsoft.com/en-us/library/mt703318.aspx

Hope it helps..

Requests to this API should contain at least 100 documents, where each document is not null or empty error while configuring Topic Analysis using Text Analytics in Dynamics 365


Hi,

Recently while trying to configure Topic Analysis in Dynamics 365

https://nishantrana.me/2017/03/24/configure-case-topic-analysis-using-cognitive-services-text-analytics-preview-in-dynamics-365-online/

we got the below error for the failed record.

Error Message:{“code”:”BadRequest”,”message”:”Invalid request”,”innerError”:{“code”:”InvalidRequestContent”,”message”:”Requests to this API should contain at least 100 documents, where each document is not null or empty”,”minimumNumberOfDocuments”:100}}

This was because we had very few case records in our CRM organization < 30. We created few more records to increase the count to be more then 100 and re run the build. This time it got succeeded.

Hope it helps..

Configure Dynamics 365 and Azure Service Bus Integration (using TwoWay relay, Azure Aware Plugin and listener)


Let us pick up from where we left in the previous post and implement two way relaying through which we can get the response back from the listener.

https://nishantrana.me/2017/03/22/configure-dynamics-365-and-azure-service-bus-integration-using-oneway-relay-and-listener/

First let us update the Service Endpoint Registration, change the designation type to TwoWay, it would also ask to enter the SAS Key. Copy it from Azure and paste it.

Update the listener windows application created in the previous post to implement ITwoWayServiceEndpointPlugin

Use the below code to create the custom azure aware plugin.

Get the service endpoint id from the Properties window of the Service End Point registered.

Register the assembly and add the Post Create Synchronous Lead Step to it.

As we are using trace service to log the response, set All for Enable logging to plugin-trace log option from Administration – System Setting – Customization.

Start the listener windows application and to trigger the plugin, create the lead record

We can see the execute method being called from Azure Service bus on create of Lead record.

The message being returned from listener application to the plugin.

The newly created lead record.

The trace message within the plugin –

Plugin Trace log with the response received from the listener –

Hope it helps..

Configure Dynamics 365 and Azure Service Bus Integration (using OneWay relay and listener)


Continuing our previous post

https://nishantrana.me/2017/03/22/configure-dynamics-365-and-azure-service-bus-integration-through-queue-and-queueclient/

Here we’d add a new Shared Access Policy in the Azure Service Bus.

We can copy the connection string

Paste it in Service Endpoint registration dialog box of Plugin Registration tool

Change the designation type to OneWay, use https for the namespace address.

Register a step for creation of lead

Now we go and create a lead record, which triggers our plugin and creates a system job for it.

The system job fails as we do not have any active listener at the end point.

Now let us create a simple windows application which will act as listener.

Basically, we need to implement IServiceEndPointPlugin Interface, create a Service Host, define a new transportclientendpointbehaviour with shared access signature token provider, use WS2007HttpRelayBinding in our service end point.

Now run the listener application, and create a lead record in CRM.

We can see the break point hit in our listener application’ Execute method. Execute method is invoked whenever a message is posted to the service bus by Microsoft Dynamics 365.

System Job also shows the status as succeeded as we had our listener registered to the endpoint and running.

The helpful post

http://www.crmviking.com/2016/10/microsoft-crm-azure-service-bus-part-3.html

https://blogs.msdn.microsoft.com/swetagu/2016/04/12/crm-azure-service-endpoint-and-listener-deep-dive/

http://iunknownme.com/blog/2015/05/27/dynamics-crm-integration-using-azure-service-bus-part-i-using-service-bus-relays/

Hope it helps.

Configure Dynamics 365 and Azure Service Bus Integration (through Queue and QueueClient)


Let us configure Dynamics 365 and Azure Service Bus integration.

Here we would implement a basic scenario, every time a lead is created in CRM we’d pass this execution context information to the queue. The app then reads and shows the information.

As a first step, we need to register a service end point through plugin registration tool.

Here we need to provide the connection string

So, let us create SAS configured Azure service bus namespace and a queue in it.

Go to portal

https://portal.azure.com

Search for Service Bus, provide the required details and click on Create.

Next, we’d create a queue. Inside Service Bus go to Queues and click on plus button create a Queue

Next inside the queue we need to go to Shared Access Policy settings and click on Add button to add a new SAS Key

Next click on connection strings, followed by Add button to add a new SAS Key.

This creates the key. Now copy the connection string.

Paste the connection string in the Plugin Registration tool

It will auto populate all the details. Now click on Save.

This adds a new service end point

Now register a new step – Entity – Lead and Message – Create.

Now to trigger it let us create a lead record in CRM.

A corresponding System Job will have the status.

Back in our queue we can see 1 new message added to it.

To read the message, let us create a simple windows application.

Install the WindowsAzure.ServiceBus package.

The source code for the queue. Here the connection string will be the same which we had specified in the plugin registration tool. The message body is of type RemoteExecutionContext.

The output.

Hope it helps..