Welcome to Part 2 on is subject. If you haven’t already read the How to register an early bound library within Microsoft Dynamics CRM Online Sandbox Isolation Mode (Part 1) I highly recommend you do so as it will give you added context along with some of the issues and options when deciding whether ILMerge is the best approach or not.

This article will outline how to setup ILMerge so that when you compile the various projects within Visual Studio the output assemblies can be merged into a single assembly as required when registering those as Plugins/Custom Workflow libraries to be used with Microsoft Dynamics CRM Online or On Premise where the isolation mode is set to Sandbox.

How to use ILMerge

There are two ways of doing this:

  • As part of the MS Build process
  • Manually through the command line

The following instructions are based on Visual Studio 2012/.NET 4.5.2 it should more or less be the same for the latest versions of Visual Studio.

Using ILMerge as part of the build process

This is a little tricky to setup at first but once done means that whenever you build your projects as part of the CRM solution everything will be built (merged) for you without you then having to do additional steps manually.

The first thing you need to do is right click on your plugin and workflow projects and go to Manage NuGet Packages. In the top right search for ILMerge. Then install the ILMerge and MSBuild ILMerge Task. The packages will be downloaded and will create a folder called packages within your solution folder. Download ILMerge Task first and allow it to download the latest ILMerge.

Untitled.png

You can then verify everything looks as expected by go to Tools->Library Package Manager->Package Visualiser:

Untitled.png

Now we need to ensure that ILMerge command is part of the build process to do this we must manually edit the Plugin cs file. Unfortunately the package installer adds files to our solution but does not go all the way in configuring this for us. You will note the following files are shown in your project now:

  • ILMerge.props
  • Packages.config
  • ILMergeOrder.txt

Right-click on your plugin project and near the bottom of the menu context window you will see an option “unload project”. This enables you to edit the project file within VS simply by right clicking and selecting edit.

Set the paths and make sure the settings within packages config file matches. You need to ensure paths match your VS solution file structure and that the versions of ILMerge Task match those from the installed NuGet versions.

  =”..\packages\MSBuild.ILMerge.Task.1.0.2\build\MSBuild.ILMerge.Task.props” Condition=”Exists(‘..\packages\MSBuild.ILMerge.Task.1.0.2\build\MSBuild.ILMerge.Task.props’)” />

Then also near the bottom of the file:

 This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.

=”..\packages\MSBuild.ILMerge.Task.1.0.2\build\MSBuild.ILMerge.Task.targets” Condition=”Exists(‘..\packages\MSBuild.ILMerge.Task.1.0.2\build\MSBuild.ILMerge.Task.targets’)” />

<!– To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets.

After this you then right-click on the project to “reload the plugin project”. This completes editing the Microsoft build steps for your specific CRM solution project however we need to also update the targets.

Assembly Type Information

When I first tried to use ILMerge I forgot to do this step and you guessed it things didn’t work as I had expected. Looking back now it seems an obvious mistake and it probably was but there are so many things to consider when building a project for CRM deployment it’s easy even for the most experienced to forget key steps.

Sufficed to say this is major step for the assemblies to work as you would expect. If you don’t do it then serialisation errors will be triggered; there are work around’s such as defining implicitly the types and converting them at compile time. The type of error from CRM which I am talking about would look as follows:

System.Runtime.Serialization.SerializationException: Microsoft Dynamics CRM has experienced an error. -2147220970

Which according to Microsoft basically translates to “An unexpected error occurred”. If you debug, you are likely to get misleading errors such as “incoming entity id Does Not Exist”.

Go into your Workflow Activity or Plugin folder and expand the “Properties” node to reveal the file “AssemblyInfo.cs”.

Untitled.png

Then at the very bottom of that section you need to add the following line:

[assembly: Microsoft.Xrm.Sdk.Client.ProxyTypesAssemblyAttribute()]

This will ensure that SDK Class Types are packaged up as part of the DLL, this is important so that when it’s merged, the CRM application is able to Cast between your early bound types and the types  expected within the proxy. For example _service.Create(Entity TaskObj), the Create method expects an “Entity” class type not an early bound Task type.

If you don’t have this line all plugins and custom workflow activity projects registered in Sandbox isolation mode will not work and throw a serialization error. One possible work around is to change the code to say _service.Create(myEarlyBoundObject.ToEntity()) that would work however is not exactly very readable and is something of a hack. To avoid the problem add the line above to the AssemblyInfo.cs files wherever those projects need to reference your early bound library.

 

Editing Your Packages.config

This is important as its a clear sign you have ILMerge in the right VS Project simply by it being present. More importantly the information contained within the file is a good checksum when comparing package files actually on your machine and there relative paths to the project (all have to be correct for ILMerge to work). Also the target framework has to be set correctly.

Signing Assemblies for CRM

The Plugin DLL needs to be signed with or without a password. In addition your custom library will need to be signed for this to work as expected in CRM. In this example I created two separate key files with the same name “signingkey.snk” one in the early binding class project and one for the actual final plugin assembly. However surprisingly the 3rd party library newtonsoft (JSON.Net) was successfully merged I assume it may have been signed by author or this could be a red herring when it comes to 3rd party DLL requirements.

System.IO.FileNotFoundException : Unable to find ILMerge Executable

This is the error I was receiving when trying to build my plugin project that was referencing the early bound Common CRM class DLL. I discovered that probably due to “re-distribution” legal reasons that although the packages had been downloaded the target folder “packages\ilmerge.2.14.1208” did indeed not contain ILMerge.exe. Instead go into the packages\ilmerge.2.14.1208\tools sub-directory and copy it from there into the folder “ilmerge.2.14.1208”.

The build then worked successfully.

Specifying Assemblies for Merge

Within a Visual Studio solution you can have potentially many projects each with their own references. The question then arises how do I specify what assemblies to merge? It is important you have set the order in which projects are built within Visual Studio using the “Project Build Order” menu option when you right click on the solution/project. Next you need to pay special attention to the “properties” window of each of the assemblies you have referenced within the project. The property “Copy Local” should be set to “True” for all the assemblies you wish to get merged. As an example: Lets say you have an early bound project called Common, you would within your Plugin/Workflow project have created a reference to it by browsing to the DLL debug folder location, after you have done this you would specify within the plugin project that the Common assembly should Copy Local. This informs the ILMerge during build to Merge it.

That is not the end of the story, even if you have done the above the Common library will not be merged unless you have also in addition instantiated an instance of a class from the Common library within your Plugin code (in other words you have code that use the classes and methods defined in the referenced Common assembly).

If using the standard developer toolkit you normally end up with two output assemblies yourplugin.dll and yourworkflow.dll and those each contain merged DLL’s such as Common.dll for early binding and any other referenced DLLs that you may have merged.

Remember adding the code direct to the DLL is the preferred and recommended approach to avoid CRM Plugin errors so always go back to basics if things don’t work as expected it may be down to the merging process.

All assemblies with Copy to Local set to true will be merged. Conversely, you normally ensure that all CRM SDK and Microsoft Core assemblies have the set “Local Copy” to false.

How to check everything was merged

Within a Visual Studio you will notice that when you build your solution that the Output window contains the steps MSBuild has taken to merge the relevant assemblies. There will be a line which says “Merged Assemblies: yourdll.; next DLL; next DLL; etc”. You can also use an assembly de-compiler tool such as the excellent  Jet Brains Dot Peek. It is a very easy to use tool which basically allows you to see what classes are part of an assembly and see the source code within the assemblies. Therefore in our earlier examples, within the Plugin.DLL file we’d expect to see the early bound classes within it and any other classes from 3rd party assemblies we may have merged such as newtonsoft.dll.

Testing it all works

The first time you go through this it will be painful but at least you have this guide to help you which is more than what I had at the time. My advice is to do each step slowly, go the extra mile by using something like Dot Peek to interrogate the contents of the DLL and ensure it works outside of CRM; before then deploying to CRM and expecting it to all work first time! (That is unlikely) so just be realistic here and work through each stage logically ensuring you understand why each step is required for this to work. Also remember that officially Microsoft no longer support this tool and approach because it can lead to unpredictable behavior as discussed in Part 1.

Best of luck! That completes this two part article on: how to register an early bound library within Microsoft Dynamics CRM Online Sandbox Isolation Mode. Any questions or comments as always feel free to contribute.

Photo Credit

Negative Space free image no copyright restriction

Advertisements