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.