Advertisements

Archive

Posts Tagged ‘Plug-ins’

[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: , ,

How to Debug Plug-Ins in CRM

January 13, 2012 7 comments

Hi,

Sometimes you might get wonder (even frustrated) why the debugger is not hitting the break point in your Plug-In code file.

Below are the Checklist to perform prior to start the debugging of your Plug-in assembly.

  • Ensure that your plug-in assembly is signed (See)
  • Rebuild the plug-in assembly
  • Reset the IIS (i.e. Open command prompt and run ‘iisreset’ command)
  • Restart CRM Asynchronous Service on CRM server (Only in case of asynchronous plug-in or Custom workflow )
  • Copy the .pdb file and your .dll file to server’s assembly (i.e., ..\Program Files\Microsoft Dynamics CRM\Server\bin\assembly)
  • Open the Plug-in Registration Tool (Download)
  • Browse the dll from your Plug-Ins projects “bin\debug” folder
  • In Plug-in Registration Tool , Choose “Specify the location where assembly should be stored” option as “Disk”
  • Register the step
  • Register the image(s) if any
  • Attach the process by opening the Plug-in project in the Visual Studio and then
    • From menu choose “Debug -> Attach to Process…” ( or Click ‘Alt + Ctrl + P’)
    • Select  w3wp.exe (i.e.,Worker Process), if plug-in is Synchronous
    • Select CRMAsyncService.exe, if Plug-in is asynchronous or Custom workflow.
Attaching Worker Process (w3wp.exe)

Attaching Worker Process (w3wp.exe)

  • You are all set by now and put a break point (Click F9) on relevant code line.

In case of Remote Debugger :-

  • If your CRM server machine is different from your development machine
  • Install “Visual Studio Remote Debugger” (Download) on CRM server machine
  • Run it as “Administrator”
  • Follow the same steps above except while attaching Process, in the “Attach to Process” window, set “Qualifier” as “CRM server machine”

Debug plug-in in outlook offline mode

  • Clean and rebuild the plug-in solution on your machine using visual studio
  • Register the plugin on the server
  • Synchronize the organization with the outlook
  • Go Offline
  • Attach the debugger to the process “Microsoft.Crm.Application.Hoster.exe
  • Place a breakpoint in the code.
  • Run the scenario

Hope it helps 🙂

Assign record (i.e., Change Owner) using CRM 2011 Plug-In

Hi,

In CRM, we cant update the “Owner” field like any other field, Assign or Changing the owner in CRM need’s an explicit service request (i.e., AssignRequest)

  •   This is the code to “Assign” a record to other user in Plug-In

public void Execute(IServiceProvider serviceProvider)

{

IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

IOrganizationService service = null;

try

{

service = factory.CreateOrganizationService(context.UserId);

// Create the Request Object and Set the Request Object’s Properties

AssignRequest assign = new AssignRequest

{

//systemuser; i.e., User to whome you are assigning the entity to

Assignee = new EntityReference(“systemuser”, {new_owner_guid}),

//Current record which you are assigning to the user

Target = new EntityReference(context.PrimaryEntityName.ToString(), context.PrimaryEntityId)

};

// Execute the Request
service.Execute(assign);

}

}

Hope it helps 🙂