Advertisements

Archive

Archive for the ‘Plug-Ins’ Category

[Dynamics CE] – Strange Plug-in issue due to the usage of global variables

December 26, 2018 Leave a comment

Other day, one of my colleagues reported a plug-in issue which could not be reproduced consistently. All the troubleshooting options (i.e., Plug-in Profiler, Tracing) had been used but was unable to found the root cause.

On close retrospection of code, we found out the usage global variables in Plug-in class file, which made the Plug-in ‘Stateful’.

Due to this, issue could not be reproduced when tested with Plug-in Profiler as it creates single Plug-in instance. Issue will only be reproduced when concurrent users instantiate plug-ins.

You have to make sure to create your Plug-in as ‘Stateless’ to avoid issues during concurrent Plug-in execution.

What is ‘Stateful’ Plug-in?

  • If the Plug-in ‘Execute’ method refer any global variable(s), makes the Plug-in ‘Stateful’.

public class CustomersVirtual : IPlugin{

// ‘context’ variable declared as Global
IPluginExecutionContext context = null;
EntityCollection results = new EntityCollection();
public void Execute(IServiceProvider serviceProvider) {
context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

if (context.MessageName.ToLower() == “retrieve”){
Entity customer = new Entity(“raj_virtualcustomer”);
customer[“raj_customersid”] = Guid.NewGuid();
customer[“raj_name”] = “ABC Corporation”;

//add it to the collection
results.Entities.Add(customer);
}

In the above Plug-in sample, variables ‘context’ and ‘results’ been defined as global and referred in ‘Execute’ method which makes it ‘Stateful’

What is ‘Stateless’ Plug-in:

  • If the Plug-in ‘Execute’ method, has its own local variables and does not refer any global variables make the Plug-in ‘Stateless’.

public class CustomersVirtual : IPlugin{
public void Execute(IServiceProvider serviceProvider){

// ‘context’ variable declared as Local variable
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));

EntityCollection results = new EntityCollection();

if (context.MessageName.ToLower() == “retrieve”)
{
Entity customer = new Entity(“raj_virtualcustomer”);
customer[“raj_customersid”] = Guid.NewGuid();
customer[“raj_name”] = “ABC Corporation”;

//add it to the collection
results.Entities.Add(customer);
}

In this sample, variables ‘context’ and ‘results’ been defined as Local in ‘Execute’ method which makes it ‘Stateless’

Why ‘Stateless’ Plug-in is recommended?

  • As per the design, Dynamics platform caches plug-in class instances and hence the constructor is not called for every invocation of plug-in execution.
  • IPlugins should be stateless is that multiple system threads could execute the same, shared, plug-in instance concurrently.
  • This opens up members of classes that implement IPlugin to potential thread-safety issues which could lead to data inconsistency or performance problems.
  • Read-only, static, and constant members are inherently thread-safe and can also be used reliably within a plug-in class.

How the Dynamics platform Caches Plug-in?

  • For performance reasons, Dynamics DOES NOT dispose of the object after it completes execution.
  • Dynamics caches the object and calls Execute on the same object instance on the next activation of the plug-in.
  • Certain operations, such as changing a plug-in’s registration properties, will trigger a notification to the platform to refresh the cache. In these scenarios, the plug-in will be reinitialized..
  • This means that you need to be very careful when defining class-level variables in the plug-in class as multiple threads can execute the code at one time

Bottom line:

  • Don’t use Global variables in Plug-ins

Refer below articles for more insights:

🙂

Advertisements
Categories: CRM, Plug-Ins Tags: , ,

The server was unable to process the request due to an internal error – plugin registration tool

June 13, 2013 1 comment

The other day my plugin registration tool suddenly stopped connecting to my CRM server and was getting below error

Unhandled Exception: System.ServiceModel.FaultException: The server was unable to process the request due to an internal error

Below steps helped me to resolve the issue

  • Go to “Plugin Registration Tool” physical folder
    • Delete existing “Microsoft.Crm.Sdk.Proxy.dll” and “Microsoft.Xrm.Sdk.dll”

    Plugin registration tool folder

    • Get back the 2 .dlls either from CRM SDK or from “C:\Program Files\Microsoft Dynamics CRM\Server\bin” path of CRM server machine
    • Paste them in “Plugin Registration Tool” folder
  • Reset the IIS
  • Open the Plugin Registration Tool and try to connect to the server

🙂

Associate/Disassociate plugin messages in CRM

April 17, 2013 11 comments

In CRM, the Associate or Disassociate event happens

  • If you have a N:N relationship between two entities and when you try to associate or disassociate records either from Associated view or Sub grid.
Entity Associate View

Entity Associate View

In Plugins, the Associate & Disassociate messages behave little different than other messages.

  • When you register a plugin on Associate message, you have to leave “Primary and Secondary” entities as ‘none’.
Associate Plugin Step

Associate Plugin Step

  • Since we don’t provide entity names, the registered Plug-in step triggers on all “Associate” operations, so we have to check few conditions to let the “Association” trigger happen only between intended entities.

You can use the below code template for Associate or Disassociate plugins

            EntityReference targetEntity = null;

            string relationshipName = string.Empty;

            EntityReferenceCollection relatedEntities = null;

            EntityReference relatedEntity = null;

            if (context.MessageName == “Associate”) {

                // Get the “Relationship” Key from context

                if (context.InputParameters.Contains(“Relationship”)) {

                    relationshipName = context.InputParameters[“Relationship”].ToString();

                }                                   

                // Check the “Relationship Name” with your intended one

                if (relationshipName != “{YOUR RELATION NAME}”) {

                    return;

                } 

                // Get Entity 1 reference from “Target” Key from context

                if (context.InputParameters.Contains(“Target”) && context.InputParameters[“Target”] is EntityReference)  {

                    targetEntity = (EntityReference)context.InputParameters[“Target”];

                }                      

                // Get Entity 2 reference from ” RelatedEntities” Key from context

                if (context.InputParameters.Contains(“RelatedEntities”) && context.InputParameters[“RelatedEntities”] is EntityReferenceCollection) {

                    relatedEntities = context.InputParameters[“RelatedEntities”] as EntityReferenceCollection;

                    relatedEntity = relatedEntities[0];

                }

            }

🙂

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

October 22, 2012 1 comment
  • 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

🙂

Add or Remove users to Team programmatically in CRM 2011

October 11, 2012 Leave a comment

In CRM,

  • Team is a group of users.
  • Each team must be associated with only one Business Unit (BU).
  • A team can include users from any business unit, not only the BU with which the team is associated.
  • Users can be associated with more than one team.  
  • You can get the members of Team from “TeamMembership” view
TeamMemberShip view

TeamMemberShip view

We can Add or Remove users from Team using below requests programmatically

  • AddMembersTeamRequest
  • RemoveMembersTeamRequest

Below is the code to add User(s) to a Team

AddMembersTeamRequest memberTeamRequest = new AddMembersTeamRequest();

memberTeamRequest.TeamId = teamId; //Guid of Team

// Prepare Member (i.e.,User) array to add to Team

Guid[] arrMembers = new Guid[2];

arrMembers[0] = userId1; // GUID of User 1

arrMembers[1] = userId2; // GUID of User 2

// Set MemberIds property with “arrMembers”

memberTeamRequest.MemberIds = arrMembers;

// Execute the Request

AddMembersTeamResponse response = (AddMembersTeamResponse)service.Execute(memberTeamRequest);

Below is the code to remove User(s) from a Team

RemoveMembersTeamRequest removeMemberTeamRequest = new RemoveMembersTeamRequest();

removeMemberTeamRequest.TeamId = teamId; //Guid of Team

// Prepare Member (i.e.,User) array to remove from Team

Guid[] arrMembers = new Guid[2];

arrMembers[0] = userId1; // GUID of User 1

arrMembers[1] = userId2; // GUID of User 2

// Set MemberIds property with “arrMembers”

removeMemberTeamRequest.MemberIds = arrMembers;

// Execute the Request

RemoveMembersTeamResponse response = (RemoveMembersTeamResponse)service.Execute(removeMemberTeamRequest); 

🙂

UserId & InitiatingUserId properties in Plugin of CRM

August 19, 2012 3 comments

In CRM plugin, “IExecutionContext” contains 2 properties

  • UserId
    • Gets the GUID of the user for whom the plug-in invokes “on behalf of”.
  • InitiatingUserId
    • Gets the GUID of the user under which the current pipeline is executing.

Consider a scenario

  • You have a user “RAJ” with “Sales Person” role with only “User Level” “Read” privilege on ‘Contact’
  • You have a plugin on Post Deletion of ‘Contact’ with name “PostContactDelete”
  • Assume in one particular scenario user “RAJ” should be able to delete a ‘Contact’
  • So you can run the “PostContactDelete” plugin in the user with “SystemAdministrator” role
    • (i.e., Set “Run in User’s Context” to User with admin role; In sample screen shot below I chosen my admin user whose name is  ‘CRM WaSu1)
Run in User Context

Run in User Context

  • When User “RAJ” logs in and try to delete ‘Contact’ the plug-in “PostContactDelete” fires. When you debug
    • IExecutionContext.UserId = GUID of  SystemAdministrator (i.e., OnBehalfOf User ‘RAJ’)
    • IExecutionContext. InitiatingUserId =GUID of  RAJ   (i.e., Actual User)

🙂

Configure Tracing and view trace log files in CRM

August 16, 2012 2 comments

Tracing is important in CRM especially when your plugin throw exceptions in Test or Production environments

We can configure and view the trace log file easily using “Crm Trace Log Viewer” tool and it work for both CRM 4.0 and 2011

Download

Once you download the tool

Configure Tracing

  • Double click on the “Crm Trace Log Viewer” Application
Crm Trace Log Viewer Application

Crm Trace Log Viewer Application

  • Configure Tracing by go to Tools –> Configure Tracing
Configure Tracing

Configure Tracing

  • Provide your CRM server machine IP or Name and click “Ok”
CRM server IP or Machine Name

CRM server IP or Machine Name

  • Provide the details as given below
    • Directory – Path where you want your log files to generate
    • Level & Schedule
Configuring Trace

Configuring Trace

View Trace Log Files

  • Once you run the CRM application log files get generate in the path which we provided
Trace Log File

Trace Log File

  • To view the logs, Go to File –> Open Log
Open the trace log

Open the trace log

  • Once you open the file, you can view the details in “Details” pane
Exception Details

Exception Details

Note – Don’t forget to disable the tracing after you are done with debugging.

  • To disable tracing, open the tool and uncheck the option “Trace Enabled” (Refer image #4)

Outlook Client Tracing

  • Using CRM 2011 “Diagnostics Tool”, we can enable/disable tracing in outlook client
  • Here is the link

🙂