20

Is there any way to force my asp.net application to load the assembly from local bin directory since there is another older version of the assembly with the same name in the gac?

I can't delete the gac version since other applications are using it and I am facing some difficulties when adding the newer version to the gac.

Khaled Musaied
  • 2,513
  • 3
  • 25
  • 38
  • 1
    Were you setting "Specific Version" true? Surely in that case it should not use an older version from the GAC. – Oliver Bock Apr 20 '16 at 02:11

8 Answers8

8

I found it

To force your application to read from local bin directory you have to remove signing from your assembly and then the application will load the assembly from bin.

Thanks Wyatt Barnett and murad.

Khaled Musaied
  • 2,513
  • 3
  • 25
  • 38
  • 4
    What if I can't remove the strong name from the assembly? – Amitabh Feb 22 '10 at 16:50
  • 2
    Could you supply the procedure for removing signing from an assembly? – dlchambers Nov 22 '11 at 14:12
  • 1
    Just remove the strong name file – Khaled Musaied Nov 26 '11 at 20:59
  • @Amitabh, you cannot remove signing from assemblies you do not have the source code of. As a trick, you can set the `DEVOVERRIDE` environment variable to a path with your assembly, which will be probed prior to the GAC. – Abel Dec 23 '15 at 12:37
  • @Abel do you have some link for this DEVOVERRIDE sollution? – RanH Jun 09 '16 at 12:50
  • @antisane, I turned it into an [answer containing relevant links and explanations](http://stackoverflow.com/a/37745654/111575). It can be used if you cannot remove the signing. – Abel Jun 10 '16 at 10:16
5

Change the version number, strong name the assembly and reference the strongly named higher version you deploy with your solution.

Abel
  • 56,041
  • 24
  • 146
  • 247
Wyatt Barnett
  • 15,573
  • 3
  • 34
  • 53
3

The oldVersion configuration that is suggested by Muse VSExtensions works! You can use the strong name for the local assembly: Please look this page: http://msdn.microsoft.com/en-us/library/7wd6ex19.aspx

Basically in web.config add something like:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="DllName"
          publicKeyToken="0123456789abc"
          culture="neutral" />        
        <!-- Assembly versions can be redirected in app, 
          publisher policy, or machine configuration files. -->
        <bindingRedirect oldVersion="2.0.0.0-2.5.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>      
    </assemblyBinding>  
  </runtime>

That way if i have an assembly in the gac that can be from version 2.0.0.0 to version 2.5.0.0 all the calls would be redirected to the newVersion (3.0.0.0)

In the assemblies section I added the assembly:

<add assembly="DllName, Version=3.0.0.0, Culture=neutral, PublicKeyToken=0123456789abc" />

And that's it.

Paco Zarate
  • 1,925
  • 1
  • 15
  • 13
3

As an alternative to the proposed solution, during development you can bind to whatever assembly you want overriding the GAC completely by setting the DEVPATH environment variable and enabling Development Mode in the machine.config. I think this is by far the easiest way to achieve what you want, but should not be used in production.

This solves the issue where version of your assembly and the one in the GAC are the same, if versions are different, you should use the bindingRedirect approach mentioned here by several users.

First, add the following to machine.config:

<configuration>
  <runtime>
    <developmentMode developerInstallation="true"/>
  </runtime>
</configuration>

Then, set the DEVPATH environment variable to the location of your non-signed assemblies. This will force Fusion's DEVOVERRIDE mode to kick in and search the DEVPATH (and its subdirectories) prior to probing the GAC.

An FAQ of DEVPATH and DEVOVERRIDE on MSDN will answer most questions on the effects of using this.

Fusion (.NET's assembly loader) will search by name and version only, it will treat strongly named assemblies equal to other assemblies, won't search the GAC before searching DEVPATH, and simply returns the first match found. You should use the Fusion Log Viewer (fuslogvw) to see that you properly enabled it, as explained in this blog post on DEVPATH.

New to using FusLogVw? Scott Hanselman wrote an excellent intro. The interface of the Viewer is rather archaïc and takes a little getting used to.

Note that the Fusion Log Viewer (or Assembly Binding Log Viewer, what's in a name) will confusingly say that you used the DEVOVERRIDE environment variable. It should look something like this:

LOG: Found assembly in DEVOVERRIDE path D:\testassemblies\Test.DLL

NOTE: if you want Visual Studio to load the assemblies from the DEVPATH location, you should set a registry key to this location, i.e., set (check the .NET version key to match your .NET version):

[HKEY_CURRENT_USER\
    SOFTWARE\
    Microsoft\
    .NETFramework\
    v2.0.50727\AssemblyFoldersEx\
    DEVPATH]@="C:\SharedAssemblies"
Community
  • 1
  • 1
Abel
  • 56,041
  • 24
  • 146
  • 247
  • On my machine, it still ends up loading from GAC. It recognizes the DEVPATH and logs it in Fusion logs, but still doesn't load the assembly from there. Any idea? Assemblies at DEVPATH and GAC are both signed and have same identity. – Turbo Jul 14 '16 at 20:59
  • @Turbo: I found [this post on PDB's](http://www.wintellect.com/devcenter/jrobbins/pdb-files-what-every-developer-must-know) which also expands to a how-to on `DEVPATH`, I think it matches my information above, except that it says (logically) that you must make sure that the DEVPATH is accessible for read/write rights. It also suggests that `developerInstallation="true"` can be used on application-level, which is good news (I haven't tested that). – Abel Jul 20 '16 at 18:25
  • @Turbo, one more thing, maybe you mean that VS doesn't recognize the DEVPATH? I updated the answer with that in mind, you need to also set a registry value for VS to find that path. – Abel Jul 20 '16 at 18:41
  • Thx for the links. I'm using vstest.console.exe to run unittests, and I want it to load assemblies from the build folder instead of GAC. As suggested in pdb post, I gave read/write permissions to all users and application packages. I set DEVPATH as system wide environment variable. And set developerInstallation="true" in both machine.config and vstest.console.exe.config. As before, the fusion logs mentions the DEVPATH value "LOG: DEVPATH = C:\MyPath", but it doesn't look there (fusion says it found assembly in GAC and nothing about probing in DEVPATH). – Turbo Jul 21 '16 at 20:47
  • I also see an exception when DEVPATH is not defined and developerInstallation is true, which means fusion is aware, but it's not using it. – Turbo Jul 21 '16 at 20:50
  • @Turbo, I'm not sure what is causing this. The matching is by name only for the `DEVPATH`, so if the same assemblies are there, it should be found. But it is very well possible that `vstest.console.exe` uses its own assembly loader, leading to different behavior. You can surpass that by using different version numbers for build and production, so that the GAC version is never found, but of course, that was not the solution you were after. I do not use the VSTEST environment, I use a different env. and therein I also found other assembly loading behavior than the default .NET behavior. – Abel Jul 29 '16 at 15:05
1

Based on the excerpted notes on assembly loading order in this answer: How to prevent a .NET application from loading/referencing an assembly from the GAC?

I am guessing that calling LoadLibrary on the local DLL file before asking the library to load as an assembly, might move it up in the search order for you.

Sadly, I am not sure how to get your LoadLibrary call to run before the framework starts loading referenced assemblies.

So this is just an idea, not a full answer.

Community
  • 1
  • 1
Jesse Chisholm
  • 3,857
  • 1
  • 35
  • 29
1

To redirect one version to another, use the <bindingRedirect> element. The oldVersion attribute can specify either a single version, or a range of versions. For example, specifies that the runtime should use version 2.0.0.0 instead of the assembly versions between 1.1.0.0 and 1.2.0.0.

s

Mark Sowul
  • 10,244
  • 1
  • 45
  • 51
BALKANGraph
  • 2,031
  • 1
  • 15
  • 16
0

Instead of using bindingRedirect, you can specify the codebase path. I have a working example with MySQL.Data.dll.

<dependentAssembly>
    <assemblyIdentity name="MySql.Data" publicKeyToken="c5687fc88969c44d" culture="neutral" />
    <codebase version="5.2.5.0" href="/bin/MySQL.Data.dll" />        
  </dependentAssembly>

This can be done in Web.config of the web application.

Hung Ha
  • 89
  • 1
  • 4
  • 1
    The path in CodeBase is looked at after the lookup in GAC. So if the assembly is in GAC (as described in the question), then this won't work. – Turbo Jul 21 '16 at 21:09
-1

Why not install the version that you like into the GAC and then reference it in the GAC?

Matthew
  • 913
  • 1
  • 8
  • 19
  • Sadly, the old version refuses to uninstall from the GAC_32 because it is still in use by some unknown application. Double-sadly, the new version has the exact same version number as the old version. Installing the new version in GAC_MSIL doesn't prevent system from using the GAC_32 old version if it chooses. – Jesse Chisholm Nov 21 '13 at 19:19