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...
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.
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.
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.
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.
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:
Add reference to assembly A to your project C, set SpecificVersion = true;
Add reference to assembly B version 1.1.39.0 to your project C, set SpecificVersion = true;
Create a post build event that copies version 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!
Related
I am using both ExcelDataReader.Mapping - 2.2.2 and ExcelMapper - 5.2.429 nuget packages in a project. I know it seems redundant, however, one of these projects gives a little more flexibility that I need when reading excel files. It seems there is some conflict between namespaces and classes between these two projects. To fix that, I have ExcelDataReader.Mapping aliased as ExcelReader and ExcelMapper as ExcelWriter. This worked briefly, but now I am running into another issue.
I get the following message on build of the project: warning MSB3243: No way to resolve conflict between "ExcelMapper, Version=5.0.0.0, Culture=neutral, PublicKeyToken=6c3f2bec99465df3" and "ExcelMapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null". Choosing "ExcelMapper, Version=5.0.0.0, Culture=neutral, PublicKeyToken=6c3f2bec99465df3" arbitrarily.
Using the diagnostic build, I also see this error: Encountered conflict between 'Runtime:C:..\.nuget\packages\exceldatareader.mapping\2.2.2\lib\netstandard2.0\ExcelMapper.dll' and 'Runtime:C:..\.nuget\packages\excelmapper\5.2.429\lib\netstandard2.0\ExcelMapper.dll'. Choosing 'Runtime:C:..\.nuget\packages\excelmapper\5.2.429\lib\netstandard2.0\ExcelMapper.dll' because AssemblyVersion '5.0.0.0' is greater than '1.0.0.0'.
It appears they are using the same name for the .dll file, so it is causing some confusion as to which one it should use. Is there a way to change the .dll file name when installing packages? Or some way to register a full path when referencing the .dll file?
If I:
Create a new C# query in LINQPad 6.
Add the System.ServiceModel.Http NuGet package or another package that references it.
Try to instantiate a class from the System.ServiceModel namespace, for example System.ServiceModel.BasicHttpBinding.
Leading to the following .linq file:
<Query Kind="Expression">
<NuGetReference>System.ServiceModel.Http</NuGetReference>
</Query>
new System.ServiceModel.BasicHttpBinding()
Then I get a compile error:
CS0433 The type 'BasicHttpBinding' exists in both 'System.Private.ServiceModel, Version=4.7.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' and 'System.ServiceModel.Http, Version=4.7.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
If I create a project in Visual Studio and add the same NuGet package and code, I do not get this error.
According to the C# Language reference for the error, it should be possible to resolve by using the -reference compiler option or by not referencing one of the assemblies. However, I can't seem to find a way to use this compiler option in LINQPad, nor can I find any way to remove the assembly reference to System.Private.ServiceModel.
How can I fix the error?
This is a bug in LINQPad, triggered by an obscure scenario. The System.Private.ServiceModel package contains a lib folder with an assembly which is required at runtime, and a ref folder with a underscore.underscore file which indicates that no assemblies should be referenced by the compiler. Because LINQPad finds no reference assemblies, it feeds the compiler the assembly in the lib folder, which causes the error.
I've got a fix ready and regression tests are currently running. The fix will likely make it into the 6.11.2 beta build, which should be released in a day or two.
I need to debug SharpDX to understand what is going on in my app - my project uses it via a reference from another NuGet package. Since the first package is referencing it with a PublicKeyToken even though I have built the same version of SharpDX and switched the SharpDX reference from NuGet to the local assemblies, my project wont build since it seems that it wants a signed version of SharpDX. The error message I am getting during the build is:
Error CS0012: The type 'TextLayout' is defined in an assembly that is not referenced. You must add a reference to assembly 'SharpDX.Direct2D1, Version=3.1.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1'.
I have built this assembly with the same version (3.1.1.0) but I have not sign it (and I assume I cannot do this since the repo does not contain the key file).
Is there any way around this how I can make the NuGet package that references SharpDX load the locally built assemblies?
I found this and tried to turn off the strong name validation for that public key token, leave the references in tact (the project still references the SharpDX NuGet package) and replace the binaries and then run the application. It still fails at runtime with:
Message:Could not load file or assembly 'SharpDX.Direct2D1, Version=3.1.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
But this did not match the explicit error about the strong name given in the link. To verify the version I opened the build assembly with ildasm and the version is in tact:
One of our build agent servers does not have System.Data.SqlXml Version=2.0.0.0 under C:\Windows\assembly but every other machine we have does. Unfortunately this causes nunit-summary.exe on that box to fail with:
EXEC Could not load file or assembly 'System.Data.SqlXml,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or
one of its dependencies. The system cannot find the file specified.
error MSB3073: The command ""../tools/nunit-summary.exe" artifacts/Test_*.xml" exited with code -1.
I tried installing MSXML 4 to no avail. I have not been able to figure out how to install version 2, any ideas?
Two possible solutions.
a) In the project, expand references to find the reference to the library. Go to properies and set Copy Local to be True. The .dll will then be included in the bin folder when the project is built.
b) Install SQLXML from Microsoft (this is different to MSXML which you tried). Details about the library (including the download link) are available at https://learn.microsoft.com/en-us/sql/relational-databases/sqlxml/what-s-new-in-sqlxml-4-0-sp1
I am using Xamarin on a Mac and have built up a series of .netstandard1.3 libraries. One of which is referencing a few external packages:
NETStandard.Library
Newtonsoft.Json
System.Linq.Queryable
System.Reactive
System.Security.Principal
When I build the project (library) it builds but with the following warning:
/Library/Frameworks/Mono.framework/Versions/4.8.1/lib/mono/xbuild/14.0/bin/Microsoft.CSharp.targets (CoreCompile target) ->
CSC: warning CS1702: Assuming assembly reference
System.Runtime.Serialization.Primitives, Version=4.1.1.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' matches assembly
System.Runtime.Serialization.Primitives, Version=4.1.1.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
You may need to supply runtime policy
I'm not directly referencing this specific library anywhere, but even if I were the version and public key token appear to be identical so why the complaint? How do I get rid of this warning and why am I getting it?
Despite having the same assembly identity, there are different implementations of System.Runtime.Serialization.Primitives.dll presumably because of runtime specific behavior / implementation. MSBuild is not sure which to use. You may target your library to multiple runtimes, or distribute it as a NuGet package which shifts the responsibility of picking a target runtime to the library or app consuming your package. You can download the package, change it to a .zip and take a peak inside to see what I mean.