Dynamics CRM and ILMerge: The Easy Way to Merge DLLs for Plugins

Being able to use external DLLs in Dynamics CRM plugins is challenging but doable. Most people who have been doing development on the Dynamics CRM platform for any period of time know that it is not enough to simply reference the DLLs in Visual Studio – you must somehow make them available to run on the server – this can range from mildly annoying to impossible (if you using CRM Online.)

If you wanted to reference an assembly that you had written, your options were pretty limited:

Register the assembly on disk with any referenced assemblies in the same directory.

Register the referenced assembly in the GAC

Include the relevant source code in the plug-in assembly

With the introduction of Solutions in Microsoft Dynamics CRM 2011, the first two options are not very manageable (as they require special setup on multiple servers during the installation of the solution”>PICTURE REMOVED]

If you wanted to reference an assembly that you had written, your options were pretty limited:

Register the assembly on disk with any referenced assemblies in the same directory.

Register the referenced assembly in the GAC

Include the relevant source code in the plug-in assembly

With the introduction of Solutions in Microsoft Dynamics CRM 2011, the first two options are not very manageable

. In addition, those options don’t work in Microsoft Dynamics CRM Online, since assemblies must be registered in the database in CRM Online. If you include source code, as the last option suggests, then all of the benefits of a referenced assembly are lost, without gaining any real benefits.

In the same article it is recommended to use ILMerge. ILMerge is a tool from Microsoft Research that can combine multiple DLLs into a single DLL – eliminating the problem (in the case of Dynamics CRM) of having multiple DLL files.

The article goes on to describe the basics of using ILMerge to create a single plugin DLL. While I have done this on many projects over the year it has always been more complicated to initially setup and maintain than I would prefer. It can also be challenging to teach new developers – many of whom are still getting comfortable with Dynamics CRM development.

I recently decided to do some research and figure out a simple and well defined set of step-by-step instructions to use ILMerge in development. In the next several steps I will describe the exact process I now use, which doesn’t involve any editing of MSBUILD files, creation of PowerShell or BAT scripts, etc. It only requires the use of Nuget and the Visual Studio GUI.

Start by creating a new Blank Solution in Visual Studio (Other Project Types -> Video Studio Solutions.) Name it as you wish, I used ThinkCrmBlog.PluginDllMerge.

Now that you have a new solution add a couple of class libraries. I’ve named mine ThinkCrmBlog.CrmHelper (this is inline with my best practice of having a standalone DLL of helper classes that can be used for CRM development but are not specific to any particular CRM org and can be used in plugins, workflows, and client side code) and ThinkCrmBlog.DemoPlugin (which will hold my IPlugin class.

So now your solution should look like this picture (assuming you deleted the Class1.cs files.)

We’ll add the Dynamics CRM libraries using NuGet.

Search for Microsoft.CrmSdk.CoreAssemblies and install.

You want to install to both projects.

Using NuGet greatly simplifies some tasks by including required dependencies. In this case it is Microsoft.IdentifyModel. Although technically not required to compile a plugin DLL if you were to use the core assemblies in a client side app it is necessary and can be something of pain when you do not realize you need it until runtime.

You can tell that everything has succeeded by the green check.

So now it is time to get ILMerge installed. Luckily for the modern developer we have NuGet to make this super simple. We don’t want just ILMerge, we want a tool that automates the ILMerge process into the build process. Do a search for MSBuild.ILMerge.Task and click install.

We only want to install to the project that will need to have DLLs merged, so uncheck the box next to ThinkCrmBlog.CrmHelper. Now, if you had more projects creating plugin DLLs that referenced ThinkCrmBlog.CrmHelper you would want to check the box for each of those projects.

The ILMerge application itself is available as a NuGet package and is a dependency, so it will be installed.

Again, the green check is your confirmation of success.

Now we need to add a reference to ThinkCrmBlog.CrmHelper from ThinkCrmBlog.DemoPlugin.

Just check the box.

Now we have to do a property update on the CRM SDK DLL files so they don’t get merged into our final DLL. The ILMerge build task we installed will merge all the DLLs in the \bin directory. To avoid merge the CRM SDK DLLs and Microsoft.IdentityModel.DLL into our plugin DLL we need to tell Visual Studio to not copy them on build. Select the three files and set the property “Copy Local” to false.

One last, but critical step, be sure to sign both of the projects. Dynamics CRM requires that DLLs be signed and therefore any DLLs we include must be signed.

The solution should look similar to this picture.

For the source code, which I’ve placed online on GitHub @ https://github.com/nicknow/ThinkCrmBlog.PluginDllMerge, I created a very basic plugin will create an instance of a class in CrmHelper and call a method before throwing an exception to allow the user to via the trace log. This was done just for demonstration – it serves no real-world purpose. Afte writing the code I did a Clean Solution and a Rebuild Solution.

In the output directory you’ll see only the final DLL – the merged DLL(s) have been deleted. If you open the DLL in a decompiler, such as dotPeek, you’ll see that the DLL contains both the ThinkCrmBlog.DemoPlugin and ThinkCrmBlog.CrmHelper namespaces.

Install the DLL using the Plugin Registration Tool (or any other preferred tool.) You’ll see that it is a Sandbox deployment – so it will work with CRM Online.

Register a plugin step against an entity and step, we are just testing so it doesn’t matter what entity and step. I choose create on contact.

If I try to create a new Contact I’ll get the following error (as expected based on the code.)

If you click Download Log File you’ll see the following indicating that our plugin fired and successfully called CrmHelper.IsTeamMember. This confirms that our DLL merge is correctly working.

NOW: Be Smart – Delete that plugin if you have been following along, you don’t want it causing you an error unexpectedly down the road.

I’ve tested this with a project that contained CrmSvcUtil.exe output for early bound objects without an issue. I’ve done this with JSON.NET without an issue (except for having to user v6.0.3 or earlier if you are in Sandbox.) I’ve run this, as shown above, in Sandbox without issue.

Remember, just because you can merge DLLs doesn’t mean you don’t have any limitations. Code running in Sandbox must still adhere to the rules – no SQL calls, disk access, reflection, etc. Also, be careful that you aren’t merging so much that your plugin DLL becomes bloated causing issues with deployment or (possibly) a negative performance hit.

Try it out and let me know your experience. I’ve only been using this method for a month but it certainly beats my previous processes that involved either using a batch file or a custom build step and editing the CSPROJ file.

Thanks for this great tutorial. I have followed the steps closely, however, I am still getting two dlls in the output directory. The merge doesn’t appear to have worked. Any ideas why this would be?

nicknow

Thanks, I’m glad you enjoyed it. First, make sure that ILMerge is deployed to the correct project in the NuGet GUI (the one that is to be deployed to CRM.) If that isn’t the issue post the Output Window contents from the build so I can have a look.

Since I have been unable to get ILMerge to work I tried installing an additional dll in the GAC. This causes an error (Attempt by security transparent method ‘XXX’ to access security critical method ‘System.Net.Http.HttpClientExtensions.PostAsJsonAsync(System.Net.Http.HttpClient, System.String, XXX)’ failed.) when I tried to call that dll because I can’t call the fully trusted GAC dll from the partially trusted plugin. I think you are aware of this issue from your Stackoverflow answer (http://stackoverflow.com/a/13650984/569016).

Chris Barber

Since I am back to square one if you have any clue why I can’t get your ILMerge tutorial to work I would be immensely grateful.

Phil Croucher

Hi Chris, I just had the same issue with VS 2012. I tried it in VS 2013 and it worked fine. I found that importing the targets for my projects worked but that the package was in a slightly different location (one further up the directory path) so I copied the working reference from 2013 and added .. for 2012 and it worked

Verify the location on disk – I had initially installed a Release Candidate version which had a totally different path.

nicknow

Looking at these pictures, I’m assuming the the more recent one is the VS2013 working screenshot, I notice that there is a folder, coretools, is the VS2012 build that isn’t there in VS2013. Any idea where that is coming from?

Can you try removing the ILMerge Target from NuGet and re-adding. For some reason it doesn’t appear to be executing on your install?

Also, what is creating the “coretools” folder in bin? I don’t get that folder and I wouldn’t expect it to exist without a custom build process.

If you look in ThinkCrmBlog.DemoPlugin.csproj do you see the following line: “”?

Chris Barber

I have managed to reproduce the issue.

I have created a simpler example in VS2012 and VS2013. Create a new solution from the Blank solution template. Create two class libraries (e.g. ThinkCrmBlog.CrmHelper, ThinkCrmBlog.DemoPlugin) and delete the two default Class1.cs files. Add a reference to the ThinkCrmBlog.CrmHelper project from the ThinkCrmBlog.DemoPlugin project. Right click the ThinkCrmBlog.DemoPlugin project and select manage NuGet packages. Do a search for MSBuild.ILMerge.Task and click install. Set ThinkCrmBlog.DemoPlugin as the startup project. Clean the solution and rebuild. The VS2013 merges the dlls into one, however, the VS2012 example does not work.

When I open the ThinkCrmBlog.DemoPlugin project files the import (<Import Project="..packagesMSBuild.ILMerge.Task.1.0.2) exists in the 2013 project file but not in the VS2012 project file.

I know the NuGet description says that it will work with VS2012 but that is not my experience. Could there be
something wrong with my VS2012?

Chris Barber

Screen grab below

nicknow

Just for clarification you are saying that it works for you with VS2013 but not VS2012?

Not the behavior I would have expected. I’ll have to get on a VM with VS2012 and see if I can reproduce.

Chris Barber

Yes that is correct. It sounds crazy I know but I asked one of my colleagues to follow my instructions and he had the same results. If you would like me to send you my code let me know.

nicknow

I don’t think it is necessary to send me the code. Can you try a test of adding the missing import line to the project file on VS2012 and see if that works?

I didn’t create the MSBuild.ILMerge.Task tool but I went and looked at the NuGet command it uses and nothing pops out to me that would keep it from working with VS2012.

Chris Barber

I have added the import line to the VS2012 project, cleaned, and rebuilt. There are no errors but it does not merge the dlls.

The reason we are using VS2012 is because this is the version the CRM SDK plugin template is in. The plugin template in 2013 is completely different.

nicknow

Gotcha. I’m not a big fan for Developer Toolkit for Plugin development – it just creates too much dependency. I prefer to use the Command Line Plugin Registration Tool on Codeplex and the Early-bound Generator GUI in XRMToolbox to automate tasks around plugins. Purely personal preference – I know plenty of people smarter than me that swear by the Developer Toolkit.

Sam Alex

Thanks! I split my CRM Plugin Framework into its own assembly so we can use a common framework for all of our plugins, and at least in my first test this worked like a camp! I plan on doing more in-depth testing, but thus far this seems like a win. Using CRM 2013 SP 1 RU 1 and Visual Studio 2013.

Alexander Nosenko

Important notice: DO NOT merge in your plugin Microsoft.Xrm.Sdk if your compile-time SDK version differs from run-time CRM version. MS changed some method signatures in the dll that CRM itself uses without changing the dlll version number. Also, don’t put your Microsoft.Xrm.Sdk in GAC, otherwise you’ll get obscure CRM crash.

Also, there is a new version of MSBuild.ILMerge.Task, so far pre-release 1.0.5-rc1, that is much more flexible about confiuring ILMerge parameters.

nicknow

Thanks, I’ll look into the updated release of MSBuild.ILMerge.Task and update this post!

Balachandar Swaminathan

Hi Nick, thanks for the article. Does this work if the CRM project is on a higher framework .Net 4.5.2 than the external dll (.net 4.0) which am trying to merge. After the merge and build while deploying I get an error “Unresolved assembly reference to Ms.Xrm.Sdk dll”. I hope not, but just wanted to confirm if that’s really the issue I have
Thanks!!

nicknow

If they would work WITHOUT ILMerge then, in most cases, they should work with ILMerge. You can test this in a local instance of CRM by deploying it the bin folder, instead of the DB.

Uday

Hi Nic,

Any fix for this. Am still getting same error.

Thanks
Uday

nicknow

Did you follow my original reply to Balachandar? If it works there then it should work with ILMerge. If it doesn’t than the problem is DLL version compatibility and that has nothing to do with ILMerge.

Rohini Nayak

Hello, I am making API call from my plugin so I added Newtonsoft.Json to the project. I am not able to merger this dll. I am getting following error: Error 1 Unresolved assembly reference not allowed: Newtonsoft.Json. OFACCheck

nicknow

What does OFACCheck mean? What stage of the build process. Can you share the Output window text of the full build process?

Rohini Nayak

I created a crm plugin which makes API call which returns Json object. So I used Json.net to deserialize the Json response. When i deployed the plugin to CRM online sandbox, I threw exception that unable to load Newtonsoft.Json dll. Someone suggested to merger the Newtonsoft.Json with my dll. When I tried merging it threw unresolved assembly.

santhosh Emmadi

hi
i need to integrate dynamics crm with xero. so here i need to add two third party dll into plugin and how can we achieve this.

Emad Hanna

Hi There,

We tried to do this with CRM 2016, does this work with crm 2016(8.0)?

This is the error I get when I try registering the error. (Please see picture)

I have done this with CRM 2016, both on-premise and online. There are several causes for that error – I would do a trace and look at the trace log to get the details of what is causing this error.

Emad Hanna

I got this error when I’m trying to load the Assembly, is there a trace log there?

nicknow

I was talking about the Dynamics CRM tracing capability: https://support.microsoft.com/en-us/kb/907490. If you aren’t familiar with tracing on the CRM server I recommend getting someone to assist you that can do this before proceeding with this blog. This is a more advanced skill-set and presumes a solid knowledge of Dynamics CRM development troubleshooting.

Emad Hanna

I was referring to tracking for CRM online not on premise. How do you trace the registration of a plugin for online?

nicknow

You’ll need to open a support ticket with Microsoft to get the logs.

Uday

Hi Nic,

I have managed to follow the process as per this article and when I build the project am getting this error. Specified merge order file ‘ILMergeOrder.txt’ doesn’t exist.

can you please assist on this.

Thanks

Sam Shiles

This works brilliantly. Thanks for the detailed and precise instructions, saved me a load of time. Cheers