Friday, April 29, 2016

How to retrieve data in web api in crm 2016

function Retrievedata()
{
var GUIDvalue = Xrm.Page.data.entity.getId();
alert(GUIDvalue);
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.0/accounts("+GUIDvalue.slice(1, -1)+")?$select=accountnumber", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("Prefer", "odata.include-annotations=\"OData.Community.Display.V1.FormattedValue\"");
req.onreadystatechange = function () {
    if (this.readyState === 4) {
        req.onreadystatechange = null;
        if (this.status === 200) {
            var result = JSON.parse(this.response);
            var accountnumber = result["accountnumber"];
alert(accountnumber);
        }
        else {
            alert(this.statusText);
        }
    }
};
req.send();
}



Plugins in CRM 2013

Passing configuration data using Plug-in registration tool (Secured vs. Unsecured)



  • CRM plugin registration tool contain “Unsecure & Secure” configuration sections while registering a “Step”
  • We can pass configuration data and can be used in the plug-in logic.
Plug-in registration - Secured and Unsecured sections
Plug-in registration – Secured and Unsecured sections
Secured vs. Unsecured
Below are key differentiations between Secured and Unsecured data configuration
  • Access
    • Data passed through “Unsecure” section is PUBLIC (i.e., It can be read by any user in CRM).
    • Only users with “System Administrator” role have access to the data passed through “Secure” configuration section
  • Storage
    • “Unsecure” config data will be stored along with the Plugin ‘Step’ registration information (i.e., In SdkMessageProcessingStep entity)
    • “Secure” config data will be stored in a separate entity named “SdkMessageProcessingStepSecureConfig
      • Only “System Administrator” has Read access on this entity, hence only users with ‘Sys Admin’ role can access this data
    • Both “Secured & Unsecured” configuration data stored as “Plain text” in DB
  • Outlook Sync
    • “Unsecured” configuration data is downloaded to the user’s computer when they go offline making it Unsecure
    • “Secured” configuration data is NOT downloaded to User’s Computer when they go Offline
How to read Configuration data in Plug-in
In our plug-in class, we can define a constructor that passes two parameters (i.e., unsecure configuration and secure configuration)
public class AccountCreateHandler: IPlugin{
public AccountCreateHandler(string unsecure, string secure){
// Do something with the parameter strings.
}
public void Execute(IPluginExecutionContext context){
// Do something here.
}
}
Note :- If you want to read “Secure” configuration in the plug-in code, either change the user context in plugin registration as “CRM administrator ” or Impersonate to “CRM Administrator” role user in the code
:)

Plug-ins in CRM 2011 – Useful points

Plug-in stages
  • Pre validation
    • Registered Plug-in run before the form is validated
    • Useful if you want to implement business logic before the actual validation starts.  i.e., Changes made in plug-in won’t be saved if the validation of the main system plugins complain because the changes are outside the database transaction.
    • Ex – Some “delete” plug-ins. Deletion cascades happen prior to pre-operation, therefore if you need any information about the child records, the delete plugin must be pre-validation.
  • Pre -operation
    • After validation and before the values are saved to the database
  • Post operation
    • Plugin will run after the values have been inserted/changed on the database
Database Transactions in Plug-Ins
  • Plug-ins may or may not execute within the database transaction
  • You can check if the plug-in is executing in-transaction by reading the ‘IsInTransaction‘ property of IPluginExecutionContext
  • Stages 20 and 40 are part of the database transaction while stage 10 and 50 may be part of the transaction
  • If plugin throws an exception, every action done during the transaction will be rollback
Few more Points
  • Whether a plug-in executes synchronously or asynchronously, there is a 2 minute time limit imposed on the execution of a (message) request.
  • If the execution of your plug-in logic exceeds the time limit, a Timeout exception is thrown
  • If a plug-in needs more processing time than the 2 minute time limit, consider using a workflow or other background process
  • ‘Pre-operation’ operations that CRM will do will not be carried out in pre-validation stage.
    • If you are deleting a record that has many-to-many relationship records with another entity; these relationship records will still be available in pre-validation stage, but not in pre-operation stage.
  • “Target” entity (i.e., pluginContext.InputParameters[“Target”])
    • It’s the entity on which plug-in registered
    • It only contains “dirty” attributes. if you convert to early bound, the value of the unchanged attribute will be null
Useful MSDN article :)

Fetching user security roles using Linq in CRM 2011 Plug-in’s

January 17, 20125 comments
Hi,
Below is the sample code to fetch the User’s security roles based on the “User Id” in the Plug-in’s using Linq
        /// <summary>
/// Returns the list of User security role names
/// </summary>
private List<string> GetUserRoles(IOrganizationService service, Guid userId) {
// Create Query Expression to fetch Role Entity
var query = new QueryExpression
{
// Setting the link entity condition and filter condition criteria/
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 =
{
userId
}
}
}
}
}
},
ColumnSet = new ColumnSet(true),
EntityName = “role”
};
// Obtain results from the query expression.
var userRoles = service.RetrieveMultiple(query);
// Get the usre role names collection
var roleNames = new List<string>();
if (userRoles != null)   {
roleNames.AddRange(
from entrole in userRoles.Entities
select entrole as Role
into role
where role != null && role.RoleId != null
select role.Name);
}
return roleNames;
}
How do I call this method :-
  • In your plug-in, pass the service and User Id as parameters to this method
public void Execute(IServiceProvider serviceProvider) {
context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = serviceFactory.CreateOrganizationService(context.UserId);
// Get the current users Security Roles Name’s
Var roleNames = GetUserRoles(service, this.context.UserId);
}
Hope it helps:)

Sending an Email using CRM 2011 Plug In

Hi,
In one of my recent requirements, I had to send an Email using Plug-in (Late Binding). Below is the code snippet.
private void SendEmail(IOrganizationService service, Guid recieverUserId, Guid senderUserId, Guid regardingObjectId, string emailBody, string emailSubject)
{
Entity email = new Entity();
email.LogicalName = “email”;
//Set regarding object property (i.e. The entity record, which u want this email associated with)
EntityReference regardingObject = new EntityReference(“{entity_name}”, regardingObjectId);
email.Attributes.Add(“regardingobjectid”,regardingObject);
//Defining Activity Parties (starts)
EntityReference from = new EntityReference(“systemuser”, senderUserId);
EntityReference to = new EntityReference(“systemuser”,recieverUserId);
//Derive from party
Entity fromParty = new Entity(“activityparty”);
fromParty.Attributes.Add(“partyid”,from);
//Derive to party
Entity toParty = new Entity(“activityparty”);
toParty.Attributes.Add(“partyid”, to);
EntityCollection collFromParty = new EntityCollection();
collFromParty.EntityName = “systemuser”;
collFromParty.Entities.Add(fromParty);
EntityCollection collToParty = new EntityCollection();
collToParty.EntityName = “systemuser”;
collToParty.Entities.Add(toParty);
email.Attributes.Add(“from”,collFromParty);
email.Attributes.Add(“to”, collToParty);
//Defining Activity Parties (ends)
//Set subject & body properties
email.Attributes.Add(“subject”,emailSubject);
email.Attributes.Add(“description”, emailBody);
//Create email activity
Guid emailID = service.Create(email);
//Sending email
SendEmailRequest reqSendEmail = new SendEmailRequest();
reqSendEmail.EmailId = emailID;//ID of created mail
reqSendEmail.TrackingToken = “”;
reqSendEmail.IssueSend = true;
SendEmailResponse res = (SendEmailResponse)service.Execute(reqSendEmail);
}

How to update parent and child account header using execute multiple in plugin

  Recently  i had requirement where i had to update  header fields of parent and child account. The header field values  in the parent and  child account should have same values .


If we have Asia HQ as a parent account which has two child accounts China and India . Then header field in  child and parent should be sum of all the child account values.




Here sum of  all local potential Annual  child account field should  be updated in  HQ Top line Potential  field in the header .  Local Existing Business ->  HQ Existing business and Local Active Opportunity to  HQ Active opportunity.


I have written a plugin that uses execute multiple as described below.




You cannot use execute multiple to update all related accounts in one plugin. Another plugin will update the current record. Below is the plugin to update  related records .








using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel;

// Microsoft Dynamics CRM namespace(s)
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Collections;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;

namespace ACES_OTHER_BRAND_UPDATE_HEADER
{
    public class UPDATEOTHERBRANDHEADER : IPlugin
    {

        EntityCollection update = new EntityCollection()
        {
            EntityName = "account"
        };

        ExecuteMultipleRequest requestWithResults;

        /// <summary>
        /// A plug-in that creates a follow-up task activity when a new account is created.
        /// </summary>
        /// <remarks>Register this plug-in on the  update message, account entity,
        /// and asynchronous mode.
        /// </remarks>
        public void Execute(IServiceProvider serviceProvider)
        {
            //Extract the tracing service for use in debugging sandboxed plug-ins.
            ITracingService tracingService =
                (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            //<snippetFollowupPlugin1>
            // Obtain the execution context from the service provider.
            IPluginExecutionContext context = (IPluginExecutionContext)
                serviceProvider.GetService(typeof(IPluginExecutionContext));
            //</snippetFollowupPlugin1>

            //<snippetFollowupPlugin2>
            // The InputParameters collection contains all the data passed in the message request.
            if (context.InputParameters.Contains("Target") &&
                context.InputParameters["Target"] is Entity)
            {
                // Obtain the target entity from the input parameters.
                Entity entity = (Entity)context.InputParameters["Target"];


                //</snippetFollowupPlugin2>
                Guid primaryEntityId = context.PrimaryEntityId;
                // Verify that the target entity represents an account.
                // If not, this plug-in was not registered correctly.
                if (entity.LogicalName != "account")
                    return;

                try
                {


                    //  Entity postentityimage = (Entity)context.PostEntityImages["Image"];
                    Entity postentityimage = (Entity)context.PostEntityImages["Image"];

                    EntityReference parentId = null;
                    if (postentityimage.Attributes.Contains("parentaccountid") && postentityimage.GetAttributeValue<EntityReference>("parentaccountid")!=null)
                    {
                        parentId = postentityimage.GetAttributeValue<EntityReference>("parentaccountid");

                    }

                    // if (preImageEntity.GetAttributeValue<Money>("hpcrm_Value") != postImageEntity.GetAttributeValue<Money>("hpcrm_value"))

                    //<snippetFollowupPlugin4>
                    // Obtain the organization service reference.
                    IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
                    //</snippetFollowupPlugin4>
                   // if (context.Depth > 1) { return; }

                    // Create the task in Microsoft Dynamics CRM.
                    tracingService.Trace("FollowupPlugin: Creating the task activity.");

                    EntityCollection accountCollection = null;



                    if (parentId != null)
                    {

                        accountCollection = RetrieveChildAccount(tracingService, parentId.Id, service);






                        decimal localmarketactiveopportunitypotential = 0;
                        decimal localmarketexistingbusiness = 0;
                        decimal localmarketpotential = 0;
                        decimal sumlocalmarketactiveopportunitypotential = 0;
                        decimal sumlocalmarketpotential = 0;
                        decimal sumlocalmarketexistingbusiness = 0;
                        Guid accountid = Guid.Empty;
                        // string straccountid = string.Empty;
                        // ArrayList list = new ArrayList();
                        foreach (var childaccount in accountCollection.Entities)
                        {

                            // accountid = childaccount.GetAttributeValue<Guid>("accountid");

                            //straccountid = accountid.ToString();
                            // list.Add(straccountid);

                            if (childaccount.Attributes.Contains("aces_marketpotential"))
                            {
                                localmarketpotential = Convert.ToDecimal(childaccount.GetAttributeValue<Money>("aces_marketpotential").Value);
                                sumlocalmarketpotential = sumlocalmarketpotential + localmarketpotential;


                                //entity.Attributes.Add("hpcrm_aum", new Money(AumPercentile));
                            }

                            if (childaccount.Attributes.Contains("aces_localmarketactiveopportunitypotential"))
                            {
                                localmarketactiveopportunitypotential = Convert.ToDecimal(childaccount.GetAttributeValue<Money>("aces_localmarketactiveopportunitypotential").Value); ;
                                // entity.Attributes.Add("hpcrm_revenue", new Money(Revenue));
                                sumlocalmarketactiveopportunitypotential = sumlocalmarketactiveopportunitypotential + localmarketactiveopportunitypotential;
                            }


                            if (childaccount.Attributes.Contains("aces_annualfeeincomeassumption"))
                            {
                                localmarketexistingbusiness = Convert.ToDecimal(childaccount.GetAttributeValue<Money>("aces_annualfeeincomeassumption").Value); ;
                                // entity.Attributes.Add("hpcrm_revenue", new Money(Revenue));

                                sumlocalmarketexistingbusiness = sumlocalmarketexistingbusiness + localmarketexistingbusiness;
                            }




                        }



                        // Entity accountentity = new Entity("account");
                        foreach (var childaccount in accountCollection.Entities)
                        {


                            accountid = childaccount.GetAttributeValue<Guid>("accountid");
                            if (accountid != primaryEntityId)
                            {
                                Entity accountentity = new Entity("account");
                                accountentity["accountid"] = accountid;

                                accountentity["aces_hqactiveopportunitiesusdinmillions"] = new Money(sumlocalmarketactiveopportunitypotential);
                                accountentity["aces_hqpotentialannual"] = new Money(sumlocalmarketpotential);
                                accountentity["aces_hqexisitingbusss"] = new Money(sumlocalmarketexistingbusiness);
                                update.Entities.Add(accountentity);
                            }


                        }


                        if (parentId != null)
                        {

                            Entity accountentity = new Entity("account");
                            accountentity["accountid"] = parentId.Id;
                            accountentity["aces_hqactiveopportunitiesusdinmillions"] = new Money(sumlocalmarketactiveopportunitypotential);
                            accountentity["aces_hqpotentialannual"] = new Money(sumlocalmarketpotential);
                            accountentity["aces_hqexisitingbusss"] = new Money(sumlocalmarketexistingbusiness);
                            update.Entities.Add(accountentity);

                        }



                   


                        // Create an ExecuteMultipleRequest object.
                        requestWithResults = new ExecuteMultipleRequest()
                        {
                            // and to not return responses.
                            Settings = new ExecuteMultipleSettings()
                            {
                                ContinueOnError = false,
                                ReturnResponses = false
                            },
                            Requests = new OrganizationRequestCollection()
                        };

                        // EntityCollection update = GetCollectionOfEntitiesToUpdate();

                        foreach (var entitytoUpdate in update.Entities)
                        {
                            UpdateRequest updateRequest = new UpdateRequest { Target = entitytoUpdate };
                            requestWithResults.Requests.Add(updateRequest);
                        }




                        // Execute all the requests in the request collection using a single web method call.
                        ExecuteMultipleResponse responseWithResults =
                            (ExecuteMultipleResponse)service.Execute(requestWithResults);



                        // Display the results returned in the responses.
                        foreach (var responseItem in responseWithResults.Responses)
                        {
                            // A valid response.
                            if (responseItem.Response != null)
                                DisplayResponse(requestWithResults.Requests[responseItem.RequestIndex], responseItem.Response);

                            // An error has occurred.
                            else if (responseItem.Fault != null)
                                DisplayFault(requestWithResults.Requests[responseItem.RequestIndex],
                                    responseItem.RequestIndex, responseItem.Fault);
                        }




                    }

                 




                }
                //<snippetFollowupPlugin3>
                catch (FaultException<OrganizationServiceFault> ex)
                {
                    throw new InvalidPluginExecutionException("An error occurred in the FollupupPlugin plug-in.", ex);
                }
                //</snippetFollowupPlugin3>

                catch (Exception ex)
                {
                    tracingService.Trace("FollowupPlugin: {0}", ex.ToString());
                    throw;
                }
            }
        }


        public EntityCollection RetrieveChildAccount(ITracingService trace, Guid parentAccountId, IOrganizationService service)
        {

            try
            {

                trace.Trace("to retrieve RetrieveAllRelatedHouseHold");
                QueryExpression queryExp = new QueryExpression();
                queryExp.EntityName = "account";
                queryExp.ColumnSet = new ColumnSet();
                queryExp.ColumnSet.AddColumns("accountid", "parentaccountid", "aces_localmarketactiveopportunitypotential" , "aces_annualfeeincomeassumption", "aces_marketpotential" );

                ConditionExpression condition1 = new ConditionExpression();
                condition1.AttributeName = "parentaccountid";
                condition1.Operator = ConditionOperator.Equal;
                condition1.Values.Add(parentAccountId);//condition to retrieve cases associated with Master Case



                FilterExpression filterExpression = new FilterExpression();
                filterExpression.AddCondition(condition1);

                filterExpression.FilterOperator = LogicalOperator.And;
                queryExp.Criteria = filterExpression;
                var accountCollection = service.RetrieveMultiple(queryExp);
                trace.Trace("Associated RetrieveAllRelatedHouseHold retrieved");
                return accountCollection;


            }




            catch (FaultException<OrganizationServiceFault> exception)
            {
                trace.Trace("Exception: {0}", exception.ToString());

                throw new FaultException("RetrieveAllClient");
            }


        }



        /// <summary>
        /// Display the response of an organization message request.
        /// </summary>
        /// <param name="organizationRequest">The organization message request.</param>
        /// <param name="organizationResponse">The organization message response.</param>
        private void DisplayResponse(OrganizationRequest organizationRequest, OrganizationResponse organizationResponse)
        {
            //Console.WriteLine("Created " + ((Account)organizationRequest.Parameters["Target"]).Name
            //    + " with account id as " + organizationResponse.Results["id"].ToString());
            //_newAccountIds.Add(new Guid(organizationResponse.Results["id"].ToString()));
        }

        /// <summary>
        /// Display the fault that resulted from processing an organization message request.
        /// </summary>
        /// <param name="organizationRequest">The organization message request.</param>
        /// <param name="count">nth request number from ExecuteMultiple request</param>
        /// <param name="organizationServiceFault">A WCF fault.</param>
        private void DisplayFault(OrganizationRequest organizationRequest, int count,
            OrganizationServiceFault organizationServiceFault)
        {
            //Console.WriteLine("A fault occurred when processing {1} request, at index {0} in the request collection with a fault message: {2}", count + 1,
            //    organizationRequest.RequestName,
            //    organizationServiceFault.Message);
        }










    }
}




















Dealing with record level access restriction with Dynamics CRM using Access team

Dealing with record level access restriction with Dynamics CRM

(Reference - https://salimadamoncrm.com/page/2/)
CRM works extremely well with giving users access to records based on a different set of security configuration tools : cumulative security roles with a “most permissive win” mechanism, business units, team memberships, access teams, hierarchy and so on. One thing it does not do well is restricting access to specific record. Imagine the following scenario:
  • Company ABC uses Microsoft Dynamics CRM to manage its cases
  • An employee leaves company XYZ to join ABC
  • After joining ABC, the new employee is given access to Dynamics CRM and has access to ongoing and past cases, say in his/her region
  • Company ABC has open cases against firm XYZ. The employee should not be able to see those cases because it represents a conflict of interest (e.g. he/she might give insights to his/her old friends at XYZ)
The following image provides an illustration of what we are trying to accomplish.
image
If you have worked with Dynamics CRM and know its security model, you can already read between the lines here. There are no easy ways to make this happen. This article provides a possible solution for this requirement based on a recent experience on a large CRM implementation.
Ruling out Team Membership & Ownership
In our scenario, members of a team or a business unit get access to all records  owned by their team or business unit. If we follow basic team/BU record ownership, the problem in this case is that once a record needs to be isolated from one individual member of the team, one of two things needs to happen:
  1. The record owner has to be changed (it can no longer be the team everyone is a member of) and the record needs to be shared with users who can still see it, but not with the individual that is getting the restriction applied OR
  2. The individual who is getting a restriction applied has to be removed from the team and all the records owned by his/her team need to be shared with him/her except the one he/she is restricted to see.  This technique implies heavy maintenance since the user will need to access new cases created for the team he/she used to be a member of.
Sharing in both cases can be done via the record share functionality, access team or any other mechanism that suits the business need. It should also be automated if there is a large number of records to share. You also need to save the information about the user and its restriction on a separate entity to be able to backtrack and understand why the records/ownership and so on have been modified.
Why we didn’t like the “Sharing” functionality
Using the out of the box sharing of record can cause problems in the long run. The PrincipalObjectAccess (POA) table gets bigger and bigger, causes performance issues and has to be cleaned up on a regular basis. In addition to that, the more access is controlled by sharing, the more you run the risk of having performance issues because of the complexity overhead in system lookups when it needs to display a record or list of records to users.
A solution using “Access Teams”
We decided to go with a design centered around Access Teams. The “Case” entity gets an “Access Team Template.” When a user is created and added to his/her group (team or business unit), we start a process to insert the user in the Access Team of each case related to his/her business unit. In order to restrict access to a specific case for a user, we can simply remove the user from the case’s Access Team.  For tracking purposes, we created a “Security Exception” entity that is created and has a relationship with a case and a user and an additional attribute that indicate the type and reason for the “Restriction”. To apply the access restriction on a case for a user (i.e. remove user from access team), we create a Security Exception record. We link the target case and user, and specify the restriction type. After the Security Exception record is created, a plugin is fired to perform validation and to remove the user from the case’s access team.
One of the reasons with went with that model was that we didn’t want to have a base security model that gets “broken” every time there a single person with restricted access, by changing record ownership or removing user from the team he/she is supposed to be a member of. With access teams, the record ownership remains the same, and users also remain on their team at all times which makes everybody happy and maintenance easier. The downside is that when a user is created, we have to look for all the cases in his/her business unit and manually (with code) add the user to each access team. Same when a case is created, users member of the case’s business unit have to be added to the case’s access team manually (also with code). That is the comprise we had to make.
As far as performance goes, the end results remain to be seen in the long run. Our system will have between 2000 and 3000 users when we complete our rollout. It will deal with over 1 million cases across multiple teams. Preliminary performance tests results look promising. I will repost if we get into any issue as it relates to performance.