Referencing different versions of the same assembly - c#

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.

Related

Why are there Different versions info for the same DLL?

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.

Dependent Assembly loading via configuration

I have a visual studio project with is running absolutely fine.
But a new client requirement comes up for deployment for placing the different dlls in different folders.
We have a framework dll which can be used in a different project. There are some third-party dlls on which this framework dll depends upon. So when I use this dll from my project every dependent dll is copied to my local on the build as CopyLocal property is true.
But now with new requirement we can not have CopyLocal property set as True. The client wants no local copy of any dll, rather he wants framework related dll in some location. When I am doing this the dependent DLL's are not getting loded.
I know I have two options:
I can put them in GAC, but I don't want to do this as I want them to support xcopy.
Using reflection(But I am not sure of this that is this the right approach)
Can we do anything using configurations??
You can configure assembly probing paths using the <probing> configuration element:
Specifies application base subdirectories for the common language runtime to search when loading assemblies.
Example from MSDN:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;bin2\subbin;bin3"/>
</assemblyBinding>
</runtime>
</configuration>
However, if the assemblies in question reside outside the application base ("which is the root location where the application is being executed"), you have the <codeBase> configuration element:
Specifies where the common language runtime can find an assembly.
Example from MSDN:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="neutral" />
<codeBase version="2.0.0.0"
href="http://www.litwareinc.com/myAssembly.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
For the exact details of how the runtime locates assemblies you can refer to this MSDN article.
As OP pointed out, unfortunately codeBase element is a usable option for strong named assemblies only. For private assemblies you need a workaround. Some viable ideas can be found in this discussion such as:
file system links (NTFS junction point) + probing element or AppDomainSetup.PrivateBinPath
AppDomain.CurrentDomain.AssemblyResolve event
I've tested the latter and can confirm it works:
AppDomain.CurrentDomain.AssemblyResolve += (s, e) =>
Assembly.LoadFile(Path.Combine(Settings.Default.AssemblyPath, Path.ChangeExtension(e.Name.Substring(0, e.Name.IndexOf(',')), ".dll")));

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>

How can you make a c# project ignore the version number of an assembly?

I am working on a project that references dlls from another product. The product has a release each year and the assemblies version changes for each one, although the methods stay the same.
When I run a build of my project for 2010 when I try and run it for 2009 it throws an error because it is dependent on a different version. Is there a way around this?
If you're referring to a problem at runtime after swapping versions of your assembly without performing a rebuild of the program referencing your newly built assembly, you'll want to use a <bindingRedirect> directive to your program's App.config (or Web.config, if you're talking about a web site.)
bindingRedirect is used to instruct the .NET Framework that it's OK to use a version of an assembly other than the one the application was originally compiled against. By default, the CLR wants to see the same version of a DLL that your application was referencing during build, and if it doesn't it will throw an exception.
Try selecting the reference, and in property window set Specific Version as false.
It is possible to map different .net version of assembly in app.config that you put in application root folder
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Waters.ACQUITY.Remote"
publicKeyToken="6c13fd0b3604de03"
culture="neutral" />
<bindingRedirect oldVersion="1.40.0.0"
newVersion="1.60.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
This is solution when assembly you have referenced has references inside it to another specifc library version.
It happens when at compilation time "Specific version" is set to true. To avoid this problem it should be false.

adding COM dll as a reference from specific location

I am posting this query again.Soory, but I dont know how to ask doubts about already asked query.
I am using a COM dll as a reference in my Project. I want that dll to be referenced from any location of computer.
<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="MyAssembly" culture="" publicKeyToken="8968ee41e78ce97a" /> <codeBase version="1.0.0.0" href="file://c:/some_path/myassembly.dll" /> </dependentAssembly> </assemblyBinding></runtime>
I have added above mentioned code in App.config file. After signing the Interop.Microsoft.Office.Interop.Excel.dll which was unsigned earlier,I have given proper value for PublicKeytoken.
This I think works fine.
but when i run the application the exe expects the dll to present in same folder & that too
the unsigned version.
Can anyone suggest me, if there is anything which i am missing in my code?
Thanks,
Amit
PS: During coding, I had added reference of unsigned version of dll. from C:\Program files...\ [Already existing dll, microsoft provided]
This is only a guess without reproducing your exact situation... It appears your missing the
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/>
In all the examples I've seen as well as all my uses of this, the above <assemblyIdentity...> tag is always followed by a <bindingRedirect ...>. BTW, You can also specify the original version as a range like the following:
<bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="2.0.0.0"/>
I think i have got the solution. As i mentioned in my question, I had added reference of older[unsigned] version of dll. I removed that & added reference of signed dll,then made changes into App.config[mentioned in my question].

Categories