Dependent Assembly loading via configuration - c#

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")));

Related

Assembly.LoadFrom how behaves on multi version dll

I've a dll with 2.0.0.1 version in one server which can be downloaded by accessing http://someipaddress/assembly/test.dll and I'm having another application which need to download this test.dll and have to access those methods.
When surfing for this, i've got three different methods to do,
1. Assembly.LoadFrom()
2. Assembly.LoadFile()
3. Assembly.Load()
I've tried Assembly.LoadFrom("http://someipaddress/assembly/test.dll")
Now i've replaced test.dll with 2.0.0.2 version and
What will happen the application download 2.0.0.2 test.dll and already downloaded test.dll 2.0.0.1.
Application which dll will refer?
Will it use existing test.dll 2.0.0.1 since its already downloaded while accessing test.dll 2.0.0.2?
Please suggest on this.
It'll depend on how you're referencing the assembly. By default if there's no binding redirect, your new dll will cause an exception. You can get around this by specifying an binding redirect rule in your application's configuration file like so;
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Test" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.2" newVersion="2.0.0.2" />
</dependentAssembly>
</assemblyBinding>
</runtime>
But you'd need to update it upon getting the new version of the dll.

Use a specific version of a dll in C#

I have a project where I would want to use some specific version of a dll.
The GAC contains couple of versions of that dll (new & old), I would want to use the old when running the program.
Issue is that the newest dll is always picked-up from the GAC.
Would you know if there is a way to either:
Force the usage the dll that is in the run folder (the one I'm referencing in my solution, working fine in debug).
Force the usage of the old version of the dll from the GAC.
Thank you!
You can use a binding redirect in your app.config or web.config in the runtime node:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
</appSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Make sure you have the correct publicKeyToken and know which versions you want to redirect to what version.
(You can check a publicKeyToken of a DLL like this with this info.)
MSDN Documentation
You can also generate these for an entire solution using the Package Manager Console
Get-Project -All | Add-BindingRedirect
This will update all app.config files and add the binding redirect.
When you have added the library to your project and you collapse the 'References'-node of the project tree, you'll see the added library. When you select it and click the 'Properties'-node of the context menu, you can specify if a specific version of the library should be used and which version to use. Simply set 'Specific Version' to true and specify the Version number. Then you don't have to cope with the question where the version you want is loaded from.
Have you try to "Redirecting Assembly Versions" in your app.config? http://msdn.microsoft.com/en-us/library/7wd6ex19(v=vs.110).aspx

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.

Remote Codebase

I have a dll. That dll is uploaded on a server. I want that each time the application starts to get the "latest" dll from the server, so I've used the following code in my app.config. Why isn't it working?
here is the app.config file:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="ReflectionTest"
publicKeyToken="f94c9b9f0707ee96"
culture="neutral" />
<codeBase version="1.0.0.0"
href="http://127.0.0.1/ReflectionTest.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
First, you may be on the wrong track. Even if you didn't change the version, your application may end up using an older copy of the assembly.
Assuming a valid URI in your <codebase> element, when your application runs for the first time, the runtime will not find the assembly in until it probes your codebase. Then, it will download the assembly to the GAC. When your application runs again, the runtime will find that assembly in the GAC, so it will not need to probe for it.
Instead of using <codebase>, consider using Reflection. Specifically, you might want to use Assembly.LoadFrom(assemblyUri) in your application, getting the URI from an application setting. From there, you'd create objects using the Reflection API, particularly using Activator.CreateInstance<T>().
As for getting that assembly from your server is concerned, make sure that your DLL is in the right location and that your web server is running and properly configured.
Is your .dll actually available at that location? Are you serving it up through some web application?
If you type that URL into a web browser, does it let you download or open that file?

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