Friday, February 12, 2010

Use CRM Assign Message in Plug-in Code

Assign message is not very often-used in MSCRM development, the information about the message is scattered here and there in the online community with no complete sample, so I am trying to give a simple example which demonstrates how to use it in your plug-in code to ensure a CRM record will only be assigned to users with a particular CRM role.

The following plug-in code is based on the requirement that the records of myapp_myentity CRM entity can only be used to be assigned to the users who have "Schedule Manager" role.
using System;
using System.Xml;
using Microsoft.Crm.Sdk;

namespace MyEntity
{
    /// <summary>
    /// CRM Plugin to demonstrate how to use Assign message.
    ///
    /// The Plugin should be registered as :
    ///
    /// Primary Entity: myapp_myentity
    /// Message:        Assign
    /// Stage:          Pre Stage
    /// Mode:           Synchronous
    /// </summary>
    public class PreAssign : IPlugin
    {
        const string entityName = "myapp_myentity";
        const string allowedCrmRole = "Schedule Manager";

        public void Execute(IPluginExecutionContext context)
        {
            // Verify the message context
            if (context.InputParameters.Properties.Contains("Target") ||
                context.InputParameters.Properties["Target"] is Moniker == false ||
                context.PrimaryEntityName != entityName)
            {
                return;
            }

            // Retrieve the new assignee from plug-in context
            SecurityPrincipal assignee = (SecurityPrincipal) context.InputParameters.Properties["Assignee"];

            // Ensure the new assignee has the specified role
            using (ICrmService crmService = context.CreateCrmService(true))
            {
                EnsureNewAssigneeIsInRole(crmService, assignee, allowedCrmRole);
            }
        }

        private void EnsureNewAssigneeIsInRole(ICrmService crmService, SecurityPrincipal assignee, string role)
        {
            // Query to check if the user is in the role.
            string fetchXml = string.Format(@"
<fetch mapping='logical' aggregate='true'>
   <entity name='systemuser'>
      <attribute name='systemuserid' aggregate='count' alias='count' />
      <filter>
         <condition attribute='systemuserid' operator='eq' value='{0}' />
      </filter>
      <link-entity name='systemuserroles' from='systemuserid' to='systemuserid' link-type='inner'>
         <link-entity name='role' from='roleid' to='roleid' link-type='inner'>
            <filter>
               <condition attribute='name' operator='eq' value='{1}' />
            </filter>
         </link-entity>
      </link-entity>
   </entity>
</fetch>
", assignee.PrincipalId, role);

            string fetchResult = crmService.Fetch(fetchXml);

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(fetchResult);

            XmlNode xn = xmlDoc.SelectSingleNode("//resultset/result/count");
            if (Convert.ToDecimal(xn.InnerText) == 0)
            {
                string exceptionMsg = string.Format("The CRM record can only be assiged to a user with \"{0}\" role. ", role);
                throw new InvalidPluginExecutionException(exceptionMsg);
            }
        }
    }
}
The key to work with Assign message is to retrieve the Assignee secruity principal from the plug-in execution context object by using Assignee property of the input parameters, as shown below:
SecurityPrincipal assignee = (SecurityPrincipal) context.InputParameters.Properties["Assignee"];
An additional note, if you need to get the record's ID, you can use the following code:
Moniker moniker = (Moniker)context.InputParameters.Properties["Target"];
Guid id = moniker.Id;
As you can tell from the code, the plug-in has to be registered with the target entity's Assign message of Pre Stage using Synchronous execution mode.

Hope this helps.

1 comment:

  1. Hi,

    I have the same code,

    just i'm trying to update custom entity,here is my code

    thank you for any help:


    //Create an instance of TargetOwnedDynamic class.
    TargetOwnedDynamic target = new TargetOwnedDynamic();


    //Create an instance of SecurityPrincipal class also to specify the SecurityPrincipalType (user type user/team)
    //and to pass the Owner(user) Guid.

    SecurityPrincipal assignee = new SecurityPrincipal();

    assignee.Type = SecurityPrincipalType.User;
    assignee.PrincipalId = GetcurrentUser(service);

    // pass the account Guid to EntityId and the Entity name.
    Guid oitraffick = ((Key)oi.Properties["datasurf_oi_traffickid"]).Value;
    //Guid idTraffick = getEntity.GetGuid(oi, service, metaservice);

    target.EntityId = oitraffick;
    target.EntityName = "datasurf_oi_traffick";

    //Create an instance of AssignRequest class and pass the TargetOwnedDynamic and SecurityPrincipal objects to it.

    AssignRequest req = new AssignRequest();

    req.Assignee = assignee;
    req.Target = target;

    //Execute the AssignRequest object.
    AssignResponse res = (AssignResponse)service.Execute(req);

    ReplyDelete