BadImageFormatException. 当使用32位Oracle客户端组件并在64位模式下运行时,会出现此错误。

52

我的一个.Net应用程序试图连接Oracle数据库时出现了此错误。

错误提示说:当在64位模式下安装32位Oracle客户端组件时,将会发生此问题。但我已经多次确认客户端已经安装在x64位而不是32位。

Date Time: 6/8/2014 10:57:55 AM: System.InvalidOperationException: Attempt to load Oracle client libraries threw BadImageFormatException.  This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed. ---> System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
       at System.Data.Common.UnsafeNativeMethods.OCILobCopy2(IntPtr svchp, IntPtr errhp, IntPtr dst_locp, IntPtr src_locp, UInt64 amount, UInt64 dst_offset, UInt64 src_offset)
       at System.Data.OracleClient.OCI.DetermineClientVersion()
       --- End of inner exception stack trace ---
       at System.Data.OracleClient.OCI.DetermineClientVersion()
       at System.Data.OracleClient.OracleInternalConnection.OpenOnLocalTransaction(String userName, String password, String serverName, Boolean integratedSecurity, Boolean unicode, Boolean omitOracleConnectionName)
       at System.Data.OracleClient.OracleInternalConnection..ctor(OracleConnectionString connectionOptions)
       at System.Data.OracleClient.OracleConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningObject)
       at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnection owningConnection, DbConnectionPool pool, DbConnectionOptions options)
       at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject)
       at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject)
       at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
       at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
       at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
       at System.Data.OracleClient.OracleConnection.Open()
       at CustomizedSetupInstaller.Runscripts.InitializeDBObjects(String connectionString, String dbProvider)

7
您正在使用System.Data.OracleClient。该命名空间已被弃用,并将在未来的 .NET 版本中删除。也许您正在使用32位版本?它也不是 Oracle 客户端的一部分,因此无论您使用的是32位还是64位 Oracle 客户端都是无关紧要的。理想情况下,您应该改为使用 Oracle.DataAccess(或 Oracle.ManagedDataAccess)。 - Luke Woodward
5
小错误:System.Data.OracleClient只是提供程序,它还使用一个必须与架构匹配的Oracle客户端。只有Oracle.ManagedDataAccess不需要安装额外的Oracle客户端。也许Oracle客户端是x64,但你的应用程序是32位的,这也行不通。可以在同一台机器上安装32位和64位的Oracle客户端。 - Wernfried Domscheit
22个回答

60
一种解决方案是在您的计算机上安装x86(32位)和x64 Oracle客户端,这样无论应用程序在哪种架构上运行都没有关系。
以下是在一台计算机上安装x86和x64 Oracle客户端的说明:
假设:Oracle Home称为“OraClient11g_home1”,客户端版本为11gR2。
  • 如有问题,可选择卸载已安装的Oracle客户端(请参考如何卸载/完全删除Oracle 11g(客户端)?

  • 下载并安装Oracle x86客户端,例如安装在C:\Oracle\11.2\Client_x86文件夹中

  • 下载并安装Oracle x64客户端到不同的文件夹,例如安装在C:\Oracle\11.2\Client_x64文件夹中

  • 打开命令行工具,进入文件夹%WINDIR%\System32(通常是C:\Windows\System32),并创建符号链接ora112到文件夹C:\Oracle\11.2\Client_x64(请参见下面的命令部分)

  • 转到文件夹%WINDIR%\SysWOW64(通常是C:\Windows\SysWOW64),并创建符号链接ora112到文件夹C:\Oracle\11.2\Client_x86(请参见下面的命令部分)

  • 修改PATH环境变量,将所有类似于C:\Oracle\11.2\Client_x86C:\Oracle\11.2\Client_x64的条目替换为C:\Windows\System32\ora112,或其\bin子文件夹。注意:C:\Windows\SysWOW64\ora112不能在PATH环境中。

  • 如果需要,将您的ORACLE_HOME环境变量设置为C:\Windows\System32\ora112

  • 打开注册表编辑器。将注册表值HKLM\Software\ORACLE\KEY_OraClient11g_home1\ORACLE_HOME设置为C:\Windows\System32\ora112

  • 将注册表值HKLM\Software\Wow6432Node\ORACLE\KEY_OraClient11g_home1\ORACLE_HOME设置为C:\Windows\System32\ora112(不是C:\Windows\SysWOW64\ora112

  • 完成!现在您可以无缝地使用x86和x64 Oracle客户端,即x86应用程序将加载x86库,x64应用程序将加载x64库,而无需对您的系统进行任何其他修改。

  • 可能最好将您的TNS_ADMIN环境变量(或注册表中的TNS_ADMIN条目)设置为一个公共位置,例如TNS_ADMIN=C:\Oracle\Common\network

创建符号链接的命令:
cd C:\Windows\System32
mklink /d ora112 C:\Oracle\11.2\Client_x64
cd C:\Windows\SysWOW64
mklink /d ora112 C:\Oracle\11.2\Client_x86

注意:

两个符号链接的名称必须相同,例如ora112

尽管它们的名称不同,但文件夹C:\Windows\System32包含x64库,而C:\Windows\SysWOW64包含x86(32位)库。不要混淆。

背景信息,为什么这样可以工作:注册表重定向文件系统重定向


1
这非常有帮助。64位xCopy软件包足够好,还是需要完整的64位客户端?除了instaclient外,我似乎找不到它的下载链接,但我没有安装32位的instaclient,而是安装了完整的客户端。 - Andrew Grothe
符号链接或修改注册表的目的是什么?如果不进行更改,提供程序将通过注册表中设置的路径找到未管理的库。 - b_levitt
@b_levitt,请阅读以下内容以了解:Windows 64位如何支持32位应用程序。64位提供程序在%WINDIR%\System32\ora112\bin中搜索Oracle二进制文件,该路径指向C:\Oracle\11.2\Client_x64\bin,而32位提供程序在%WINDIR%\SysWOW64\ora112\bin中搜索,该路径指向C:\Oracle\11.2\Client_x86\bin。您不能直接将文件夹放入PATH,因为(取决于顺序)64位提供程序可能首先搜索C:\Oracle\11.2\Client_x86\bin并失败。 - Wernfried Domscheit
@b_levitt,我在我的机器上进行了一些测试。直接在PATH中使用c:\ oracle \ product \ 11.2 \ Client_x64; c:\ oracle \ product \ 11.2 \ Client_x64 \ bin对于ODP.NET(x86)有效,但是一些OLEBD(x86)和ODBC(x86)驱动程序失败了。如果没有符号链接,所有驱动程序都会失败,如果架构不匹配,即使我使用微软驱动程序(除ODBC以外已被废弃)或Oracle驱动程序也是如此,包括ODP.NET、OLEDB和ODBC。 - Wernfried Domscheit
1
我应该澄清一下我的最后一条评论。在.NET应用程序连接Oracle提供程序的情况下,如果有人显然是新手,我想知道为什么你不会只是在.config文件中设置dllpath而要经历这一切?最终我会发布我的答案,但既然你已经接受了答案,我想展示一下讨论。 - b_levitt
显示剩余6条评论

23

我的Windows 10电脑出现了同样的问题。我将项目从旧电脑复制到新电脑上,两者都是64位,并在新电脑上安装了Oracle Client 64位。我得到了相同的错误信息,但经过尝试多种解决方案无果后,实际上对我有用的是这个方法: 在Visual Studio中(我的版本是2017),前往 工具 > 选项 > 项目和解决方案 > Web 项目

在该页面上,勾选以下选项: 使用64位版本的IIS Express作为网站和项目的服务器


1
这也对我起作用了。在 VS 中,默认情况下,IIS Express 将以 32 位模式运行。 - Sreekumar P

16
在我的情况下,Oracle 11.2 32位客户端已安装在我64位Windows 2008 R2操作系统上。 我的解决方案:在分配给我的ASP.NET应用程序的应用程序池的高级设置中,我将启用32位应用程序设置为True。 请参见下面的独立的.ashx测试脚本,该脚本用于测试连接到Oracle的能力。在进行应用程序池更改之前,其响应为:
[Running as 64-bit] Connection failed.

......并在应用程序池更改后:

[Running as 32-bit] Connection succeeded.

TestOracle.ashx - 使用System.Data.OracleClient测试Oracle连接的脚本:

使用方法:根据需要更改用户、密码和主机变量。

请注意,此脚本可以独立使用,不会影响您的ASP.NET Web应用程序项目文件。只需将其放入应用程序文件夹中即可。

<%@ WebHandler Language="C#" Class="Handler1" %>
<%@ Assembly Name="System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" %>

using System;
using System.Data.OracleClient;
using System.Web;

public class Handler1 : IHttpHandler
{
    private static readonly string m_User = "USER";
    private static readonly string m_Password = "PASSWORD";
    private static readonly string m_Host = "HOST";

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";

        string result = TestOracleConnection();
        context.Response.Write(result);
    }

    public bool IsReusable
    {
        get { return false; }
    }

    private string TestOracleConnection()
    {
        string result = IntPtr.Size == 8 ?
            "[Running as 64-bit]" : "[Running as 32-bit]";

        try
        {
            string connString = String.Format(
              "Data Source={0};Password={1};User ID={2};",
              m_Host, m_User, m_Password);

            OracleConnection oradb = new OracleConnection();
            oradb.ConnectionString = connString;
            oradb.Open();
            oradb.Close();
            result += " Connection succeeded.";
        }
        catch
        {
            result += " Connection failed.";
        }

        return result;
    }
}

6

修改IIS:

  1. 选择应用程序池。
  2. 单击ASP .NET V4.0 Classic。
  3. 选择高级设置。
  4. 在常规选项中,启用32位应用程序,默认为false。选择TRUE。
  5. 刷新并检查站点。

注释:

平台:Windows Server 2008 R2 Enterprise - 64位 - IIS 7.5


3

我遇到了同样的问题,后来通过更改配置管理器 x86 -> x64 并进行构建来解决它。

image


2
这个解决方案对我有用, 要修改IIS。
Select Application Pools.
Clic in ASP .NET V4.0 Classic.
Select Advanced Settings.
In General, option Enable 32-Bit Applications, default is false. Select TRUE.
Refresh and check site.

评论:

平台:Windows Server 2012标准版-64位-IIS 8


2
我在SSIS 2008中遇到了同样的问题。我尝试使用ODAC 12c 32位连接到Oracle 11g。还尝试安装了ODAC 12c 64位。实际上,SSIS能够预览表格,但是在尝试运行包时会出现此错误消息。没有什么帮助。 转而使用VS 2013,在调试模式下运行成功,但使用dtexec / f文件名运行包时仍然出现相同的错误。 后来我找到了这个页面:http://sqlmag.com/comment/reply/17881
简而言之,它说:(如果页面仍然存在,请转到该页面并按照说明操作...) 1)从Oracle网站下载并安装最新版本的odac 64位xcopy。 2)从Oracle网站下载并安装最新版本的odac 32位xcopy。 如何操作?以管理员身份打开cmd shell并运行: c:\64bitODACLocation> install.bat oledb c:\odac\odac64。 第一个参数是您要安装的组件。第二个参数是安装位置。 像这样安装32位版本:c:\32bitODACLocation> install.bat oledb c:\odac\odac32。 3)更改系统路径,包括c:\ odac \ odac32; c:\ odac \ odac32 \ bin; c:\ odac \ odac64; c:\ odac \ odac64 \ bin,按此顺序。 4)重新启动计算机。 5)确保在odac32 \ admin \ network和odac64 \ admin \ network文件夹中具有相同的tnsnames.ora(或至少具有连接的相同条目)。 6)现在在Visual Studio中打开SSIS(我使用了带有ssis包的免费2013版)-使用OLEDB,然后选择Oracle Provider for OLE DB提供程序作为您的连接类型。将tnsnames.ora中的条目名称设置为“服务器或文件名”。用户名是模式名称(数据库名称),密码是模式的密码。完成!
再次强调,您可以在原网站上找到非常详细的解决方案以及更多信息。
这是唯一对我有用且不会破坏我的环境的方法。
祝贺! gcr

1
请用自己的话描述指令告诉你要做什么。你链接的页面很容易消失,那么我们仍然不知道如何解决这个错误。 - Martijn Pieters

2

正如评论中指出的那样,System.Data.OracleClient已经被弃用。所以在这个时候开始使用它没有太多的理由。

同样在评论中指出(我将其标记为社区wiki以示尊重),现在odp.net包的12c及更高版本中有一个托管提供程序。该提供程序不需要任何非托管dll,因此在这种情况下,这应该不是问题。

如果您希望使用来自Oracle的旧的非托管Oracle.DataAccess提供程序,则最简单的解决方案是设置“DllPath”配置变量:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <oracle.dataaccess.client>
    <add key="DllPath"            value="C:\oracle\bin"/>
  </oracle.dataaccess.client>
</configuration>

请参阅http://docs.oracle.com/database/121/ODPNT/InstallODP.htm中的“未管理的DLL搜索顺序”获取更多信息。


一个更新,自从VS2015和Oracle 12cR3发布以来...如果你想安装32位和64位客户端,请下载两个ODAC包(花了我一段时间才找到它们,但只需搜索例如“oracle 64位odac”等)。将它们各自安装到Oracle基本路径“C:\Oracle\12.1.0.2.1\”,然后在软件位置上添加“\Client_x86”(或x64)到该路径。然后应用b_levitt所说的所有内容。两个版本都已完全配置,32位应用程序将使用32位驱动程序,而64位应用程序将使用64位驱动程序。非常简单。 - sliderhouserules
哦,截至2015年9月4日,Oracle仍未发布适用于Visual Studio 2015的Oracle开发人员工具。他们承诺在VS2015 RTM发布后一个月内发布,但现在已经远远超过了这个时间,仍然没有出现。:( - sliderhouserules

1
我在安装在Windows 2012 R2上的DNN应用程序中遇到了这个错误。它使用了一些32位dll,只有Oracle.DataAccess.dll x32能够正常工作。我的解决方案是:
  1. 卸载旧的Oracle Client \ ODAC。
  2. 安装Oracle 11 Client x32。
  3. 安装Oracle ODAC 12 x64。
  4. 检查IIS应用程序池(经典版本)是否启用“启用32位应用程序”选项 = true。

1
在您所使用的IIS应用程序池中将Enable32bit应用程序设置为TRUE。

1
只是为了以防有人遇到类似情况而发出此言。在我的案例中,应用程序池的32位设置为True。我不得不将其设置为False才能使我的程序正常工作,但问题出在应用程序池上。 - Caverman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接