Why are there Different versions info for the same DLL? - c#

I recently had my first encounter with Could not use file or assembly version issue. And I had some understanding How and Why assemblyBinding>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="4.1.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
But I am still not sure about the usage of other versions info?
Q:- what is the use of Runtime version(red box), the File Version(yellow box) and any other use of Green box?
Noob Q:- Why can't we have one unique version for each DLL?

what is the use of Runtime version(red box)
This is the runtime that will be used by this reference. This will always be 4.0.30319 for .Net 4.8 references, and any other .Net framework 4.x reference. Since .Net framework 3.x and earlier is uncommon these days I do not think this is very useful anymore. I do not think this is even displayed for .Net standard/core projects.
the File Version(yellow box) and any other use of Green box
The file version, product version, and version in the reference box, all uses different fields in the file. So there is nothing that says they have to be the same. But if you just create a regular library project and build a dll, the compiler should set all of them to the same value. It is usually fairly simple with pure .Net dlls, but other types of dlls can have different versioning practices to make things more complicated.
Why can't we have one unique version for each DLL?
I'm not sure what exactly you mean by this. But versioning is difficult. A common problem occur when libraries use different versions of a third library. It is possible the two versions are different in some regards, and any way you can handle this risks breaking something.
I would recommend reading John Skeet's article on Options for .NET’s versioning issues for better insight into the potential problems.

Related

Google.Apis version doesn't work with newer version of Newtonsoft.Json [duplicate]

This is not a problem question but a general understanding question on assembly binding redirect's working.
Queries
Why binding redirect shows only major version and not minor, build and revision numbers?
Does old and new version change only when there is change in major version?
<dependentAssembly>
<assemblyIdentity name="FooBar"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<bindingRedirect oldVersion="7.0.0.0" newVersion="8.0.0.0" />
</dependentAssembly>
Why are binding redirects needed at all? Suppose you have application A that references library B, and also library C of version 1.1.2.5. Library B in turn also references library C, but of version 1.1.1.0. Now we have a conflict, because you cannot load different versions of the same assembly at runtime. To resolve this conflict you might use binding redirect, usually to the new version (but can be to the old too). You do that by adding the following to app.config file of application A, under configuration > runtime > assemblyBinding section (see here for an example of full config file):
<dependentAssembly>
<assemblyIdentity name="C"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<bindingRedirect oldVersion="1.1.1.0" newVersion="1.1.2.5" />
</dependentAssembly>
You can also specify a range of versions to map:
<bindingRedirect oldVersion="0.0.0.0-1.1.1.0" newVersion="1.1.2.5" />
Now library B, which was compiled with reference to C of version 1.1.1.0 will use C of version 1.1.2.5 at runtime. Of course, you better ensure that library C is backwards compatible or this might lead to unexpected results.
You can redirect any versions of libraries, not just major ones.
We came across an issue with binding redirect for NewtonSoft.Json. We looked up the file version in win 10 file properties "9.0.1.19813", looked up the number and the redirect kept failing. Further investigation and found that we were looking at file version and not assembly version. So, I wonder if people are mistaking File Version (which changes often) and Assembly version (which you can't see in windows 10 File Explorer). To see the Assembly version of a dll you can run this in powershell. Replace the dll name with the one you want to find version for.
[Reflection.AssemblyName]::GetAssemblyName('C:\development\bin\Newtonsoft.Json.dll').Version
The result of above is.
Major Minor Build Revision
----- ----- ----- --------
9 0 0 0
See References:
How can i see the assembly version of a .NET assembly in Windows Vista and newer (WIndows 7, 2008)?
https://support.microsoft.com/en-nz/help/556041

Assembly Binding redirect: How and Why?

This is not a problem question but a general understanding question on assembly binding redirect's working.
Queries
Why binding redirect shows only major version and not minor, build and revision numbers?
Does old and new version change only when there is change in major version?
<dependentAssembly>
<assemblyIdentity name="FooBar"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<bindingRedirect oldVersion="7.0.0.0" newVersion="8.0.0.0" />
</dependentAssembly>
Why are binding redirects needed at all? Suppose you have application A that references library B, and also library C of version 1.1.2.5. Library B in turn also references library C, but of version 1.1.1.0. Now we have a conflict, because you cannot load different versions of the same assembly at runtime. To resolve this conflict you might use binding redirect, usually to the new version (but can be to the old too). You do that by adding the following to app.config file of application A, under configuration > runtime > assemblyBinding section (see here for an example of full config file):
<dependentAssembly>
<assemblyIdentity name="C"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<bindingRedirect oldVersion="1.1.1.0" newVersion="1.1.2.5" />
</dependentAssembly>
You can also specify a range of versions to map:
<bindingRedirect oldVersion="0.0.0.0-1.1.1.0" newVersion="1.1.2.5" />
Now library B, which was compiled with reference to C of version 1.1.1.0 will use C of version 1.1.2.5 at runtime. Of course, you better ensure that library C is backwards compatible or this might lead to unexpected results.
You can redirect any versions of libraries, not just major ones.
We came across an issue with binding redirect for NewtonSoft.Json. We looked up the file version in win 10 file properties "9.0.1.19813", looked up the number and the redirect kept failing. Further investigation and found that we were looking at file version and not assembly version. So, I wonder if people are mistaking File Version (which changes often) and Assembly version (which you can't see in windows 10 File Explorer). To see the Assembly version of a dll you can run this in powershell. Replace the dll name with the one you want to find version for.
[Reflection.AssemblyName]::GetAssemblyName('C:\development\bin\Newtonsoft.Json.dll').Version
The result of above is.
Major Minor Build Revision
----- ----- ----- --------
9 0 0 0
See References:
How can i see the assembly version of a .NET assembly in Windows Vista and newer (WIndows 7, 2008)?
https://support.microsoft.com/en-nz/help/556041

Transitive Dependency causing Conflicting version of same DLL

What is the best practice in the .NET world to manage transitive dependencies that cause version conflict ?
In details :
Project A Depends on Project B which in turn depends on library C
also
Project A also depends on Project X which depends on a DIFFERENT and (potentially) incompatible version of library C.
A->B->Cv1.0
&
A->X->Cv2.0
where Cv1.0 <> Cv2.0
Is there a way to make this work ?
Can it be done WITHOUT using the GAC ?
Can it be done even if B and X are in binary format only (source not accessible) ?
In other words is there a way where I can have Project B and X each using their own dependencies when used together in Project A without causing conflicts.
NOTE: I realize that ideally I should not have this problem at all but as reliance on external libraries expands this will be an unavoidable side effect. So I am wondering should it occur how best to deal with it.
There are a lot of similar questions On Stack Overflow.
For e.g. Referencing 2 different versions of log4net in the same solution
Summary:
Ensure that you deploy the assembly C in folders 1.0 and 2.0 respectively within the folder containing the main executable.
Change app.config file and include something like following:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="C" publicKeyToken="C's public key token" />
<codeBase version="version string for C1.0 e.g. 1.0.0.0" href="1.0\C.dll" />
<codeBase version="version string for C2.0 e.g. 2.0.0.0" href="2.0\C.dll" />
</assemblyIdentity>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
you can get the public key token of C using sn -T C.dll
If v1.0 and v2.0 of C have different public key (though ideally they shouldn't) then include two dependentAssembly tags.

Unit testing c# code in a ScriptSharp project

Im using ScriptSharp to create a RIA app.
Works nice besides some oddities.
However finding and fixing problems using Firebug isn't really convinient.
Since scriptsharp also delivers a Dll I was hoping to use a separate testproject using Nunit to test some parts of my code.
Issue that arises is that the generated dll references mscorlib 0.7 resulting in conflict with mscorlib 4 in the test project.
A simple solution is to create a second plain C# project and copy codefiles around. But maintaining 2 projects with the same code base...
Curious if there is another way to do this. Anybody?
EDIT:
Solution as proposed by Christian Dalager works.
Small thing is that ScriptSharp has redefined System.Diagnostics in mscorlib. No more Debug.Assert/Writeline. But there is almost no more need for it now.
You might try using assembly binding redirects
You would put something like this in the app.config on your testproject.
Havent tested this particular configuration, so you will need to adjust it.
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" appliesTo="v1.0.3705">
<dependentAssembly>
<assemblyIdentity name="mscorlib" publicKeyToken="b77a5c561934e089" culture="neutral"/>
<bindingRedirect oldVersion="0.7.0.0" newVersion="4.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

Referencing different versions of the same assembly

If A references assembly B 1.1 and C, and C references B 1.2, how do you avoid assembly conflicts?
I nievely assumed C's references would be encapsulated away and would not cause any problems, but it appears all the dll's are copied to the bin, which is where the problem occurs.
I understand the two ways around this are to use the GAC or assembly bindings? The GAC doesn't seem like the best approach to me, as I don't like assuming dlls will be there, I prefer to reference dlls from a lib directory in my solution.
Where as assembly bindings don't seem robust to me, what if one version of the assembly has functionality that the other doesn't, will this not produce problems?
In my case its because I'm using a 3rd party dll uses a older version of nHibernate, than I'm using myself.
I've achieved the same results using the GAC in the past, but you should question your reasons for having to reference more than one version and try to avoid it if possible. If you must do it, a binding redirect may help in your case.
Also, have you read this yet?
A seemingly little known way of doing this is to use the extern keyword.
From C# Reference
To reference two assemblies with the same fully-qualified type names,
an alias must be specified at a command prompt, as follows:
/r:GridV1=grid.dll
/r:GridV2=grid20.dll
This creates the external aliases GridV1 and GridV2. To use these
aliases from within a program, reference them by using the extern
keyword. For example:
extern alias GridV1;
extern alias GridV2;
Each extern alias declaration introduces an additional root-level
namespace that parallels (but does not lie within) the global
namespace. Thus types from each assembly can be referred to without
ambiguity by using their fully qualified name, rooted in the
appropriate namespace-alias.
In the previous example, GridV1::Grid would be the grid control from
grid.dll, and GridV2::Grid would be the grid control from grid20.dll.
I was required to support multiple versions of an assembly and found this solution:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="MyAssembly" publicKeyToken="..." />
<codeBase version="1.1.0.0" href="MyAssembly_v1.1.0.0.dll"/>
<codeBase version="2.0.0.0" href="MyAssembly_v2.0.0.0.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
You can add a bindingRedirect element to your configuration file to specify which version of the assembly you want to use at runtime.
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0"
newVersion="2.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
The .NET runtime is perfectly capable of loading multiple versions of the same assembly simultaneously. If you are going to open this can of worms, however, I strongly suggest you stronly name your assemblies and use the Major.Minor.* naming scheme to avoid naming conflicts.
I don't think you should think of a one-size-fits-all approach to using (or not) the GAC. The GAC can be really nice if you want to automagically use new functionality published with future versions of a DLL. Of course, this blessing comes at a cost that new versions might not work exactly like you expect them too :). It's all a matter of what's most practical, and how much control you have over what gets published to the GAC.
Regards,
-Alan.

Categories