.netreferencemanifestgacpublisher-policy

Specifying Exact Reference Versions in app.manifest


Whilst implementing the use of ODP.Net in our apps I came across a potential problem with versions so I knocked up a quick test app to see if it would affect us, and it did.

We have clients who have or want our apps on Oracle, but they use different versions and they generally have a corporate standard for the version of Oracle Client deployed on their work stations. Our idea was to deploy a fixed version of ODP plus the appropriate instant client with our app (in the program directory) as Oracle guarantee 2 major versions of compatibility either side for any given version of the client meaning we could work with, say, Oracle 10.1 up to the theoretical Oracle 12 by using deploying ODP and Client 11.1.

That's fine, but the problem comes if our clients then deploy a higher version of the Oracle Client which registers a newer version of ODP in the GAC and a publisher policy that tells applications to use the new version no matter what. We are using a custom implementation of one library from EntlibContrib (the ODP wrapper) built with the specific version of EL5 and ODP that we use, and deploying a newer version to the GAC causes this to fail, as proven with the test app.

To test this, I used a clean VM with Win 7 x86 installed and then added Oracle Client 10.2 (which registered ODP 10.2 in the GAC) and had my test app use ODP and Client 11.1. This worked fine so I then installed Client 11.2 with ODP registered in the GAC which adds the publisher policies as well and this proved that the test app would fail.

To get around this I added a dependency entry to the app.manifest like this:

  <dependency>
    <dependentAssembly>
      <assemblyIdentity
          type="win32"
          name="Oracle.DataAccess"
          version="2.111.7.20"
          processorArchitecture="x86"
          publicKeyToken="89b483f429c47342"
       />
    </dependentAssembly>
  </dependency>

This matches the version and public key of the ODP binary we are deploying so I was expecting the test app to use it. However on starting the app I got the following error:

The application has failed to start because its side-by-side configuration is incorrect.

And the event log contains this:

Activation context generation failed for "C:\Program Files\OPT\OPT\OraclePerformanceTester.exe". Dependent Assembly Oracle.DataAccess,processorArchitecture="x86",publicKeyToken="89b483f429c47342",type="win32",version="2.111.7.20" could not be found. Please use sxstrace.exe for detailed diagnosis.

Using sxstrace, I got the following output:

Begin Activation Context Generation.
Input Parameter:
    Flags = 0
    ProcessorArchitecture = x86
    CultureFallBacks = en-US;en
    ManifestPath = C:\Program Files\OPT\OPT\OraclePerformanceTester.exe
    AssemblyDirectory = C:\Program Files\OPT\OPT\
    Application Config File = C:\Program Files\OPT\OPT\OraclePerformanceTester.exe.Config

INFO: Parsing Application Config File C:\Program Files\OPT\OPT\OraclePerformanceTester.exe.Config.
INFO: Parsing Manifest File C:\Program Files\OPT\OPT\OraclePerformanceTester.exe.
INFO: Manifest Definition Identity is OraclePerformanceTester.exe,version="1.0.0.0".
INFO: Reference: Oracle.DataAccess,processorArchitecture="x86",publicKeyToken="89b483f429c47342",type="win32",version="2.111.7.20"
INFO: Resolving reference Oracle.DataAccess,processorArchitecture="x86",publicKeyToken="89b483f429c47342",type="win32",version="2.111.7.20".
INFO: Resolving reference for ProcessorArchitecture x86.
    INFO: Resolving reference for culture Neutral.
        INFO: Applying Binding Policy.
            INFO: No publisher policy found.
            INFO: No binding policy redirect found.
        INFO: Begin assembly probing.
            INFO: Did not find the assembly in WinSxS.
            INFO: Attempt to probe manifest at C:\Windows\assembly\GAC_32\Oracle.DataAccess\2.111.7.20__89b483f429c47342\Oracle.DataAccess.DLL.
            INFO: Attempt to probe manifest at C:\Program Files\OPT\OPT\Oracle.DataAccess.DLL.
            INFO: Attempt to probe manifest at C:\Program Files\OPT\OPT\Oracle.DataAccess.MANIFEST.
            INFO: Attempt to probe manifest at C:\Program Files\OPT\OPT\Oracle.DataAccess\Oracle.DataAccess.DLL.
            INFO: Attempt to probe manifest at C:\Program Files\OPT\OPT\Oracle.DataAccess\Oracle.DataAccess.MANIFEST.
            INFO: Did not find manifest for culture Neutral.
        INFO: End assembly probing.
ERROR: Cannot resolve reference Oracle.DataAccess,processorArchitecture="x86",publicKeyToken="89b483f429c47342",type="win32",version="2.111.7.20".
ERROR: Activation Context generation failed.

The referenced file (Oracle.DataAccess.dll) exists in the program directory next to the executable, with all the other dependencies but for some reason it just will not pick it up. The only manifest I've had to use before was for UAC checks on an exe which worked fine and as far as I can see I have followed the steps to specify an exact version which should override the publisher policy. What have I done wrong?

Cheers


Solution

  • I'm going to add an answer as Hans Passant (who gave me the answer) hasn't added an official answer, plus I want to expand on it because Hans' answer is similar to others I found but which weren't overly clear because they only tell part of the story.

    Adding <publisherPolicy apply="no" /> in the app.config does indeed work, but I found almost everywhere which says this doesn't explain where in app.config it should go. you need to add this to the <runtime> section like this:

    <configuration>
        <!--Other Sections-->
        <runtime>
            <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                <dependentAssembly>
                 <!--Ensures Oracle Publisher Policies don't override the version of ODP being used.-->
                    <assemblyIdentity name="Oracle.DataAccess" publicKeyToken="89B483F429C47342"/>
                    <publisherPolicy apply="no"/>
                  </dependentAssembly>
            </assemblyBinding>
        </runtime>
        <!--Other Sections-->
    </configuration>
    

    Of ocurse you must change the assembly name and public key according to your needs. And that's it. I was given duff information from a normally reliable source about using manifest files so the lesson here is double check your information before spending a load in the end.of time trying stuff out - it'll probably be time wasted.