Archive
[Code Snippet] Dynamics Post Assign Plugin
This article is a response to one of the blog questions.Â
Below is the code snippet for Post Assign (i.e., Ownership change) plug-in.
In the ‘Post Assign’ plug-in you get 2
- Current record as ‘Entity Reference’ in ‘Target‘ attribute.
- Records new Owner (i.e., Owner or Team) in the ‘Assignee‘ attribute.
EntityReference entRefCurrentRecord = null;
EntityReference entRefAssignee = null;// Get current record as Entity Reference
if ((context.InputParameters.Contains(“Target”)) && (context.InputParameters[“Target”] is EntityReference))
{
entRefCurrentRecord = (EntityReference)context.InputParameters[“Target“];
}// Get User/Team whom the record assigned to from ‘Assignee’ property of Context
if ((context.InputParameters.Contains(“Assignee”)) && (context.InputParameters[“Assignee”] is EntityReference))
{
entRefAssignee = (EntityReference)context.InputParameters[“Assignee“];
}// Write your business logic
- You might want to register Pre/Post images on the Plug-in step, to read other attributes of the record.
đ
Complete a transaction and throw exception in CRM Plug-in
Recently I was asked a question in my blog on how to achieve below scenario in plug-in.
- User try to save Account record by providing data in multiple fields.
- Create Plug-in should check whether any other Account already exists in CRM with provided data.
- If match found, update the existing record and display âCannot save the Account as Account with data already existsâ
- If no match found, create an Account.
Challenge:
- If ‘Account’ match found, system should update matched Account and at the same time throw message âCannot save the Account as Account with data already existsâ.
- To display message Plugin must throw Execution with message which would roll back the update operation.
Proposed Design:
- Register a Plug-in on âPreCreateAccountâ with following logic, if matching âAccountâ already exists with input data.
- To complete update operation,
- Use âExecuteMultipleRequestâ with option âContinueOnError = trueâ which completes transaction.
- Instantiate âUpdateRequestâ and execute using âExecuteMultipleRequestâ
- In next line, throw exception with message
Plug-in Code:
// Get the matched Account
Entity matchedAccount = new Entity(“account”);
UpdateRequest reqUpdate = new UpdateRequest();
reqUpdate.Target = matchedAccount;// Use this to complete the update operation even on an exception
ExecuteMultipleRequest reqMultiple = new ExecuteMultipleRequest(){
Requests = new OrganizationRequestCollection(),
Settings = new ExecuteMultipleSettings(){
ContinueOnError = true,
ReturnResponses = false
}
};// Add Update Request to Multiple Request.
reqMultiple.Requests.Add(reqUpdate);// Trigger the Execute Multiple.
crmOrgService.Execute(reqMultiple);// Use this to display message to user
throw InvalidPluginExecutionException(“Cannot save the Account as Account with data already exists”);
đ
Specified domain does not exist or cannot be contacted â Error connecting to SharePoint from CRM on premise Plug-in
In one of our Plug-in, we have logic to upload the noteâs attachment to SharePoint server.
Everything was working as expected until we got this unexpected exception âSpecified domain does not exist or cannot be contactedâ.
Reason & Fix:
- Reason for this exception while updating Plug-in Assembly, I accidentally set the âIsolation modeâ to âSandboxâ.
- Since there was no trust established with SharePoint server, plug-in thrown exception when tried to upload file to SharePoint Document Library.
- Changing Isolation Mode to âNoneâ solved our issue.
- Alternative way for Isolation ‘none’ is to establish trust. Refer this article on how establish trust.
đ
Passing configuration data using Plug-in registration tool (Secured vs. Unsecured)
- CRM plugin registration tool contain âUnsecure & Secureâ configuration sections while registering a “Step”
- We can pass configuration data and can be used in the plug-in logic.
Secured vs. Unsecured
Below are key differentiations between Secured and Unsecured data configuration
- Access
- Data passed through âUnsecureâ section is PUBLIC (i.e., It can be read by any user in CRM).
- Only users with âSystem Administratorâ role have access to the data passed through âSecureâ configuration section
- Storage
- âUnsecureâ config data will be stored along with the Plugin ‘Step’ registration information (i.e., In SdkMessageProcessingStep entity)
- âSecure” config data will be stored in a separate entity named âSdkMessageProcessingStepSecureConfigâ
- Only âSystem Administratorâ has Read access on this entity, hence only users with âSys Adminâ role can access this data
- Both âSecured & Unsecuredâ configuration data stored as âPlain textâ in DB
- Outlook Sync
- âUnsecuredâ configuration data is downloaded to the userâs computer when they go offline making it Unsecure
- âSecuredâ configuration data is NOT downloaded to Userâs Computer when they go Offline
How to read Configuration data in Plug-in
In our plug-in class, we can define a constructor that passes two parameters (i.e., unsecure configuration and secure configuration)
public class AccountCreateHandler: IPlugin{
public AccountCreateHandler(string unsecure, string secure){
// Do something with the parameter strings.
}
public void Execute(IPluginExecutionContext context){
// Do something here.
}
}
Note :- If you want to read âSecureâ configuration in the plug-in code, either change the user context in plugin registration as “CRM administrator ” or Impersonate to “CRM Administrator” role user in the code
đ
Plug-ins in CRM 2011 – Useful points
Plug-in stages
- Pre validation
- Registered Plug-in run before the form is validated
- Useful if you want to implement business logic before the actual validation starts. Â i.e., Changes made in plug-in won’t be saved if the validation of the main system plugins complain because the changes are outside the database transaction.
- Ex – Some âdeleteâ plug-ins. Deletion cascades happen prior to pre-operation, therefore if you need any information about the child records, the delete plugin must be pre-validation.
- Pre -operation
- After validation and before the values are saved to the database
- Post operation
- Plugin will run after the values have been inserted/changed on the database
Database Transactions in Plug-Ins
- Plug-ins may or may not execute within the database transaction
- You can check if the plug-in is executing in-transaction by reading the ‘IsInTransaction‘ property of IPluginExecutionContext
- Stages 20 and 40 are part of the database transaction while stage 10 and 50 may be part of the transaction
- If plugin throws an exception, every action done during the transaction will be rollback
Few more Points
- Whether a plug-in executes synchronously or asynchronously, there is a 2 minute time limit imposed on the execution of a (message) request.
- If the execution of your plug-in logic exceeds the time limit, a Timeout exception is thrown
- If a plug-in needs more processing time than the 2 minute time limit, consider using a workflow or other background process
- âPre-operationâ operations that CRM will do will not be carried out in pre-validation stage.
- If you are deleting a record that has many-to-many relationship records with another entity; these relationship records will still be available in pre-validation stage, but not in pre-operation stage.
- âTargetâ entity (i.e., pluginContext.InputParameters[“Target”])
- Itâs the entity on which plug-in registered
- It only contains âdirtyâ attributes. if you convert to early bound, the value of the unchanged attribute will be
null
Useful MSDN article
:)
Fetching user security roles using Linq in CRM 2011 Plug-in’s
Hi,
Below is the sample code to fetch the User’s security roles based on the âUser Idâ in the Plug-in’s using Linq
       /// <summary>
/// Returns the list of User security role names
/// </summary>
private List<string> GetUserRoles(IOrganizationService service, Guid userId)Â {
// Create Query Expression to fetch Role Entity
var query = new QueryExpression
{
// Setting the link entity condition and filter condition criteria/
LinkEntities =
{
new LinkEntity
{
LinkFromEntityName = “role”,
LinkFromAttributeName = “roleid”,
LinkToEntityName = “systemuserroles”,
LinkToAttributeName = “roleid”,
LinkCriteria = new FilterExpression
{
FilterOperator =
LogicalOperator.And,
Conditions =
{
new ConditionExpression
{
AttributeName = “systemuserid”,
Operator =Â Â Â Â ConditionOperator.Equal,
Values =
{
userId
}
}
}
}
}
},
ColumnSet = new ColumnSet(true),
EntityName = “role”
};
// Obtain results from the query expression.
var userRoles = service.RetrieveMultiple(query);
// Get the usre role names collection
var roleNames = new List<string>();
if (userRoles != null)Â Â {
roleNames.AddRange(
from entrole in userRoles.Entities
select entrole as Role
into role
where role != null && role.RoleId != null
select role.Name);
}
return roleNames;
}
How do I call this method :-
- In your plug-in, pass the service and User Id as parameters to this method
public void Execute(IServiceProvider serviceProvider) {
context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = serviceFactory.CreateOrganizationService(context.UserId);
// Get the current users Security Roles Name’s
Var roleNames = GetUserRoles(service, this.context.UserId);
}
Hope it helps đ
Sending an Email using CRM 2011 Plug In
Hi,
In one of my recent requirements, I had to send an Email using Plug-in (Late Binding). Below is the code snippet.
private void SendEmail(IOrganizationService service, Guid recieverUserId, Guid senderUserId, Guid regardingObjectId, string emailBody, string emailSubject)
{
Entity email = new Entity();
email.LogicalName = “email”;//Set regarding object property (i.e. The entity record, which u want this email associated with)
EntityReference regardingObject = new EntityReference(“{entity_name}”, regardingObjectId);
email.Attributes.Add(“regardingobjectid”,regardingObject);//Defining Activity Parties (starts)
EntityReference from = new EntityReference(“systemuser”, senderUserId);
EntityReference to = new EntityReference(“systemuser”,recieverUserId);
//Derive from party
Entity fromParty = new Entity(“activityparty”);
fromParty.Attributes.Add(“partyid”,from);//Derive to party
Entity toParty = new Entity(“activityparty”);
toParty.Attributes.Add(“partyid”, to);EntityCollection collFromParty = new EntityCollection();
collFromParty.EntityName = “systemuser”;
collFromParty.Entities.Add(fromParty);EntityCollection collToParty = new EntityCollection();
collToParty.EntityName = “systemuser”;
collToParty.Entities.Add(toParty);email.Attributes.Add(“from”,collFromParty);
email.Attributes.Add(“to”, collToParty);//Defining Activity Parties (ends)
//Set subject & body properties
email.Attributes.Add(“subject”,emailSubject);
email.Attributes.Add(“description”, emailBody);//Create email activity
Guid emailID = service.Create(email);
//Sending email
SendEmailRequest reqSendEmail = new SendEmailRequest();
reqSendEmail.EmailId = emailID;//ID of created mail
reqSendEmail.TrackingToken = “”;
reqSendEmail.IssueSend = true;SendEmailResponse res = (SendEmailResponse)service.Execute(reqSendEmail);
}
This is tested code and you can use as it is. Hope it Helps đ