Changing public API of your .NET assembly

Tags: .net, api, assemblies

This was an issue that I recently stumbled upon.

But first a little background.

I was writing a plugin for some specialized CNC software application. The plugin is a class that implements defined interface IPlugin and is contained in its own assembly DLL (we will call it "Plugin" from now) that is dynamically loaded by the application. Application then invokes IPlugin.Execute(...) method which executes plugin.

My Plugin references some other commonly available assembly (call it "Shared Old") that is bound to an application. Of course, when I ship my Plugin assembly, I ship only Plugin's assembly DLLs and all "Shared" assemblies are taken from application dictionary. Nothing fancy, it's all pretty basic stuff.

Everything worked properly until new version of the application came out and it introduced some changes in that "Shared Old" assembly (so after the changes call it "Shared New"). Of course I wasn't aware of the changes and was still using "Shared Old" assembly with my Plugin.

The change in "Shared Old->New" assembly was very subtle and simple. In "Shared Old" there was a function void Foo( byte arg ) which in "Shared New" was changed to void Foo( int arg ). This little change of argument type resulted in application (well, plugin) crash with exception MissingMethodException that took some time to figure out since everything was being done in several threads. One could expect that casting from byte to int in this case should be done automatically, but on the other hand it's clear, that those are totally different methods.

The fix was obvious: I just needed to replace "Shared Old" with "Shared New" in my Plugin solution and just recompile it - without any changes in my plugin's code. And voila, everything works back again. Only if all the fixes were that simple, the world would be a far better place for us developers.

As a side note, there are some cases, when you can get away when you introduce some changes in your public API. For instance, let's say you have a public struct Bar or public class Bar that in assembly version 1 has only one property and this version is being used by plugins or external components. Now, the new version (version 2) of this assembly is shipped with the new version of application, and which now has new property or method. So plugins references version 1 but application now has version 2 of the assembly with enhanced struct/class Bar. But despite that change, everything will still work properly.

I guess the conclusion of this story is: instead of changing things, try adding new things first (and use deprecating Attributes). And if you MUST change them, just be sure to notify consumers of your API.