Background

As stated in previous post, our XrmFramework is based on Developer Toolkit for Microsoft Dynamics CRM. It has a really good user interface to create plug-ins and at the same point register them:

The main issue here is that the register information is stored as XML and it’s not possible to edit afterwards with the same user interface, which makes not very user friendly.

The other alternative, is to use the PluginRegistration Tool, located in the SDK: Tools\PluginRegistration\PluginRegistration.exe, which once again have a very good user interface but you have to do three manual steps:

1) Register the assembly:

2) Register all the plug-ins steps (events):

3) And finally go into to the MS CRM and add the assembly and the steps as part of the solution that you will deploy from DEV to TEST and PROD.

What we have seen is that the third step is forgotten a lot and therefore we can’t ensure a valid TEST deploy, and sometimes PROD deploy.

Plug-in synchronization

This is the reason we decided to create this functionality so we can determine from our code, what will be synchronized with the MS CRM Solution.

We still rely on the Plugin base class that is part of the Developer Toolkit, but we have expanded it (several times) so we can parse the neccesary information to register events on the solution:

For more information on usage, please read the following: Plugin Registration Setup.

Example:

Based on the following file, we added three events: Update and creation/deletion of many-2-many relations (Associate/Disassociate).

Note: When Associating/Dissociating you will have to listen on all entites.

AccountPostPlugin.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    public class AccountPostPlugin : Plugin
    {
        public AccountPostPlugin()
            : base(typeof(AccountPostPlugin))
        {
            RegisterPluginStep<AnyEntity>(
                EventOperation.Associate, 
                ExecutionStage.PostOperation, 
                ExecuteAccountPostPlugin);

            RegisterPluginStep<AnyEntity>(
                EventOperation.Disassociate, 
                ExecutionStage.PostOperation, 
                ExecuteAccountPostPlugin);

            RegisterPluginStep<Account>(
                EventOperation.Update, 
                ExecutionStage.PostOperation, 
                ExecuteAccountPostPlugin);
        }

        ...
      }

DG.Delegate.HowToDaxif.PluginsSyncDev.fsx

We execute the following Daxif script, without having to leave Visual Studio:

1
2
3
4
5
6
7
8
9
10
11
12
13
#load @"DG.Delegate.HowToDaxif.Config.fsx"

module cfg = DG.Delegate.HowToDaxif.Config

open DG.Daxif.Modules

let dll  = cfg.rootFolder + @"\..\Plugins\bin\Debug\ILMerged.Delegate.Delegate.HowToDaxif.Plugins.dll"
let proj = cfg.rootFolder + @"\..\Plugins\Plugins.csproj"

Plugins.syncSolution
  cfg.wsdlDev' cfg.solution proj dll
    cfg.authType cfg.usrDev cfg.pwdDev cfg.domainDev 
      cfg.log

Daxif output on the first run:

Producing the following output:

2016-03-02T10:11:48.7391862+01:00 - Info: Sync solution Plugins: HowToDaxif
2016-03-02T10:11:48.7391862+01:00 - Verbose: Organization: https://ORG_GOES_HERE.crm4.dynamics.com/XRMServices/2011/Organization.svc
2016-03-02T10:11:48.7391862+01:00 - Verbose: Solution: HowToDaxif
2016-03-02T10:11:48.7391862+01:00 - Verbose: Path to Plugins VS Project: D:\tmp\howToDaxif\DG.Delegate\DG.Delegate.HowToDaxif\Daxif\..\Plugins\Plugins.csproj
2016-03-02T10:11:48.7391862+01:00 - Verbose: Path to Plugins Assembly: D:\tmp\howToDaxif\DG.Delegate\DG.Delegate.HowToDaxif\Daxif\..\Plugins\bin\Debug\ILMerged.Delegate.Delegate.HowToDaxif.Plugins.dll
2016-03-02T10:11:48.7391862+01:00 - Verbose: Authentication Provider: OnlineFederation
2016-03-02T10:11:48.7391862+01:00 - Verbose: User: admin@ORG_GOES_HERE.onmicrosoft.com
2016-03-02T10:11:48.7391862+01:00 - Verbose: Password: ***********
2016-03-02T10:11:48.7391862+01:00 - Verbose: Domain: 
2016-03-02T10:11:48.7391862+01:00 - Verbose: Checking local assembly
2016-03-02T10:11:48.7704356+01:00 - Verbose: Authenticating credentials
2016-03-02T10:11:50.8173309+01:00 - Verbose: Authentication completed
Binding session to 'D:\tmp\howToDaxif\DG.Delegate\DG.Delegate.HowToDaxif\Daxif\Microsoft.Xrm.Sdk.dll'...
2016-03-02T10:11:51.1767261+01:00 - Verbose: Retrieving assemblies from CRM
2016-03-02T10:11:51.5985980+01:00 - Verbose: Validating plugins to be registered
2016-03-02T10:11:51.6298562+01:00 - Verbose: Validation completed
2016-03-02T10:11:51.6298562+01:00 - Verbose: Syncing plugins
2016-03-02T10:11:51.6298562+01:00 - Info: Retrieving Steps
2016-03-02T10:11:51.8642226+01:00 - Info: Deleting images
2016-03-02T10:11:52.0517813+01:00 - Info: Deleting steps
2016-03-02T10:11:52.0517813+01:00 - Info: Deleting types
2016-03-02T10:11:52.4580355+01:00 - Verbose: Retrieving assemblies from CRM
2016-03-02T10:11:52.6611067+01:00 - Info: Updating Assembly
2016-03-02T10:11:53.7236234+01:00 - Verbose: pluginassembly: ILMerged.Delegate.Delegate.HowToDaxif.Plugins was updated
2016-03-02T10:11:53.7236234+01:00 - Info: Creating types
2016-03-02T10:11:53.7392562+01:00 - Verbose: Creating type: DG.Delegate.HowToDaxif.Plugins.AccountPostPlugin
2016-03-02T10:11:54.4736389+01:00 - Verbose: plugintype: DG.Delegate.HowToDaxif.Plugins.AccountPostPlugin was created
2016-03-02T10:11:54.4892893+01:00 - Info: Creating and updating steps
2016-03-02T10:11:56.5830716+01:00 - Verbose: sdkmessageprocessingstep: (DG.Delegate.HowToDaxif.Plugins.AccountPostPlugin: Associate of any Entity) was created
2016-03-02T10:11:56.5830716+01:00 - Verbose: sdkmessageprocessingstep: (DG.Delegate.HowToDaxif.Plugins.AccountPostPlugin: Disassociate of any Entity) was created
2016-03-02T10:11:56.5830716+01:00 - Verbose: sdkmessageprocessingstep: (DG.Delegate.HowToDaxif.Plugins.AccountPostPlugin: Update of account) was created
2016-03-02T10:11:57.5206179+01:00 - Info: The solution Plugins were synced successfully

AccountPostPlugin.cs (with outcommented steps)

If we now outcomment the steps run the Daxif script again.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    public class AccountPostPlugin : Plugin
    {
        public AccountPostPlugin()
            : base(typeof(AccountPostPlugin))
        {
            //RegisterPluginStep<AnyEntity>(

            //    EventOperation.Associate, 

            //    ExecutionStage.PostOperation, 

            //    ExecuteAccountPostPlugin);


            //RegisterPluginStep<AnyEntity>(

            //    EventOperation.Disassociate, 

            //    ExecutionStage.PostOperation, 

            //    ExecuteAccountPostPlugin);


            //RegisterPluginStep<Account>(

            //    EventOperation.Update, 

            //    ExecutionStage.PostOperation, 

            //    ExecuteAccountPostPlugin);

        }

        ...
      }

Daxif output on the first run:

Producing the following output:

2016-03-02T10:16:59.3771254+01:00 - Info: Sync solution Plugins: HowToDaxif
2016-03-02T10:16:59.3771254+01:00 - Verbose: Organization: https://ORG_GOES_HERE.crm4.dynamics.com/XRMServices/2011/Organization.svc
2016-03-02T10:16:59.3771254+01:00 - Verbose: Solution: HowToDaxif
2016-03-02T10:16:59.3771254+01:00 - Verbose: Path to Plugins VS Project: D:\tmp\howToDaxif\DG.Delegate\DG.Delegate.HowToDaxif\Daxif\..\Plugins\Plugins.csproj
2016-03-02T10:16:59.3771254+01:00 - Verbose: Path to Plugins Assembly: D:\tmp\howToDaxif\DG.Delegate\DG.Delegate.HowToDaxif\Daxif\..\Plugins\bin\Debug\ILMerged.Delegate.Delegate.HowToDaxif.Plugins.dll
2016-03-02T10:16:59.3771254+01:00 - Verbose: Authentication Provider: OnlineFederation
2016-03-02T10:16:59.3771254+01:00 - Verbose: User: admin@ORG_GOES_HERE.onmicrosoft.com
2016-03-02T10:16:59.3771254+01:00 - Verbose: Password: ***********
2016-03-02T10:16:59.3771254+01:00 - Verbose: Domain: 
2016-03-02T10:16:59.3771254+01:00 - Verbose: Checking local assembly
2016-03-02T10:16:59.4083763+01:00 - Verbose: Authenticating credentials
2016-03-02T10:17:01.4240922+01:00 - Verbose: Authentication completed
Binding session to 'D:\tmp\howToDaxif\DG.Delegate\DG.Delegate.HowToDaxif\Daxif\Microsoft.Xrm.Sdk.dll'...
2016-03-02T10:17:03.7053188+01:00 - Verbose: Retrieving assemblies from CRM
2016-03-02T10:17:04.1428631+01:00 - Verbose: Validating plugins to be registered
2016-03-02T10:17:04.1584519+01:00 - Verbose: Validation completed
2016-03-02T10:17:04.1584519+01:00 - Verbose: Syncing plugins
2016-03-02T10:17:04.1584519+01:00 - Info: Retrieving Steps
2016-03-02T10:17:04.4084639+01:00 - Info: Deleting images
2016-03-02T10:17:05.0647246+01:00 - Info: Deleting steps
2016-03-02T10:17:06.2210441+01:00 - Verbose: sdkmessageprocessingstep: DG.Delegate.HowToDaxif.Plugins.AccountPostPlugin: Disassociate of any Entity was deleted
2016-03-02T10:17:06.2210441+01:00 - Verbose: sdkmessageprocessingstep: DG.Delegate.HowToDaxif.Plugins.AccountPostPlugin: Update of account was deleted
2016-03-02T10:17:06.2210441+01:00 - Verbose: sdkmessageprocessingstep: DG.Delegate.HowToDaxif.Plugins.AccountPostPlugin: Associate of any Entity was deleted
2016-03-02T10:17:06.2210441+01:00 - Info: Deleting types
2016-03-02T10:17:07.0022768+01:00 - Verbose: plugintype: DG.Delegate.HowToDaxif.Plugins.AccountPostPlugin was deleted
2016-03-02T10:17:07.0022768+01:00 - Verbose: Retrieving assemblies from CRM
2016-03-02T10:17:07.2210606+01:00 - Info: Updating Assembly
2016-03-02T10:17:08.2210258+01:00 - Verbose: pluginassembly: ILMerged.Delegate.Delegate.HowToDaxif.Plugins was updated
2016-03-02T10:17:08.2210258+01:00 - Info: Creating types
2016-03-02T10:17:08.2210258+01:00 - Info: Creating and updating steps
2016-03-02T10:17:08.2210258+01:00 - Info: The solution Plugins were synced successfully

Note: Remember to re-compile the plug-in project for each time you make changes to the code.

Conclusion

We have provided a more robust interface to make the synchronization of plug-ins, which ensures that code saved in the source control of the events that should be registred in MS CRM. As we use scripts, these can easily be built-in to the current built-script of the solution for deploy automation.

Note: We ensure that plug-in steps are enabled by running the following functionality, Solution.pluginSteps, after the solution is deployed.

1
2
3
4
5
6
7
8
9
10
11
... 

Solution.import
  cfg.wsdlTest' cfg.solution zip true
    cfg.authType cfg.usrTest cfg.pwdTest cfg.domainTest 
      cfg.log

Solution.pluginSteps
  cfg.wsdlTest' cfg.solution true
    cfg.authType cfg.usrTest cfg.pwdTest cfg.domainTest 
      cfg.log

More info: