Track an Entity record form opening / retrieve activity by system user in Dynamics 365 CRM
If you want to track a user who has opened records of any specific entity then you are on the right blog because today we are going to see how we can do simple customization to track the user activity of who has open which record for how many times.
Step 1: Create an Entity to track the log of retrieve activity of the registered entity.
Following are fields in the entity to track user activity tracking activity
1. Name — Logical name of Retrieved Entity.
2. Record Id — Record Id of that Retrieved Entity.
3. No of Time Retrieved — Stored number of times a user has retrieved that specific record.
Step 2: Create a Plugin to create a Retrieved Log record
The record will be created or updated whenever the user opens the entity form to check details and the following is code for the same.
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
namespace Demo.RetriveRecordTracker
{
public class TrackActivity : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
if (context.Depth < 2)
{
if (context.InputParameters.Contains("Target"))
{
EntityReference entity = (EntityReference)context.InputParameters["Target"];
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
try
{
//fetchXML to retrieve existing records
string fetchXML = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='cf_entitytracker'>
<attribute name='cf_entitytrackerid' />
<attribute name='cf_name' />
<attribute name='createdon' />
<attribute name='cf_nooftimeretrieved' />
<order attribute='cf_name' descending='false' />
<filter type='and'>
<condition attribute='cf_recordid' operator='eq' value='" + entity.Id.ToString() + @"' />
<condition attribute='cf_user' operator='eq' uitype='systemuser' value='{" + context.InitiatingUserId + @"}' />
<condition attribute='cf_name' operator='eq' value='" + entity.LogicalName.ToString() + @"' />
</filter>
</entity>
</fetch>";
//Retrieve existing Record of Log with same Record, User and Entity
EntityCollection retrievedExistingLog = service.RetrieveMultiple(new FetchExpression(fetchXML));
//If record don't exist in system then create a new Retrieve Entity Log.
if (retrievedExistingLog.Entities.Count == 0)
{
Entity retrieveLog = new Entity("cf_entitytracker");
retrieveLog["cf_recordid"] = entity.Id.ToString();
retrieveLog["cf_name"] = entity.LogicalName.ToString();
retrieveLog.Attributes["cf_user"] = new EntityReference("systemuser", context.InitiatingUserId);
retrieveLog["cf_nooftimeretrieved"] = 1;
service.Create(retrieveLog);
}
//If record exist with same Record, User and Entity then increase the number of retrieve count.
else
{
Entity existingLog = retrievedExistingLog.Entities[0];
Entity updateRetrievedLog = new Entity
{
Id = existingLog.Id,
LogicalName = existingLog.LogicalName
};
updateRetrievedLog["cf_nooftimeretrieved"] = existingLog.GetAttributeValue<int>("cf_nooftimeretrieved") + 1;
service.Update(updateRetrievedLog);
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in TrackActivity.", ex);
}
catch (Exception ex)
{
tracingService.Trace("TrackActivity: {0}", ex.ToString());
throw;
}
}
}
}
}
}
Explanation:
1. When the plugin will trigger it will check if the retrieved log of that record is already present or not.
2. If retrieve records is not present it will simply create a log record with the following details
a. Name — Type of records which user has opened [Entity]
b. Record Id — Record Id of record which user has opened
c. User — which the user has opened the record.
d. Count = 1
3. If the retrieved record is already existing in the system then it will increment the count of the number of times a user has retrieved that record by 1 so that we can track how many times the same user has open that specific record.
Step 3: Register the Plugin on Retrieve of Entity on entities for which you want to add tracking.
Retrieve: It will trigger whenever an entity form is open by any user.
While registering the new step for the plugin please make sure that Run in User’s Context must be “Calling User” so that we can have a track that which user has opened which record.
Note: All security roles which are given to the user should have read, create and update right to “Entity Tracker” Entity.
Also, the stage of execution of Plugin and execution mode must be “PostValidation” and “Asynchronous” so that it will not affect any system jobs and it can run in the background process.
If you want to track a retrieve activity of opportunity then you just need to register the new step and select Primary Entity as an opportunity as I have already done for Account and Contact.
Now, your system is ready to track the user’s entity retrieve activities, and you will see the following records:
Using the above record you can create any type of custom charts and put them in your admin dashboard or you can create a Power BI report to track activity.
I hope this helps you, if yes please like the blog. And, the next blog will be on the dashboard & charts based on our Entity Tracker records so stay tuned for that!