Jeg får denne feilen mens en av mine .Net
-applikasjoner prøver å opprette en forbindelse til Oracle-databasen.
Feilen sier at Dette problemet vil oppstå når du kjører i 64 bit modus med 32 bit Oracle klientkomponenter installert.
. Men jeg har forsikret meg om mange ganger at klienten er installert i x64
bit og ikke 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)
En løsning er å installere både x86 (32-biters) og x64 Oracle-klienter på maskinen, så spiller det ingen rolle hvilken arkitektur applikasjonen kjører på.
Her er en instruksjon for å installere x86- og x64 Oracle-klienten på én og samme maskin:
Forutsetninger: Oracle Home heter OraClient11g_home1
, klientversjonen er 11gR2.
Du kan eventuelt fjerne alle installerte Oracle-klienter (se https://stackoverflow.com/questions/8450726/how-to-uninstall-completely-remove-oracle-11g-client hvis du får problemer).
Last ned og installer Oracle x86 Client, for eksempel i C:\Oracle\11.2\Client_x86
.
Last ned og installer Oracle x64 Client i en annen mappe, for eksempel i C:\Oracle\11.2\Client_x64
.
Åpne kommandolinjeverktøyet, gå til mappen %WINDIR%\System32, vanligvis C:\Windows\System32
og opprett en symbolsk lenke ora112
til mappen C:\Oracle\11.2\Client_x64
(se avsnittet om kommandoer nedenfor).
Bytt til mappen %WINDIR%\SysWOW64, vanligvis C:\Windows\SysWOW64
og opprett en symbolsk lenke ora112
til mappen C:\Oracle\11.2\Client_x86
, (se nedenfor).
Endre miljøvariabelen PATH
, og erstatt alle oppføringer som C:\Oracle\11.2\Client_x86
og C:\Oracle\11.2\Client_x64
med C:\Windows\System32\ora112
, henholdsvis deres \bin
undermappe. Merk: C:\Windows\SysWOW64\ora112
må ikke være i PATH-miljøet.
Ved behov kan du sette miljøvariabelen ORACLE_HOME
til C:\Windows\System32\ora112
.
Åpne registerredigeringsprogrammet. Sett registerverdien HKLM\Software\ORACLE\KEY_OraClient11g_home1\ORACLE_HOME
til C:\Windows\System32\ora112
.
Sett registerverdien HKLM\Software\Wow6432Node\ORACLE\KEY_OraClient11g_home1\ORACLE_HOME
til C:\Windows\System32\ora112
(ikke C:\Windows\SysWOW64\ora112
)
Du er ferdig! Nå kan du bruke x86- og x64 Oracle-klienten sømløst sammen, dvs. at en x86-applikasjon laster x86-bibliotekene og en x64-applikasjon laster x64-bibliotekene uten ytterligere endringer på systemet.
Det kan være lurt å sette miljøvariabelen TNS_ADMIN
(hhv. TNS_ADMIN
-oppføringene i Registry) til en felles plassering, for eksempel TNS_ADMIN=C:\Oracle\Common\network
.
Kommandoer for å opprette symbolske lenker:
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`.
Merknader:
Begge symbolske lenker må ha samme navn, f.eks. ora112
.
Til tross for navnene inneholder mappen C:\Windows\System32
x64-bibliotekene, mens C:\Windows\SysWOW64
inneholder x86-bibliotekene (32-biters). Ikke bli forvirret.
I min situasjon var Oracle 11.2 32-biters klienten installert på mitt 64-biters Windows 2008 R2 operativsystem.
Min løsning: I de avanserte innstillingene for Application Pool som er tilordnet ASP.NET-applikasjonen, setter jeg Enable 32-Bit Applications til True.
Nedenfor finner du det frittstående .ashx testskriptet som jeg brukte for å teste muligheten til å koble til Oracle. Før jeg endret Application Pool, var svaret følgende:
[Running as 64-bit] Connection failed.
...og etter endringen av Application Pool:
[Running as 32-bit] Connection succeeded.
TestOracle.ashx - Skript for å teste en Oracle-tilkobling via System.Data.OracleClient:
Slik bruker du det: Endre bruker-, passord- og vertsvariablene etter behov.
Merk at dette skriptet kan brukes frittstående uten å forstyrre prosjektfilen for ASP.NET-webapplikasjonen. Det er bare å legge det i applikasjonsmappen.
<%@ 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;
}
}
BadImageFormatException oppstår når en 32bit (x86) dll kaller en 64bit dll eller omvendt. Hvis du bruker AnyCPU for den kjørbare filen, vil den kjøres som 64-biters når den kjøres på en 64-biters maskin, men hvis den deretter kaller en 32-biters dll, får du unntaket, og det er derfor AnyCPU ikke alltid er løsningen.
Jeg har en tendens til å bygge alt som 32bit (x86), siden vi fortsatt må ha grensesnitt mot noen gamle komponenter som er laget i VB6 (32bit (x86)). Selv om ytelsen kan være bedre for 64bit-maskiner hvis vi bygger i AnyCPU, er pålitelighet viktigere for oss.
Jeg vil foreslå at du prøver å bygge alle komponentene dine i 32bit (x86), med mindre du gjør noen veldig intensive ting, tviler jeg på at det vil gjøre noen stor forskjell.