Reopened: Conflicting DLL versions in multiple modules causing exceptions..is there a workaround for this

Topics: Writing modules
May 25, 2012 at 9:02 AM
Edited May 28, 2012 at 10:19 AM

*An Update - I had thought that by using the extern alias that I had things working properly. It turned out that it doesn't help

*Attention gurus*

I've posted something similar a while back, but now I'm running into a pretty serious roadblock as a result of this issue

http://orchard.codeplex.com/workitem/18266

I've got a module which we've written that uses the latest Facebook Dlls (6.0.16)

However, another team member has been implementing our authentication services which uses the NGM.OpenAuthentication project. The NGM.OpenAuthentication uses Facebook.dll (5.0.9.0)

Now that's this code has been combined with our facebook module, we're running in a situation where the NGM.OpenAuthentication is always loaded before our module so the facebook dll in the Orchard.Web\App_Data\Dependencies folder is always the (5.0.9.0) version which breaks our module. 

Now I know I could probably update the NGM module to use new facebook library, but I'd like to avoid modifying 3rd part components whenever possible.

Also note that I rean into a very similar problem 3 weeks ago where the NGM module uses an older version of Newtonsoft.Json. Were able to work around this one by lowering our requirement and using the old version of the dll as well, but in the case of facebook, we need to use the new dll.

Is there some other way to "force" Orchard to use or load a particular version of the same dll?

 

Given that I've ran into this twice in the last month, I imagine others will run into something similar.

Any Suggestions or Workarounds aside from renaming my module or modifying the NGM code?

Any updates on the status of the open work item?

Thanks.

Ryan

 

May 25, 2012 at 9:46 AM
Edited May 28, 2012 at 10:20 AM

An Update: This was found to be incorrect

Some good news. I figured out a workaround that I can live with I think. It is still an issue, but I think this workaround will suffice.

 

Using the information in this article http://blogs.msdn.com/b/abhinaba/archive/2005/11/30/498278.aspx

I found that I was able to load both facebook dlls but because of how Orchard works, I had to make the following changes.

  • I renamed my Facebook.dll to Facebook.6.0.16.dll and added the reference to my project
  • Then I right clicked on the reference in my project and changed the Alias to "facebook6016" from "global"
  • Then in my code I had to add an extern alias to facebook6016 and then was able to use it by using the alias syntax facebook6016::Facebook.FacebookClient()

Phew. That's a bit of a relief. I think I'm going to use this technique from now on whenever I use external 3rd party dlls. 

Hope this helps.

Ryan

May 28, 2012 at 10:35 AM

So Unfortunately, the fix that I had thought was working in my last post is not actually helping at all. I had a reference to the original (not renamed) Facebook.dll in another module and that assembly was being used instead of the renamed one. I also investigated some more and found that you can't actually rename a .NET Dll because the Dll itself contains information about the module and it's name. 

Back to square one. 

The issue seems to be that the ExtensionLoaderCoordinator loads the modules and their references without considering newer versions of the dll it simply matches on the reference name so I could have a facebook.dll loaded in some other module that will always get used here because the reference name is the same. I'm sure the resolution isn't that simple as you'd probably need to create a subfolder or something to store duplicate dlls with different versions. Perhaps there could be a way in the Module.txt file or somewhere to specify whether your module should always contain specific versions of references. 


     private void ProcessExtensionReference(ExtensionLoadingContext context,
            ExtensionProbeEntry activatedExtension,
            string referenceName,
            IList<DependencyReferenceDescriptor> activatedReferences) {

            // If the reference is an extension has been processed already, use the same loader as 
            // that extension, since a given extension should be loaded with a unique loader for the 
            // whole application
            var bestExtensionReference = context.ProcessedExtensions.ContainsKey(referenceName) ?
                context.ProcessedExtensions[referenceName] :
                null;

Any suggestions please?  It's basically making it impossible to add modules that have older versions of dlls that we use without modifying 3rd party module code....unless I'm missing something here...

Thanks.

Ryan

 

 

 

 

Coordinator
May 29, 2012 at 6:30 AM

All modules need to use the latest version of their dependencies. You'll have to upgrade those that don't.

May 29, 2012 at 8:42 AM

I can understand that all modules that we write should use the same dependencies and versions, but how do you control which version of a dll that a 3rd party uses now or in the future. More importantly, the gallery does not indicate anything about what versions of dependencies are used so a customer would be taking a big gamble by installing anything from the gallery. Even if the module installs properly from the gallery, depending on how it's named and loaded, an old dll could be loaded into the dependencies folder (before the new one) which would likely break any of the "previously working" modules that depend on the newer version of the dll (which is exactly what we've run into twice with NGM OpenAuthentication).  It's also a real pain to debug or diagnose these issues. We're about to go into production with our custom solution built on Orchard, and at the moment I have to have to tell our customers that they can't install any new modules from the gallery unless our team validates that it can be used.  Is there any plans to address this? It will have a significant impact on how we talk about our solution, Orchard and how customers can customize it.

R.

Coordinator
May 30, 2012 at 7:05 AM

You can't. That's the price to pay for a comparatively simple dependency mechanism. It hasn't been a big issue so far for the vast majority of users.

May 30, 2012 at 7:54 AM

 Well not to belabor the point, but I'm wondering if adding new components using the Orchard gallery meant primarily for developers? ...Or is it intended to target the average site-admin end user (non-developer).  I would imagine that most people working with Orchard at the moment are pretty technical given how new Orchard is which could be why most people either haven't run into this problem or aren't complaining.  While I do like the simple dependency mechanism, the fact that you can cause your site to stop working entirely just by installing a module make me think that it's a matter of time before module incompatibility does become a major issue especially with the non-developers. I'm thinking primarily about our target customers who are sysadmin types.

Perhaps some kind of an extension module that checks for compatibility of dependencies against the currently installed features and fails gracefully and/or warns the user before starting the installation would be something worth looking at. Do you think that's possible? (if so any suggestions on what I'd need to hook into). Related to this (I think), I'm not 100% clear on the order that modules/extensions are loaded but it appears that all modules are loaded in alphabetical order whether they are active or not.  I'm wondering if it's possible to change the order of the dependency processing so that the Active modules are processed before the Inactive modules so that an inactive module doesn't interfere with modules that are active. Or even better, only the Active modules are loaded into the dependencies folder and the inactive ones have their dependencies loaded only when they become active... This way a module with incompatible references could still be on the server but not causing problems with the modules that are installed, and it would be possible to inject some code during the activation process to check for compatibility...

For example

I have MyModuleA , and MyModuleB installed which both use facebook.dll (v6.0.1)

I go to the gallery and want to install BobsModule which uses facebook.dll (v5.4) before it does anything, it could check to see if the facebook.dll version is the same as what's currently in the dependencies folder. If there is a difference, the user could be warned

"BobsModule uses facebook.dll version 5.4 which is different than what is currently loaded into Orchard (facebook.dll 6.0.1) do you want to proceed? This may cause problems with your site. 

Thoughts? If I wanted to play with something like this do you have any suggestions on an approach?

Coordinator
May 30, 2012 at 6:18 PM

You are describing dll hell. There is unfortunately no perfect solution to this problem, although many people have tried for dozens of years. We went for simplicity, which has its own issues, you are recommending stricter binding, which comes with its own issues as well.

Developer
May 30, 2012 at 10:06 PM

That's why I created the Facebook SDK module. In its description there are two related discussions linked.

May 31, 2012 at 9:51 AM
Edited May 31, 2012 at 9:53 AM

Thanks Piedone. The thread http://orchard.codeplex.com/discussions/270586  helped me to understand the reasoning and some of the dialog that has already occurred around managing dlls.  Fundamentally, I understand why the Orchard team wants to encourage people to collaborate on and centralize their dependencies. Unfortunately I don't think all module developers are thinking that way at the moment (I know nobody on my team was until today). I will be encouraging my team to use modules for all external Dlls and in some cases where we have a conflict we'll try using Piedones solution.

 

Gracias

 


Developer
May 31, 2012 at 10:02 AM

I think centralized dependencies is the best, although no perfect solution we can use at the moment. If Orchard gets even better module handling (e.g. automatically installing dependencies with specific version) this will get easier to maintain.