Unmanaged Jerry and I’m lovin’ every minute of it!
We’ve been using the unmanaged Oracle Data Provider for .NET as part of a production software suite for quite some time. Ideally one would use the managed version, but for a variety of reasons including the fact that some functionality from the unmanaged version is not available in the managed version we continue to have to use the unmanaged version.
Oracle.DataAccess.dll is a managed assembly, but it calls out to the unmanaged provider code in OraOps12.dll using a specific search order that has nothing to do with how .NET loads assemblies.
The Oracle.DataAccess.dll checks the version of the unmanaged DLL it finds and if it does not match up exactly with the version it expects then it throws an exception like this…
The provider is not compatible with the version of Oracle client
One of the main issues with resolving this problem in ODP.NET installations prior to 18c is that the Oracle.DataAccess.dll is installed in the GAC by the provider installer. Also, if you had a previous version of ODP.NET installed then the installer will add policy files that redirect from the older version to the newer version. Policy files are just assemblies with configuration embedded in them. That configuration implements a binding redirect in the same fashion as you would if you were doing it through configuration.
There are numerous problems with a publisher trying to automatically redirect versions via policy files, but then you also have the issue of said assembly having to locate a set of unmanaged files that exactly match a particular version. In addition, if you deployed the Oracle.DataAccess.dll assembly in your application bin folder and some or all of your application uses late binding calls to load Oracle.DataAccess.dll that don’t specify a particular assembly version, then you’re going to end up even more confused since your application will not load the assembly from the GAC and will instead load the one from your local bin folder which may or may not be compatible with the provider that you have installed.
This last point became a problem for us with using NHibernate, because it does late binding in this fashion (to be fair due to the ODP.NET versioning issue there is really no other way for it to go and we’ll see how to fix this in a bit).
There are several things you can do to discover where your issues are happening.
Fusion Log Viewer
You should definitely use Fusion Log Viewer to see from where your application is attempting to load Oracle.DataAccess.dll and what version it is attempting to load. This is likely going to give you the primary reason you are getting the provider compatibility error. If your application looks finds a 12.1 DLL in the local bin and your provider is 12.2 you have your answer. Usually it’s as simple as that, but if you have installed multiple ODP.NET providers onto the same machine it could get more complicated as you are then possibly dealing with Policy files in the GAC redirecting from one version to another. In that case you will need to examine the gac using gacutil looking for assemblies named Policy.VERSION.Oracle.DataAccess.dll.
Compatibility and Binding Redirects
Despite this requirement that each version of Oracle.DataAccess.dll be matched to a particular unmanaged version of the provider, in the majority of cases you can still use a binding redirect to point your application to a newer (or older) version of the managed Oracle.DataAccess.dll client assembly even if the exact version is not installed. Most basic functionality is unchanged from one version to another so a binding redirect in your client application’s config file is all you need to solve the issue.
<dependentAssembly> <assemblyIdentity name="Oracle.DataAccess" publicKeyToken="89b483f429c47342"/> <bindingRedirect oldVersion="18.104.22.168" newVersion="22.214.171.124" /> </dependentAssembly>
The other issue is with late binding and the GAC. Without specifying the fully qualified assembly name a late binding call will not load an assembly from the GAC. In some cases you may not want to ship the Oracle.DataAccess.dll with your application since it requires the customer to install ODP.NET anyway. In this case, if you have issues with late binding from third party apps such as NHibernate you can add a Qualify Assembly element to your application configuration that specifies the particular version you want to load and any unqualified calls will use the version you specify.
<qualifyAssembly partialName="Oracle.DataAccess" fullName="Oracle.DataAccess, Version=126.96.36.199, Culture=neutral, PublicKeyToken=89b483f429c47342" />