Introduction
Hi everyone, I just want to share how Share/Unshare in CRM will trigger a plugin or just in case you need to do some logic after users has done the Share/Unshare records in CRM.Especially if you want to Share the child records once you share the parent record, yes you can do the Cascading behaviour, but you might be aware that this parental and configurable cascading behaviour can only applied to 1 relationship, so imagine you have many entities, which this problem is the one i am facing right now.
The Problem
In the Plugin Registration Tool, there is no Share or Un-Share Messages and you see MSDN also does not have!So meaning CRM does not allow the injection of the Share or Un-Share logic?
No..CRM does allow, just the Message Name is..
GrantAccess and RevokeAccess
Meanwhile you also can get the Parameters from that Request
The Code
This is the Code!//pass the context here from your common Execute function void Post_Message_GrantOrRevokeAccess(IServiceProvider serviceProvider, IPluginExecutionContext context) { if (context.MessageName == "GrantAccess") { //this GrantAccess is for sharing //for Unshare, messagename = "RevokeAccess" and will do the same passing parameters // Obtain the target entity from the input parameter. EntityReference EntityRef = (EntityReference)context.InputParameters["Target"]; //after get this EntityRef then will be easy to continue the logic //Obtain the principal access object from the input parameter Microsoft.Crm.Sdk.Messages.PrincipalAccess PrincipalAccess = (Microsoft.Crm.Sdk.Messages.PrincipalAccess)context.InputParameters["PrincipalAccess"]; //Then got the User or Team and also Access Control that being Granted //***to Get User/Team that being Shared With var userOrTeam = PrincipalAccess.Principal; var userOrTeamId = userOrTeam.Id; var userOrTeamName = userOrTeam.Name; //this userOrTeam.Name will be blank since entityReference only will give you ID var userOrTeamLogicalName = userOrTeam.LogicalName; //use the logical Name to know whether this is User or Team! if (userOrTeamLogicalName == "team") { //what you are going to do if shared to Team? } if (userOrTeamLogicalName == "systemuser") { //what you are going to do if shared to Team? } Trace(userOrTeamId.ToString()); Trace(userOrTeamLogicalName); //***to Get the Principal Access var AccessMask = PrincipalAccess.AccessMask; Trace(AccessMask.ToString()); throw new InvalidPluginExecutionException("to trigger the trace only"); //please remove later //your logic continue here after already have all of them } else if (context.MessageName == "RevokeAccess") { // Obtain the target entity from the input parameter. EntityReference EntityRef = (EntityReference)context.InputParameters["Target"]; //after get this EntityRef then will be easy to continue the logic //Unshare does not have PrincipalAccess because it removes all, only can get the revokee //Obtain the principal access object from the input parameter var Revokee = (EntityReference)context.InputParameters["Revokee"]; var RevokeeId = Revokee.Id; var RevokeeLogicalName = Revokee.LogicalName; //this one Team or User Trace(RevokeeId.ToString()); Trace(RevokeeLogicalName); throw new InvalidPluginExecutionException("Unshared"); //please remove later } }
I just give you the concept that you can just continue from it..
Register the Plugin
Yup this is the last step, just using your favorite Plugin Registration Tool will do.Result from the Trace
And here is the result that you can see, you can get the user or Team you have shared With and also What is the Access MaskI try to share to a CRM User: Read and Write
So you can get the full Parameter in your plugin
Here is the Trace result
*As you can see you can get the System User ID as well Team ID if you share to Team and also the privilege, ReadAccess and also WriteAccess
How about UnShare?
Same as well!
I completely remove the CRMUser from all his previous shared access (Read & Write)
And this is the Trace result
*But, you need to Remember that Share here meaning performing Share to the user or Team that previously did not have any Access, it will trigger the GRANTACCESS event.
And also Unshare means Completely remove the Access, then it will trigger the REVOKEACCESS event.
If you want to only modify the Access (ex: from Read and Write to Read only), then you need to register your plugin to another message, so call MODIFYACCESS which i will tell you about this in the my next post..(I hope soon).
*Remember to remove the Trace, I use my own function to do trace in order let you know the Result and also you might not need it
And I hope this is helpful for you guys!
Thank you.
I was trying to find info about how to run a plugin on sharing Account, found your article. Very helpful!
ReplyDeleteNice article. Hey Ali
Deletehi my self Sohail
ReplyDeleteyour artical help me more and more but one problem is that when I'm trying to RewokeAccess by mean i want Rewoke and also that Account related Contacts according account user/team then how can I update Contact entity Team/User???
private void Post_Message_GrantOrRevokeAccess(IServiceProvider serviceProvider, IOrganizationService service, IPluginExecutionContext context, ITracingService tracingService)
ReplyDelete{
if (context.MessageName == "GrantAccess")
{
//this GrantAccess is for sharing
//for Unshare, messagename = "RevokeAccess" and will do the same passing parameters
EntityReference EntityRef = (EntityReference)context.InputParameters["Target"];
EntityCollection contactEntityCollection = GetQuery(EntityRef.Id, service);
//Obtain the principal access object from the input parameter
PrincipalAccess PrincipalAccess = (PrincipalAccess)context.InputParameters["PrincipalAccess"];
var userOrTeam = PrincipalAccess.Principal;
var userOrTeamId = userOrTeam.Id;
var userOrTeamName = userOrTeam.Name;
//this userOrTeam.Name will be blank since entityReference only will give you ID
var userOrTeamLogicalName = userOrTeam.LogicalName;
foreach (var contcts in contactEntityCollection.Entities)
{
Guid contactEntityId = (Guid)contcts["contactid"];
//use the logical Name to know whether this is User or Team!
if (userOrTeamLogicalName == "team")
{
var CreatedReference = new EntityReference("team", userOrTeam.Id);
var grantAccessRequest = new GrantAccessRequest
{
PrincipalAccess = new PrincipalAccess
{
AccessMask = AccessRights.ReadAccess | AccessRights.WriteAccess,
Principal = CreatedReference
},
Target = new EntityReference("contact", contactEntityId)
};
service.Execute(grantAccessRequest);
tracingService.Trace("get Team from account contex and share with contact");
}
if (userOrTeamLogicalName == "systemuser")
{
//what you are going to do if shared to User?
var CreatedReference = new EntityReference("systemuser", userOrTeam.Id);
var grantAccessRequest = new GrantAccessRequest
{
PrincipalAccess = new PrincipalAccess
{
AccessMask = AccessRights.ReadAccess | AccessRights.WriteAccess,
Principal = CreatedReference
},
Target = new EntityReference("contact", contactEntityId)
};
service.Execute(grantAccessRequest);
tracingService.Trace("get user from account contex and share with contact");
}
}
}
}
private EntityCollection GetQuery(Guid entityId, IOrganizationService service)
{
QueryExpression query = new QueryExpression("contact");
query.ColumnSet = new ColumnSet("contactid");
query.Criteria.AddCondition("parentcustomerid", ConditionOperator.Equal, entityId);
EntityCollection contactCollection = service.RetrieveMultiple(query);
return contactCollection;
}