We had a recent requirement where we needed to assign a specific role to a user on user create using a plugin. The below is the complete source code of the plugin that had been written.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
namespace AssignDefaultRole
{
public class AssignRoleCS : IPlugin
{
Guid systemUserGuid = Guid.Empty;
EntityReference buLookup;
Guid buid = Guid.Empty;
EntityCollection userRolesColl = null;
Entity entitySystemUser;
string securityRole = string.Empty;
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity primaryEntity = (Entity)context.InputParameters["Target"]; // systemuser
if (primaryEntity.LogicalName != "systemuser" && context.MessageName.ToLower()!="update")
{
return;
}
else if (context.PostEntityImages.Contains("PostUserImage") && context.PostEntityImages["PostUserImage"] is Entity)
{
entitySystemUser = (Entity)context.PostEntityImages["PostUserImage"];
buLookup = (EntityReference)entitySystemUser.Attributes["businessunitid"];
buid = buLookup.Id;
systemUserGuid = new Guid(entitySystemUser.Attributes["systemuserid"].ToString());
//Check if the user already has the Default Role
bool userHasRole = CheckRoleExists(service);
if (!userHasRole)//user does not have the Default role
{
//Get the Default Role
Guid DefaultSecurityRoleId = GetSecurityRoleId(service, buid, securityRole);
//Assign the role to the user.
AssignSecurityRole(systemUserGuid, DefaultSecurityRoleId, service);
}
}
}
}
///
/// Check if the user already has the default role assigned.
///
private bool CheckRoleExists(IOrganizationService service)
{
try
{
//UserGuid = context.InitiatingUserId;
securityRole = "Default Privileges Role";
QueryExpression Query = new QueryExpression()
{
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 = { systemUserGuid }
}
}
}
}
}
};
Query.ColumnSet = new ColumnSet(true);
Query.EntityName = "role";
userRolesColl = service.RetrieveMultiple(Query);
//If the role exists, return true
if (userRolesColl.Entities.Count > 0 && userRolesColl.Entities[0].Attributes["name"].ToString() == securityRole)
{
return true;
}
return false;
}
catch (System.Web.Services.Protocols.SoapException ex)
{
throw new InvalidPluginExecutionException(ex.Detail.InnerText);
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message);
}
}
///
/// Get the Role ID of the Default CRM 2011 role
///
private Guid GetSecurityRoleId(IOrganizationService service,Guid businessUnitID,string roleName)
{
Guid SecurityRoleId = Guid.Empty;
EntityCollection ec = new EntityCollection();
try
{
QueryExpression qe = new QueryExpression("role");
ColumnSet set = new ColumnSet(new string[] { "roleid" });
qe.ColumnSet = set;
ConditionExpression cond = new ConditionExpression("name", ConditionOperator.Equal, roleName);
ConditionExpression cond2 = new ConditionExpression("businessunitid", ConditionOperator.Equal, businessUnitID);
FilterExpression fl = new FilterExpression(LogicalOperator.And);
fl.Conditions.Add(cond);
fl.Conditions.Add(cond2);
qe.Criteria.AddFilter(fl);
ec = service.RetrieveMultiple(qe);
if (ec.Entities.Count > 0)
{
SecurityRoleId = new Guid(ec.Entities[0].Attributes["roleid"].ToString());
}
}
catch (System.Web.Services.Protocols.SoapException soapex)
{
throw new InvalidPluginExecutionException(soapex.Detail.InnerText);
}
catch (Exception ex)
{
throw ex;
}
return SecurityRoleId;
}
///
/// Assign the Default CRM 2011 Role to the user
///
public void AssignSecurityRole(Guid userID, Guid securityRoleID, IOrganizationService service)
{
try
{
service.Associate(
"role",
securityRoleID,
new Relationship("systemuserroles_association"),
new EntityReferenceCollection() { new EntityReference("systemuser", userID) });
}
catch (System.Web.Services.Protocols.SoapException soapex)
{
throw new InvalidPluginExecutionException(soapex.Detail.InnerText);
}
catch (Exception ex)
{
throw ex;
}
}
}
}
The above code first checks if the user has any role assigned. If not, it goes ahead and assigns the Default Security Role to the user.
After building the plugin, I had it registered in the following manner:
Notice that for both "Create" and "Update" events, I have registered just the one step displayed above
I am not exactly sure why, but I noticed that even if I register my plugin for the Create event, the plugin also automatically fires another update event. So, I have just registered my plugin for the update event and this works for both the create and the update.
Another issue I was facing was when I tried to register this plugin in a synchronous manner. I would keep getting the error message "
Error: usersettings With Id = 92bd1403-6ace-e211-a1c4-0800279f0ce3 Does Not Exist" in the trace logs.
In order to rid myself of the error and in order to ensure that the plugin only fires once per transaction, I have registered it ONLY for the "Update" message and in "Asynchronous" execution mode.
Cheers!