Plugins in Dynamics CRM
Plugins in Dynamics CRM
Definition :
A Dynamics CRM plugin is custom business logic or code that integrates with Microsoft Dynamics
CRM to modify or extend the standard behaviour of the platform. Essentially, plugins act as event
handlers and are registered to execute in response to specific events, such as creating, updating, or
deleting records.
o Open Visual Studio and create a new project. Select Class Library and name it
MyFirstPlugin.
o Create a new class that implements the IPlugin interface. This interface requires you
using System;
using Microsoft.Xrm.Sdk;
namespace MyFirstPlugin
IPluginExecutionContext context =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// The InputParameters collection contains all the data passed in the message request.
if (entity.LogicalName != "account")
return;
Now that you have created your first plugin, the next step is to register it with Dynamics 365 CE
using
o Browse to the DLL file generated from your Visual Studio project and select it.
o Enter a name and description for the assembly and click Register.
3. Create a Step:
o After registering the assembly, you need to create a step that specifies when the
o Right-click on the newly registered assembly and select Register New Step.
o Fill in the details, such as the message (e.g., Create), primary entity (e.g., account),
• Pre-Validation Stage:
o Executes outside the database transaction, meaning changes made here are not
• Pre-Operation Stage:
o Executes within the database transaction, so changes are rolled back if the main
operation fails.
Main Operation:
• Post-Operation Stage:
o Suitable for actions dependent on the results of the main operation, such as sending
o Execute immediately and block the main operation until the plugin completes.
• Asynchronous Plugins:
o Ideal for operations that do not require immediate execution, such as sending emails
o Use the Service Locator pattern to instantiate required services only when needed.
2. Optimize Queries:
3. Use Caching:
Proper error handling and logging are essential for diagnosing issues and ensuring reliable plugin
execution.
3. Graceful Degradation:
o Design plugins to handle failures gracefully, ensuring that the main operation can
continue if possible.
Security Considerations
Security is a critical aspect of plugin development. Here are some key considerations:
o Ensure that all user inputs are validated to prevent security vulnerabilities such as
SQL injection.
o Check user roles and permissions before performing operations to ensure compliance
Performance Optimization
Optimizing plugin performance is essential for maintaining system responsiveness and user
satisfaction.
performance.
Working with Secure and Unsecure Configuration
Plugins can be configured with secure and unsecure configuration data, providing flexibility
in managing sensitive information.
1. Secure Configuration:
2. Unsecure Configuration:
Example for Unsecure configuration Plugin (Show hide Views based On BU):
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Sdk.Query;
namespace Plugins
_secureConfig = secureConfig;
_unsecureConfig = unsecureConfig;
#endregion
IPluginExecutionContext context =
(IPluginExecutionContext)serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionCon
text));
IOrganizationServiceFactory serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService adminUserService =
serviceFactory.CreateOrganizationService(adminuser.Id);
try
if (context.MessageName.Equals("RetrieveMultiple"))
if (user != null)
userBUName = user.Attributes.Contains("businessunitid") ?
user.GetAttributeValue<EntityReference>("businessunitid").Name : string.Empty;
UserEntity["cap_lastaccesstime"] = DateTime.Now;
tracer.Trace("User Name: " + user.Attributes["fullname"].ToString().ToUpper());
adminUserService.Update(UserEntity);
tracer.Trace("lastaccesstime stamped");
query = (QueryExpression)context.InputParameters["Query"];
if (query.EntityName == "savedquery")
EntityFilters = EntityFilters.Entity,
LogicalName = "queueitem"
};
RetrieveEntityResponse retrieveAccountEntityResponse =
(RetrieveEntityResponse)service.Execute(retrieveEntityRequest);
EntityMetadata queueItemEntity =
retrieveAccountEntityResponse.EntityMetadata;
if (returnedtypecode == entityTypeCode)
if (!string.IsNullOrWhiteSpace(userBUName))
List<BUAndViewsMapping> buAndViewsMapping =
ReadUnsecuredConfigStringToObject(_unsecureConfig);
query.Criteria.Conditions.Add(queryCondition);
else
else
else
string parameterName =
SMHviews.Entities[i].Contains("cap_parametername") ? SMHviews.Entities[i]
["cap_parametername"].ToString() : string.Empty;
treatmentViews = treatment.Split(',');
allergyViews = allergy.Split(',');
conditionViews = condition.Split(',');
{
string familyHistory =
SMHviews.Entities[i].Contains("cap_parametervalue") ? SMHviews.Entities[i]
["cap_parametervalue"].ToString() : string.Empty;
familyHistoryViews = familyHistory.Split(',');
SAOViews = sao.Split(',');
.ToArray();
socialActivityViews = social.Split(',');
EntityFilters = EntityFilters.Entity,
LogicalName = "cap_treatment"
};
RetrieveEntityResponse retrieveTreatmentEntityResponse =
(RetrieveEntityResponse)service.Execute(retrieveTreatmentRequest);
EntityMetadata treatmentEntity =
retrieveTreatmentEntityResponse.EntityMetadata;
if (returnedtypecode == treatmentEntityTypeCode)
{
if (treatmentViews.Length > 0)
query.Criteria.Conditions.Add(treatmentCondition);
EntityFilters = EntityFilters.Entity,
LogicalName = "cap_allergy"
};
RetrieveEntityResponse retrieveAllergyEntityResponse =
(RetrieveEntityResponse)service.Execute(retrieveAllergyRequest);
if (returnedtypecode == allergyEntityTypeCode)
if (allergyViews.Length > 0)
query.Criteria.Conditions.Add(allergyCondition);
}
RetrieveEntityRequest retrieveConditionRequest = new RetrieveEntityRequest
EntityFilters = EntityFilters.Entity,
LogicalName = "cap_condition"
};
RetrieveEntityResponse retrieveConditionEntityResponse =
(RetrieveEntityResponse)service.Execute(retrieveConditionRequest);
EntityMetadata conditionEntity =
retrieveConditionEntityResponse.EntityMetadata;
if (returnedtypecode == conditionEntityTypeCode)
if (conditionViews.Length > 0)
query.Criteria.Conditions.Add(condition);
EntityFilters = EntityFilters.Entity,
LogicalName = "cap_familyhistoryshort"
};
RetrieveEntityResponse retrieveFamilyHistoryEntityResponse =
(RetrieveEntityResponse)service.Execute(retrieveFamilyHistoryRequest);
EntityMetadata familyHistoryEntity =
retrieveFamilyHistoryEntityResponse.EntityMetadata;
if (familyHistoryViews.Length > 0)
query.Criteria.Conditions.Add(familyHistoryCondition);
EntityFilters = EntityFilters.Entity,
LogicalName = "cap_recreationaldruguse"
};
RetrieveEntityResponse retrieveSAOEntityResponse =
(RetrieveEntityResponse)service.Execute(retrieveSAORequest);
if (returnedtypecode == SAOEntityTypeCode)
if (SAOViews.Length > 0)
query.Criteria.Conditions.Add(SAOCondition);
}
RetrieveEntityRequest retrieveSocialActivityRequest = new
RetrieveEntityRequest
EntityFilters = EntityFilters.Entity,
LogicalName = "cap_socialactivity"
};
RetrieveEntityResponse retrieveSocialActivityEntityResponse =
(RetrieveEntityResponse)service.Execute(retrieveSocialActivityRequest);
EntityMetadata socialActivityEntity =
retrieveSocialActivityEntityResponse.EntityMetadata;
if (returnedtypecode == socialActivityEntityTypeCode)
if (socialActivityViews.Length > 0)
query.Criteria.Conditions.Add(socialActivityCondition);
EntityFilters = EntityFilters.Entity,
LogicalName = "cap_careadvicegiven"
};
RetrieveEntityResponse retrieveAccountEntityResponse1 =
(RetrieveEntityResponse)service.Execute(retrieveEntityRequest1);
query.Criteria.Conditions.Add(regradeQueryCondition);
ms.Close();
return deserializedBuAndViews;
{
EntityReference user = new EntityReference();
try
APfilterexpression.AddCondition(Apconditionexpression);
ApplicationParameterQuery.Criteria.Filters.Add(APfilterexpression);
if (APdata.Entities.Count > 0)
fe.AddCondition(ce);
qe.Criteria.Filters.Add(fe);
EntityCollection ec = service.RetrieveMultiple(qe);
user.Id = ec.Entities[0].Id;
user.LogicalName = ec.Entities[0].LogicalName;
}
return user;
try
<entity name='cap_applicationparameter'>
<filter type='and'>
</filter>
</entity>
</fetch>";
EntityCollection ResultApplicationParameter = service.RetrieveMultiple(new
FetchExpression(FetchApplicationParameter));
return ResultApplicationParameter;
throw;
return null;
"BUName": "Sales",
"Views": [
},
"BUName": "Support",
"Views": [
},
"BUName": "Marketing",
"Views": [
},
"BUName": "HR",
"Views": [
transaction.
context.SharedVariables["key"] = value;
Context in Plugins
The context in a plugin refers to the IPluginExecutionContext object, which contains
information about the runtime environment of the plugin. It provides detailed information
about the event that triggered the plugin, the data being processed, and other relevant
parameters.
Key properties of the context include:
MessageName: The message (operation) that triggered the plugin, e.g., Create,
Update, Delete, Assign, SetState, etc.
PrimaryEntityName: The name of the entity being acted upon (e.g., account,
contact, opportunity).
PrimaryEntityId: The ID of the entity being acted upon. This is typically the unique
identifier (GUID) of the record.
InputParameters: A collection of parameters that are passed into the plugin, which
can include data about the entity being modified or other relevant information.
OutputParameters: Parameters that the plugin can use to modify the outcome of
the operation.
Depth: The execution depth (used to prevent infinite recursion in workflows or
plugins).
UserId: The GUID of the user who triggered the plugin.
Stage: Indicates the stage at which the plugin is executed (pre-operation, post-
operation).
SecurityContext: Information about the security privileges of the user executing the
plugin.
For example, in a plugin, you can check the MessageName to ensure that your logic only
runs for a certain message, or use the PrimaryEntityId to fetch additional data related to the
entity being worked on.
Target in Plugins
The target in a plugin refers to the Target parameter passed into the plugin, which typically
contains the entity object that the operation is being performed on. This is usually available
in the InputParameters collection.
The target could be:
For Create: The entity record that is being created.
For Update: The entity record that is being updated, containing the updated fields.
For Delete: The entity record that is being deleted (though you typically only get the
ID here and not the full entity data).
For Associate/Disassociate: The related entity data.
You can access the target by using the InputParameters collection in the context. For
example, in an update operation, you can retrieve the modified entity from the Target
property to determine what fields have changed.
Example of how you access the target:
public void Execute(IServiceProvider serviceProvider)
{
// Retrieve the plugin execution context
IPluginExecutionContext context =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
if (targetEntity != null)
{
// Work with the target entity (e.g., update fields)
Guid entityId = targetEntity.Id;
// You can also access specific attributes of the target entity like:
string name = targetEntity["name"].ToString();
}
}