15

I have a project which needs to reference two DLLs with the same name. The DLLs are not strong named, have the same exact name.

I need to access some types within each DLL, but these types have the same fully qualified name. So let's say the first one is companyDLL.dll with someProduct.Type1 and the second one is companyDLL.dll with someProduct.Type1.

How can I access both Type1 classes within the same project?

I have already tried using extern alias, but it requires me to change the name of one of the DLLs.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
varosh
  • 151
  • 1
  • 1
  • 3
  • 8
    This falls squarely into the category of "if you're trying to do this, your design is severely broken." – cdhowie Dec 14 '10 at 23:09
  • Definitely agreed, this is for a tool which needs information from two versions of a company product (built with .NET). But the product in question here is regulated and hence can't be changed. – varosh Dec 15 '10 at 18:55
  • 1
    @cdhowie Not necessarily. There is a wide range of different scenarios involving a conversion between old and new versions, or for example benchmark comparisons. – BartoszKP Aug 29 '18 at 09:59

5 Answers5

12

If your two DLLs have the same name, you are going to have to rename them. Such as Assembly1.dll and Assembly2.dll.

Add these DLLs as a reference in your project as you normally would and in the properties for each reference specify an alias.

in your code when using the DLLs use extern alias to specify what dll you want to reference.

extern alias Assembly1Reference;
using Assembly1Reference::AssemblyNamespace.MyClass;

If you leave it like this, you will most likely get a FileNotFoundException saying that it Could not load file or assembly. To fix this you need to add a ResolveEventHandler that will load the correct assembly you are trying to use. To do this you have to specify exactly where you are storing your DLL files. In the case below, I manually copied the Dll files to the projects debug folder. Where it says "name of assembly1" you can find the name after you reference the DLL, build the project, and open the csproj file with notepad. What to look for will be below my example code.

extern alias Assembly1Reference;
extern alias Assembly2Reference;

static void Load()
{
    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    Do();
}

static void Do()
{
    new Assembly1Reference.Assembly.Class();
    new Assembly2Reference.Assembly.Class();
}

static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string currentPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
    if(args.Name == "Name of assembly1")//Found in csproj file after referenced and built
    {
        return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(currentPath, "Assembly1.dll"));
    }
    if(args.Name == "Name of assembly2")//Found in csproj file after referenced and built
    {
        return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(currentPath, "Assembly2.dll"));
    }
    return null;
}

As promised, here is what a reference looks like in the csproj file. The name is everything inside the include attribute.

<Reference Include="MyAssembly_3.6.2.0, Version=3.6.2.0, Culture=neutral, PublicKeyToken=12341234asdafs43, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>Resources\Assembly1.dll</HintPath>
      <Aliases>Assembly1Reference</Aliases>
</Reference>

I know this is late but hopefully it will help anyone coming to this page from now on.

Jordan Rhode
  • 169
  • 1
  • 5
  • This is useful and I could make this work this partially but I have following questions. What is the purpose of this? `static void Do() { new Assembly1Reference.Assembly.Class(); new Assembly2Reference.Assembly.Class(); }` Also what is the advantage of resolving the assemblies via code rather than via app.config like [this](https://stackoverflow.com/a/3163050/431561). In my case, always the latest version of the assembly is getting loaded. What should I do to load the exact dll of the particular renamed assembly. – Rajaraman Subramanian Feb 20 '18 at 12:45
3

Using extern alias to bring the assemblies in with different namespaces. If you can differenciate the namespace, you should be able to use using altType1 = someProduct.Type1 to create a local alias for the type.

First qualify the assemblies from the command line:

/r:ProductA=companyDLLA.dll
/r:ProductB=companyDLLB.dll

Then reference them using extern alias:

extern alias productA;
extern alias productB;

Finally you can alias the local types:

using productTypeA = productA.Type1;
using productTypeB = productB.Type1;
Greg Buehler
  • 3,897
  • 3
  • 32
  • 39
  • unfortunately for me, the two dlls have the same name.i.e./r:ProductA=companyDLLA.dll /r:ProductB=companyDLLA.dll – varosh Dec 15 '10 at 18:55
  • is there a reason you cannot rename the DLL? If I were in your situation, I would attempt renaming them `companyDLLv1.dll` and companyDLLv2.dll`. – Greg Buehler Dec 15 '10 at 21:09
  • Yes, the DLLs cannot be renamed. The DLLs in question here are regulated and cannot be changed without going through an official approval process (which is out of question for my scenario) – varosh Dec 16 '10 at 02:22
0

I can think of two ways to handle this.

  1. load each DLL into a separate AppDomain. You'll have to make calls across the AppDomain boundary to tickle the various properties and methods.

  2. before loading the assemblies, disassemble and then re-assemble each assembly and put them into unique (maybe dynamically generated) namespaces. There are tools that can help with this (1) (2). You could potentially automate it.

But my base feeling is, you really shouldn't be doing this. It's easier to solve this problem upstream, than it is to solve it after you already have compiled assemblies.

Cheeso
  • 189,189
  • 101
  • 473
  • 713
0

None of the proposed solutions worked for me. I had to recompile the DLLs and give them different identity, i.e. change "Assembly name" in project settings.

If you are unable the recompile the DLLs, another solution would be to create wrappers with suitable names.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
0

When I came across this problem I created two different wrapper projects, each referencing different version of the dlls, and used the Costura.Fody nuget in order to embed the dlls into the wrapper projects and prevent clashes in builds.

Yuval Perelman
  • 4,499
  • 1
  • 22
  • 32