Deploying .NET assemblies to clients and servers in need is no simple affair. In my last post I have explained the problem, and announced the solution.
As promised, in this post I bring you the solution.
To be fully honest, this post only brings the conceptual solution, just a little brain game for you to train your .NET brain muscles a bit. The actual code I’ll deliver in the next post.
Let me start by explaining some theory.
In .NET, assemblies are loaded automatically by .NET runtime. However, for an assembly to be loaded, it must reside either in the Global Assembly Cache (GAC), or in the same directory as the executable that’s attempting to load it. The same directory means exactly that – the same directory, not one directory up or down, or in any system directory or whatever. Same directory.
What happens if an executable attempts to load an assembly, and the assembly does not exist in either GAC or the executable’s directory?
If you say: an error happens, then you are wrong.
When .NET runtime cannot find a required assembly, it raises an event in the application that requested the assembly (more precise, in the application domain that requested it). This event is called AssemblyResolve, and it allows the application to load the assembly from somewhere where .NET framework might not look itself, but the application may expect the assembly to be. This is exactly how NAV knows to look into Add-ins subfolder, and not in some other random folder.
Very nice, this .NET guy, isn’t it?
Yes, and it’s also nice about something else – in .NET events are not one on one, like in C/AL (one event can have exactly one event trigger) but one to many: one event can have many subscribers, and all of these subscribers will be called when event is raised.
So, when an assembly cannot be found, .NET will keep firing the events until one of them returns the resolved assembly. If NAV cannot find the assembly in the Add-ins, .NET may not give up just yet.
In theory, if you could supply an AssemblyResolve event yourself, you could be able to provide the assembly to the .NET Framework even if NAV wasn’t able to locate it itself, and NAV will still happily use it, because it was successfully resolved and loaded by the application domain.
So, can you do this? Well, no, and yes.
If you attempt to subscribe to the AssemblyResolve event of the AppDomain directly from C/AL you’ll soon learn that C/AL does not support .NET events that have a return value. So, the only way to do this is to create your own assembly, add a class to it that subscribes to the AssemblyResolve event, and then either pre-feed it with assemblies, or have it raise a simple C/AL compatible event and notify C/AL when an assembly cannot be resolved.
Finally, last piece of theory is about loading assemblies. In .NET, an assembly can be loaded from file, but also from a byte array. This means that the assembly does not need to be physically present on the disk – it can, for example, be stored in a BLOB field in the database, and then streamed into a byte array, and then loaded dynamically from there. Regardless of how exactly you got your assembly (from file, or from byte array), .NET framework (for all practical purposes as far as NAV goes) does not care.
This means that with that little assembly that subscribes to AssemblyResolve event you could read an assembly from the database, on demand, and provide it to .NET runtime to use and abuse.
And that’s it. With this simple concept and little .NET theory applied to NAV practice, you can solve your DLL hell. Simply upload all your assemblies to the database, and have your assembly resolver take care of the rest.
No worries – I don’t stop here! As promised, I’ll deliver the code as well, just not in this post. I want to tease you a bit, maybe motivate you to attempt to do all this yourself to get a little practice in .NET and learn yourself about possibilities and limitations and how to overcome them.
And then, in my next post I show you my solution. And let me tell you – it won’t be anything like what you thought it would be. It’ll blow your socks off, I’m pretty sure of that. See you tomorrow!