I have a Microsoft CRM 2016 plugin that checks if the user that triggers an update message has at least one of the required roles, when the updated record is owned by a specific user.
Here's the code:
public class CheckIfOwnedByPool : BasePlugin
{
public CheckIfOwnedByPool(string unsecure, string secure)
: base(unsecure, secure)
{
}
public override void ExecutePluginLogic(XrmObjects xrmObjects)
{
if (xrmObjects.PluginContext.MessageName.ToLower() == "update" && xrmObjects.PluginContext.PreEntityImages.Contains("entity"))
{
Guid PoolId = Guid.Empty;
List<Guid> allowedRoles = new List<Guid>();
var entity = xrmObjects.PluginContext.PreEntityImages["entity"];
//retrieve id of "POOL" team and allowed roles GUIDs from plugin step XML config. GUID varies from environment to environment...
try
{
PoolId = new Guid(GetAllNodes("ownerconfig")[0].Attributes["value"].InnerText);
GetAllNodes("roles")[0].Attributes["value"].InnerText.Split(';').ToList().ForEach(x => allowedRoles.Add(new Guid(x)));
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(string.Format("Error deserializing plugin step XML config: {0}", ex.Message));
}
if (PoolId == Guid.Empty || allowedRoles.Count == 0)
return;
//if entity is owned by team called "POOL"
if (((EntityReference)entity["ownerid"]).Id == PoolId)
{
using (XrmServiceContext ctx = new XrmServiceContext(xrmObjects.Service))
{
//retrieve current user roles
var userRoles = ctx.SystemUserRolesSet.Where(x => x.SystemUserId == xrmObjects.PluginContext.InitiatingUserId).ToList();
//check if current user has one of required roles
if (!userRoles.Any(x => allowedRoles.Any(y => y == x.RoleId.Value)))
throw new InvalidPluginExecutionException("You do not have access to modify this record. Please see with your supervisor");
}
}
}
}
}
This seems to work fine and is registered in pre-operation of Update
of any entity. As observed, if one plugin in pre-operation throws an exception, all the plugin stack is stopped, meaning all other pre/post operation plugins won't execute, which is what I want.
Do you see anything that can go wrong? The only issue is that every update done on an entity owned by "POOL", there will be a retrieve to get the user's role. This could hurt performance, but by how much ?
BasePlugin
is an abstract class implementing IPlugin
and xrmObjects
holds useful members such as the tracing service, the plugin exec. context, etc. GetAllNodes
is a member of BasePlugin
which allows for easy access of the XML plugin step config.