Friday, June 7, 2013

CRM 2011 - Auto assign a role to user when a New User is created/Updated

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!

Wednesday, March 27, 2013

CRM 2011 - Instantiating the CRM Service and Impersonating it

 The below code can be used to create the CRM service in CRM 2011 and also to impersonate the CRM service

public static IOrganizationService Service() 
{
    ClientCredentials Credentials = new ClientCredentials(); 
    Credentials.Windows.ClientCredential.UserName ="Impersonating User ID Name"; 
    Credentials.Windows.ClientCredential.Password ="Impersonating User ID password"; 

    //Update the below URL as per your environment
    Uri OrganizationUri = new Uri("http://serverName/OrganizationName/XRMServices/2011/Organization.svc"); 
    Uri HomeRealmUri = null; 

    //Get the CRM Service from the CRM Service Proxy
    using (OrganizationServiceProxy serviceProxy = new OrganizationServiceProxy(OrganizationUri, HomeRealmUri, Credentials, null)) 
    {
        IOrganizationService service = (IOrganizationService)serviceProxy; 
        return service; 
    }
}

Friday, November 18, 2011

Learning ODATA Queries

Hi,
The below link is one of the best blogs I have come across for learning ODATA queries

http://crmscape.blogspot.com/2011/03/crm-2011-odata-json-and-crm-forms.html

Please check it out.

Thursday, October 6, 2011

Publishers and Changing a Custom Entity Prefix in MS CRM 2011

I think this is a great new feature in CRM 2011. Please refer to the following article that describes how to do this:
http://support.microsoft.com/kb/2500602

Tuesday, October 4, 2011

Changing the Font Color of a Read-Only Field in MS CRM 2011

I recently got a request to change the font color of certain fields in CRM 2011. I used the below code to achieve this:

function setColor() {
    if (document.getElementById("new_name") != null) {
        //Add the below line if the field is disabled
        document.getElementById("new_name").disabled = false;
        //The below line changes the font color
        document.getElementById("new_name").style.color = "red";
    }
}
Note: Accessing the DOM as shown above is totally unsupported. I had to use the above method since I was not able to find any supported way of achieving this functionality

Thursday, September 1, 2011

Enabling JScript/JavaScript in Bulk Edit CRM 2011

I recently came across a situation where I had to use Jscript while Bulk Editing the records in CRM 2011. As we all know, this is not possible out of the box but thanks to Michael Höhne (http://www.stunnware.com/crm2/topic.aspx?id=BulkEdit) and Microsoft for providing with the KB article (http://support.microsoft.com/kb/949941)

Here is what we need to do:

1. Export the entity as a solution for which JScript needs to be enabled during Bulk Edit.
2. Open the customization.xml
3. Add BehaviorInBulkEditForm="Enabled" to the event handlers as shown below
 
<
event name="onchange" application="false" active="false" attribute="new_day" BehaviorInBulkEditForm="Enabled"
>

<
event name="onsave" application="false" active="false" BehaviorInBulkEditForm="Enabled"
>

4. Save and Import the solution. Your JScript code should now be triggered!

 --Srihari

Wednesday, July 6, 2011

MS CRM 2011 - Cool New Data Import Wizard

Yesterday, while trying to import some data into my dev system, I stumbled upon a cool new feature built inside the MS CRM 2011 Import Wizard - The ability to create an "Entity" and all it's attributes right during the import.
This means that I no longer have to create an entitty and then import the data into it. I can do this in one shot. Thats an AMAZING feature considering I am doing a whole bunch of mock-ups  in order to present to the client :-)

Let us walk through the steps below:

1. I have an excel sheet with some data in the following format. Let me call this "TIMETABLE"


July
Accounts
Management A/c
5
Corporate Financial reporting
Project Planning & capital budgeting
6
Corporate Restructuring
Project Planning & capital budgeting
7
Corporate Restructuring
Project Planning & capital budgeting
8
Corporate Restructuring
Project Planning & capital budgeting
9
Corporate Restructuring
Project Planning & capital budgeting
10
Consolidated Fian Stats
Project Planning & capital budgeting
11
Consolidated Fian Stats
Project Planning & capital budgeting
12
Consolidated Fian Stats
Project Planning & capital budgeting
13
Consolidated Fian Stats
Project Planning & capital budgeting
14
Consolidated Fian Stats
Leasing decisions
15
Consolidated Fian Stats
Leasing decisions
16
Consolidated Fian Stats
Leasing decisions
17
Consolidated Fian Stats
Dividend decisions
18
Consolidated Fian Stats
Dividend decisions
19
Consolidated Fian Stats
Indian capital market
20
Consolidated Fian Stats
Indian capital market
21
Consolidated Fian Stats
Indian capital market
22
Consolidated Fian Stats
Indian capital market
23
Consolidated Fian Stats
Indian capital market
24
Consolidated Fian Stats
Security Analysis
25
Consolidated Fian Stats
Security Analysis
26
Consolidated Fian Stats
Security Analysis
27
Consolidated Fian Stats
Portfolio theory
28
Consolidated Fian Stats
Portfolio theory
29
A/c & reporting of financial instruments
Portfolio theory
30
Revision
Revision
31
Revision
Revision



Now, let's use the Data Import Wizard to create and Import the Time-Table entity into CRM 2011.

2. Open CRM 2011. Click on Tools -->Import Data
3. Click on "Browse" and choose the above excel sheet which was saved in ".csv" format.

4. Click on Next.
5. Verify that the file is uploaded and click on Next again.
6. Choose the Default Automatic Mapping and click on Next

7. Now this is where the real fun begins. Choose "Create New" in the Map Record Types Screen.


8. Specify a name for this entity. In this case I call is Time Table. Click on Next


9. As you can see below, the wizard automatically recognizes the columns from the excel sheet and is asking us to specify the field names in CRM.
10. Since there are no fields yet created, I selected "Create New Field" from the dropdown list.

11. Specify the Field Name and also choose the data type for the field and then click on OK.

12. Perform the same for all the other fields that you want and then finally, click Next.
13. Verify the "Review  Mapping Summary" and click on Next.

14. Specify if you want to allow duplicates and also choose the default owner for the Imported Records. Finally click on Submit.

15. CRM will start creating the entity and the attributes for you as shown below

16. If everything is successful, it should display the screen as shown below.

17. The import job should complete successfully and after that we just need to go to the customization and customize the form and the views as per our requirement.

18. Publish the entity and voila! - we have a new Time Table entity with all the data in it.


I am going to love this feature as creating demos for customers is going to be a lot more easier from now on.

Thanks!