views:

147

answers:

2
+2  Q: 

Dllhell with .NET

Hi, guys.

Rather than trying to piece out the individual pains I'm dealing with, I want to give the 10 000 feet overview of it. I learn .NET as I go, and I suspect that there is something obvious that I'm missing here. I'm sitting working overtime on a Sunday and I'd really appreciate if someone would toss in their five cents.


Here goes:

Our mainstay product is a process control system. There are many possible ways of extending/customizing the system. We have traditionally separated the control system release from the specific configuration of the Process Plant being controlled so that the two can be maintained seperately.

C:\Control System base release\ (I call this CS$) This is the base release. Bug fixes etc.

C:\Delivery Project\ (I call this Proj$) This is the information of the system being controlled.

A little background:

  • Our service engineers expects to be able to reinstall or upgrade the CS$ folder without loss of customization data.
  • The Delivery project is traditionally deployed by XCOPY.
  • There is some dll-referencing between the two, which works fine in the MFC.
  • On our lab machines, it is common to have many versions installed simultaneously.
  • The system is launched from .bat-files residing in the delivery project that sets up the environment and then launches. The launching process is environment-variable intense.

Now, I experience some difficulties in accommodating this model when using .NET. When the system is using embedded .NET controls or displays a winform, the mscorlib is loaded on demand with CS$\Run\bin being the app base path. This presents me with some problems:

  • .NET assemblies deployed under Proj$ are outside the app base path.
  • .NET assemblies deployed under CS$\Run\bin will be deleted if people reinstall the control system base. I can make deployment part of the batch startup, of course.
  • .NET assemblies paths are provided by textual configuration residing in the Proj$ folder structure. Relative paths within the delivery project is common, but is a problem when they start accessing CS$, which is subject to change.
  • .NET assemblies deployed under CS$\Run\bin may have further dependencies. I may have two different versions of Util1.dll under CS$\run\bin\ext1 and CS$\run\bin\ . This results in CLR not being able to resolve CS$\run\bin\ext1\util1.dll because of the probing path order.
  • I have experimented with seperating appdomains, but instances of classes found in CS$\run\bin\ext1\ext1.dll can number in the hundreds. And I make heavy use of Singletons (static) to coordinate resource management.

Needless to say, I use a lot of Reflector and Fuslogvw. Are there any more tools that I should know of? Is it possible to inspect running processes for the CLR information within them? Since the mscorlib is loaded on demand, I sometimes find that CLR has a app base that is way off. This sometimes prevents my code from being loaded, so I can't access the appdomain programatically or output it to trace.

Is there any way to control the probing path to start relative from the calling assembly before starting from the app base path?

Can mixed mode assemblies in the GAC access MFC resources in CS$?

Although I don't own the MFC code base that loads the mscorlib on demand, I do have a saying in it. Is there something that can be done from there? I am going to request that key information when loading mscorlib is output to trace (as well as exceptions).

Articles, tools or a short description of some aspect I appear to be missing would be appreciated.

I appreciate you taking the time to read this and to maintain a clear head throughout this legacy pain I'm describing here :)

+1  A: 

If .Net's assembly probing logic is not working out for you, you can always extend the CLR host with your own code using IHostAssemblyManager and IHostAssemblyStore. See this blog post or read this book to learn more about that option.

Another option would be to refactor the application to fit .Net's rules instead of forcing .Net to play by your rules. Maybe if you write down the functional demands instead of the technical you might find you can reach the same goals with .Net in another way. Like using the assembly version as part of an assembly's identity, shadow copy, publisher policies, etc.

Lars Truijens
Good stuff. Thank you.I'm still in .NET 1.1, which does not allow me to override before regular probing has tried and failed. I hear you on the refactoring issue, but the problem is that in our control system, .NET is only one of many extensibility points. The separation of project and software is heavily integrated in our distibution and deployment strategies. I may have to exctend the startup scripts to check and, if necessary, redeploy the assemblies if they are missing from the control system base folder as part of the regular startup.
Tormod
+1  A: 

It would have been helpful if you had documented how you solved this problem for your unmanaged assemblies. Options to direct Windows to find an unmanaged DLL are a lot more restricted. Your issue would be simple to solve if you'd install the .NET assemblies to the GAC but that's not very compatible with your deployment strategy.

Anyhoo, you can almost surely solve your problem by implementing the AppDomain.AssemblyResolve event. The CLR will call this when it needs to find an assembly but can't find it by itself. Your code would have to be aware of the locations of the CS$ and Proj$ folders to make this work right.

Hans Passant
Would this allow me to load dependant assemblies that are not located below the app base path nor in the GAC?
Tormod
Yes it does, you can use Assembly.LoadFrom() in the event handler.
Hans Passant