You spent years polishing your algorithm, moving bytes around, replacing strings with StringBuilders, extracting every last bit of performance from your code. The assembly Acme.CoolTools.dll is into its' 3rd major version, competitors are begging for mercy. Life is good. Then Microsoft CRM 4 comes along with its' beastly architecture wanting plug-ins to be deployed in a database. And offline CRM clients, clutching a copy of Reflector all want your dazzling assembly as well.
Perhaps you simply wanted to avoid GAC, which Chris Sells knew to be evil back in 2004. Or may be you just felt that instead of being sucked into assembly hell you would rather distribute one and only one assembly.
Whatever the real reason might be, today's challenge is to write a Microsoft CRM 4 plug-in that uses classes and methods from other assemblies; then package it all into one blob that can be deployed and distributed as required. In fact, it was the challenge from one of our customers as well as from the newsgroups (speaking of good timing!). [more]
Let's say we have a secret code that predicts annual turnover for a company based on the name. Here is our complex algorithm in its' entire glory.
public static class AccountMagic
public static decimal CalculateAnnualTurnover(string companyName)
The code is compiled into a separate assembly Acme.CoolTools.dll that is then referenced by our plug-in.
The plug-in is as sophisticated: it's designed to "monitor" account creations and updates, and then to recalculate and update annual turnover using company name.
public class AccountPlugin: IPlugin
public void Execute(IPluginExecutionContext context)
// safe-guard recursion
if (context.Depth > 1)
// Extract dynamic entity from postentityimage. We should have id, name and revenue
// properties if they are not null in the database.
DynamicEntity entity = (DynamicEntity)context.PostEntityImages["accountEntity"];
// Re-calculate annual turnover based on a company name. Use proven and tested algorithm.
decimal turnover = Acme.CoolTools.AccountMagic.CalculateAnnualTurnover((string)entity["name"]);
// Get Crm service, set revenue property and update the entity.
ICrmService service = context.CreateCrmService(true);
entity["revenue"] = new CrmMoney(turnover);
Note that we use PostEntityImages to access account information. For performance reasons this is recommended way to pass entity properties to a plug-in code instead of executing Retrieve requests left and right. As a handy side-effect, entity extracted from postentityimage is exactly what we need to update the record.
Merging the libraries
Remember how you can compile ASP.NET code into a single assembly? ILMerge is a sibling utility that can be used to merge existing assemblies into a single one. It even merges PDB files and resigns the final output. There are some GUI wrappers but, honestly, it's just as easy from the command-line; MSBuild fans can use ILMerge task.
The command to merge our two assemblies into one while maintaining strong name is quite simple:
"c:\Program Files\Microsoft\ILMerge\ilmerge" /keyfile:acme.snk Acme.Plugins.dll Acme.CoolTools.dll /out:Acme.dll
Note that we have to give it a key to resign the assembly.
Now we have a single Acme.dll assembly that needs to be registered using the latest CRM plug in registration tool:
- Register assembly and the plugin
- Register steps for Create and Update messages on account entity. Synchronous, Post stage, Parent Pipeline, Server. Plus Offline if required.
- For Update message specify name as the only filtering attribute, i.e. the one that triggers plug-in execution.
- Register post images for both steps. We only need accountid, name and revenue properties.
Registration should like the following:
The code and a simple command file to build the plug-in are attached. You'll need to copy Microsoft.Crm.Sdk.dll and Microsoft.Crm.SdkTypeProxy.dll libraries into the same folder as the source files for C# compiler to find them. Alternatively, adjust references in the batch file to point to the existing location.
I has not tested Offline client but I cannot see why it would not work.
And last but not least, company named Test generates about 5.5 times annual revenue of Acme company.
Last revised: 05 Dec, 2012 05:25 PM