Sunday, June 13, 2010

MS CRM Rollup 11 Known Issue (ISV config)

After installing UR11 one cannot find the menus which were added in ISV config.

Workaround until SE fix (TBD):
Add regkey [HKEY_CURRENT_USER\Software\Microsoft\MSCRMClient] "InitToolbarForO14"=dword:00000001

Monday, June 7, 2010

Passing / Sharing Data Between Plug-ins

The message pipeline model provides for a PropertyBag of custom data values in the execution context that is passed through the pipeline and shared among registered plug-ins. This collection of data can be used by different plug-ins to communicate information between plug-ins and enable chain processing where data processed by one plug-in can be processed by the next plug-in in the sequence and so on. This feature is especially useful in pricing engine scenarios where multiple pricing plug-ins pass data between one another to calculate the total price for a sales order or invoice. Another potential use for this feature is to communicate information between a plug-in registered for a pre-event and a plug-in registered for a post-event.

The name of the parameter that is used for passing information between plug-ins is SharedVariables. This is a collection of System.Object. A common type of object that is used to fill the collection is DynamicEntity. At run time, plug-ins can add, read, or modify properties in the SharedVariables property bag. This provides a method of information communication among plug-ins.

Note Only types that are XML serializable should be placed in SharedVariables. All types derived from BusinessEntity are XML serializable.

The following code example shows how to use SharedVariables to pass data from a pre-event registered plug-in to a post-event registered plug-in.


using System;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;

public class AccountSetStatePreHandler : IPlugin
public void Execute(IPluginExecutionContext context)
// Create or retrieve some data that will be needed by the post event
// handler. You could run a query, create an entity, or perform a calculation.
//In this sample, the data to be passed to the post plug-in is
// represented by a GUID.
Guid contact = new Guid("{74882D5C-381A-4863-A5B9-B8604615C2D0}");

// Pass the data to the post event handler in an execution context shared
// variable named PrimaryContact.
new PropertyBagEntry("PrimaryContact", (Object)contact.ToString()));
// Alternate code: context.SharedVariables["PrimaryContact"] = contact.ToString();

Writing the Plug-in Constructor

The Microsoft Dynamics CRM platform has special support for a plug-in constructor that accepts two string parameters. If you write a constructor for your plug-in that accepts two string parameters, you can pass any two strings of information to the plug-in at run time. The following code shows these two parameters.


using System;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;

namespace CustomPlugin
public class ContactCreate: IPlugin
public ContactCreate(string unsecure, string secure)
// Do something with the parameter strings.

public void Execute(IPluginExecutionContext context)
// Do something here.

The first string parameter of the constructor contains public (unsecure) information. The second string parameter contains non-public (secure) information. However, the secure string is not passed to a plug-in that executes while offline.

The information that is passed to the plug-in constructor in these two strings is specified when the plug-in is registered with Microsoft Dynamics CRM. When you use the PluginRegistration tool to register a plug-in, you can enter the secure and unsecure information in the Secure Configuration and Unsecure Configuration fields provided in the Register New Step form. The PluginDeveloper tool only supports the unsecure string through its CustomConfiguration attribute of the Step tag in the register.xml input file.

Debugging a Plug-in

The following steps describe how to debug a plug-in.

1. Deploy the plug-in assembly.
Copy the assembly to the standard plug-in folder on the server: \Server\bin\assembly. If there is another copy of the assembly at the same location and you cannot overwrite that copy because it is locked by Microsoft Dynamics CRM, run the iisreset program in a command window to free the assembly.

2. Register the plug-in on the desired stage of the event execution pipeline. Register the plug-in assembly on the server using on-disk deployment.
Tip It is possible to debug a database deployed plug-in. The compiled plug-in assembly's .pdb file must be copied to the server's \Server\bin\assembly folder and IIS must then be restarted. After debugging has been completed, you must remove the .pdb file and reset IIS to prevent the w3wp.exe process from consuming additional memory.

Generally, you do not want to register your plug-in in the event execution pipeline until the plug-in assembly is available on the Microsoft Dynamics CRM server. If someone else is using Microsoft Dynamics CRM on the server, and you have registered the plug-in in but have not yet deployed the assembly, the person running Microsoft Dynamics CRM receives an error if the system tries to execute the missing plug-in.

3. Configure the debugger.
Set a breakpoint in your plug-in code. For an online plug-in, attach the debugger to the w3wp.exe process on the Microsoft Dynamics CRM server. For an offline plug-in, attach the debugger to the Microsoft.Crm.Application.Hoster.exe process. For asynchronous registered plug-ins (or workflow assemblies) attach to the CrmAsyncService.exe process. If there are multiple processes running for the same executable file, attach the debugger to all of them because you do not know which process runs your custom code.

4. Test the plug-in.
Run the Microsoft Dynamics CRM Web application, or other custom application that uses the SDK, and perform whatever action is required to cause the plug-in to execute. For example, if a plug-in is registered for an account creation event, create a new account.

5. Debug your plug-in code.
Make any needed changes to your code so that it performs as you want. If the code is changed, compile the code into an assembly and repeat step numbers 1, 3, and 4 in this procedure as necessary. However, if you change the plug-in assembly version number, you must unregister the earlier version of the assembly and register the new version.

6. Register the plug-in in the database.
After the edit/compile/deploy/test/debug cycle for your plug-in has been completed, unregister the (on-disk) plug-in assembly and then reregister the plug-in in the Microsoft Dynamics CRM database.

Create a CrmService proxy for plug-ins that execute in the child pipeline.

We always come across creating a CrmService Proxy for plug-ins that execute in the child pipeline. In a Child pipeline, you must instantiate the CrmService or MetadataService manually. We just need to check the InvocationSource Property (Child = 1, Parent = 0) of the IPluginExecutionContext. Pass the InvocationSource Property value to the below method.

Below is very simple code which creates a proxy.
/// The execution context that was passed to the plug-in's Execute method.
/// Set to True to use impersonation.
/// A CrmServce instance.
private CrmService CreateCrmService(IPluginExecutionContext context, Boolean flag)

CrmAuthenticationToken authToken = new CrmAuthenticationToken();
authToken.AuthenticationType = 0;
authToken.OrganizationName = context.OrganizationName;

// Include support for impersonation.
if (flag)
authToken.CallerId = context.UserId;
authToken.CallerId = context.InitiatingUserId;

CrmService service = new CrmService();
service.CrmAuthenticationTokenValue = authToken;
service.UseDefaultCredentials = true;

// Include support for infinite loop detection.
CorrelationToken corToken = new CorrelationToken();
corToken.CorrelationId = context.CorrelationId;
corToken.CorrelationUpdatedTime = context.CorrelationUpdatedTime;
corToken.Depth = context.Depth;

RegistryKey regkey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\MSCRM");

service.Url = String.Concat(regkey.GetValue("ServerUrl").ToString(), "/2007/crmservice.asmx");
service.CorrelationTokenValue = corToken;

return service;