Reputation: 1641
I'm getting the following error when I try and compile a utility, which uses files that have been deployed to our client.
Assembly '*A* version 2.0.1.2' uses '*B* version 1.1.39.0' which has a higher version than referenced assembly '*B* version 1.1.32.0'.
Our client can use these DLLs no problem, because we have a binding redirection config file in place, which takes effect at run-time:
<dependentAssembly>
<assemblyIdentity name="*B*" publicKeyToken="..." culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-65535.65535.65535.65535" newVersion="1.1.32.0" />
</dependentAssembly>
To give a bit of background, the DLLs exist in separate solutions, and therefore some of the references are file references rather than project references, just something I have to live with!
Is there any equivalent binding redirection that applies at compile time?
I've tried compiling using debug DLLs (version 1.0.0.0), with source rolled back to the relevant version above, however I get the following error at run-time:
The located assembly's manifest definition does not match the assembly reference
Maybe the build server is configured differently to my machine, but anyway that didn't seem to work...
Upvotes: 13
Views: 5185
Reputation: 61007
You can get around the compiler error by making sure that you wrap the types from assembly A in a way that they are not visible outside of assembly B you can then depend on assembly B, use A through B and use an bindingRedirect
to make sure that assembly A loads the correct DLL version. Your mileage will vary, but it does work.
Upvotes: 0
Reputation: 941635
This is a very common mishap. Nuget packages are the most likely troublemakers, log4net and NewtonSoft.Json are on the top of that list. Modern versions of MSBuild know how to resolve that. Something you can see when you use Tools > Options > Projects and Solutions > Build and Run > MSBuild project build output verbosity = Detailed.
I'll show what it looks like on VS2015, reproducing your exact problem scenario. It starts to get interesting at the ResolveAssemblyReference task:
1>Task "ResolveAssemblyReference"
...
1> Primary reference "B, Version=1.1.32.0, Culture=neutral, PublicKeyToken=null".
1> Resolved file path is "c:\projects2\BCopy\bin\Debug\B.dll".
1> Reference found at search path location "{HintPathFromItem}".
1> Found related file "c:\projects2\BCopy\bin\Debug\B.pdb".
1> The ImageRuntimeVersion for this reference is "v4.0.30319".
1> Primary reference "A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null".
1> Resolved file path is "c:\projects2\A\bin\Debug\A.dll".
1> Reference found at search path location "{HintPathFromItem}".
1> Found related file "c:\projects2\A\bin\Debug\A.pdb".
1> The ImageRuntimeVersion for this reference is "v4.0.30319".
And a bunch more for .NET Framework assemblies. Towards the end of the task it notices that A has a dependency on a new version of B:
1> Dependency "B, Version=1.1.39.0, Culture=neutral, PublicKeyToken=null".
1> Resolved file path is "c:\projects2\B\bin\Debug\B.dll".
1> Reference found at search path location "c:\projects2\B\bin\Debug".
1> For SearchPath "c:\projects2\B\bin\Debug".
1> Considered "c:\projects2\B\bin\Debug\B.winmd", but it didn't exist.
1> Required by "A, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL".
1> Found related file "c:\projects2\B\bin\Debug\B.pdb".
1> This reference is not "CopyLocal" because it conflicted with another reference with the same name and lost the conflict.
1> The ImageRuntimeVersion for this reference is "v4.0.30319".
1> There was a conflict between "B, Version=1.1.32.0, Culture=neutral, PublicKeyToken=null" and "B, Version=1.1.39.0, Culture=neutral, PublicKeyToken=null".
1> "B, Version=1.1.32.0, Culture=neutral, PublicKeyToken=null" was chosen because it was primary and "B, Version=1.1.39.0, Culture=neutral, PublicKeyToken=null" was not.
1> References which depend on "B, Version=1.1.32.0, Culture=neutral, PublicKeyToken=null" [c:\projects2\BCopy\bin\Debug\B.dll].
1> c:\projects2\BCopy\bin\Debug\B.dll
1> Project file item includes which caused reference "c:\projects2\BCopy\bin\Debug\B.dll".
1> B, Version=1.1.39.0, Culture=neutral, processorArchitecture=MSIL
1> References which depend on "B, Version=1.1.39.0, Culture=neutral, PublicKeyToken=null" [c:\projects2\B\bin\Debug\B.dll].
1> c:\projects2\A\bin\Debug\A.dll
1> Project file item includes which caused reference "c:\projects2\A\bin\Debug\A.dll".
1> A, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL
1>Done executing task "ResolveAssemblyReference".
Note how it tries to decide whether to use version 1.1.32.0 or 1.1.39.0. It likes the old version better since it is the "primary reference". In other words, your project references it and the 1.1.39.0 is less important because it is an indirect reference from A.
The project builds clean, no complaint whatsoever. Why this doesn't work for you is entirely unclear, pretty important to name your VS version. I can't remember exactly when this feature was added, it was a while ago. Somewhere around VS2010 or VS2012.
So try to get ahead by comparing the build trace you get on your machine with what I posted. If it is just a plain old VS version problem then you'll be of course be much ahead by updating it.
Upvotes: 7
Reputation: 7017
If I understand you correctly, you have legacy assembly A
that references specific version of assembly B
. At the same time you are building utility C
which uses both assemblies - A
and B
.
You should be able to use two different versions of the same assembly B
by following steps. Not a compile time redirection, but it should work:
A
to your project C
, set SpecificVersion = true
;B
version 1.1.39.0
to your project C
, set SpecificVersion = true
;1.1.39.0
of assembly B
to project output path /bin/B_1.1.39.0/B.dll
;Add following binding redirects and specify custom location for assembly B
with version 1.1.39.0
using codeBase
element;
Now your legacy assembly A
should be happy as you have version 1.1.32.0
of assembly B
in your output folder. Your utility C
should be happy as well as it using specific version 1.1.39.0
of assembly B
and you have provided custom location where to look for it.
Hope it helps!
Upvotes: -1
Reputation: 56869
The answer to your inquiry is no, there is no way to do binding redirects at compile time. At that point, it is assumed that you can update all of the project references to the same version (or had done so before checking in to source control), so the build should go without a hitch.
However, you are here for a solution, so I will make a suggestion. One possible way to ease this pain is to package each one of your "separate DLL solutions" into NuGet packages. You don't have to publish them on the NuGet gallery, you can instead use a specialized NuGet feed (such as MyGet) or even host your own. Once you have the files in a feed, it is a bit easier to manage getting the right version into a project.
The main advantage of using NuGet is that you don't need to check the binaries into source control, so they won't get out of sync with the version number that is referenced in the .csproj
or .vbproj
file. If set up with NuGet package restore, the right verision of each of the packages will be automatically installed when you compile, and is thus guaranteed to build the same way regardless of the machine that builds it.
You might also consider consolidating some of the separate solutions into a single solution/build process to synchronize the version numbers/binaries between NuGet pacakges so it is easy to tell if one of the versions is lagging behind the others (and thus needs to be updated before checking in).
Of course, NuGet isn't perfect and takes a bit of effort to setup and even then you may still have some issues keeping versions in sync, but updating them to the right version is considerably easier.
Upvotes: 0
Reputation: 101483
I doubt it's possible to "fix" it as you want to. If you read documentation for that compile error (https://msdn.microsoft.com/en-us/library/416tef0c.aspx), you will see that you can either update code to use the same version, or reference both versions during compilation (not an option in your case).
Imagine, that version 1.0.0.0 contains method MyMethod(), but version 1.0.0.1 contains MyMethod(string), and first version is used by assembly A, second version is used by assembly you are compiling. How do you want compiler to resolve this? In runtime, when you use binding redirection, only one version of assembly will be loaded still. Here, you do not own code for assembly A (which you are refering to, and which in turn references MyMethod), and reference to assembly 1.0.0.0 is embedded in A's manifest.
Long story short - I suppose only way to solve it for you is use assembly A which references the same version of B as you do.
Upvotes: 8