Microsoft has deprecated System.Data.OracleClient, so here's a simple example of using the new ODP.NET Oracle.DataAccess.Client, with the following benefits:
* Simple Xcopy deployment
* No Oracle [instant] client installation needed
* No TnsNames.Ora file needed
Firstly, download the ~200mb ODP.Net from Oracle. Don't freak out, you won't need to redistribute *all* this with your app, just ~30megs worth. I used this version [link] but you'll probably want to get the latest version [link].
Grab Oracle.DataAccess.dll from:
ODAC1110710beta.zip \ stage \ Components \ oracle.ntoledb.odp_net_2 \ 11.1.0.7.10 \ 1 \ DataFiles \ filegroup4.jar
Copy it into your project (For winforms: the same folder as your project's Program.cs; For Asp.net: the Bin folder). In Visual Studio, right click references and add the Oracle.DataAccess.dll.
Write some code like this in your app:
using Oracle.DataAccess.Client; // This goes up the top
...
string connstring =
"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=1527))" +
"(CONNECT_DATA=(SID=mysid)));User Id=myuserid;Password=mypassword;";
using (OracleConnection conn = new OracleConnection(connstring))
{
conn.Open();
string sql = "select distinct owner from sys.all_objects order by owner";
using (OracleCommand comm = new OracleCommand(sql, conn))
{
using (OracleDataReader rdr = comm.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine(rdr.GetString(0));
}
}
}
}
You'll then need the following dll's to be placed in the same folder as your EXE:
* oci.dll (Find 'oci.dll.dbl' and rename it to remove the '.dbl'; in ODAC1110710beta.zip \ stage \ Components \ oracle.rdbms.rsf.ic \ 11.1.0.7.0 \ 1 \ DataFiles \ filegroup2.jar)
* Oracle.DataAccess.dll (in ODAC1110710beta.zip \ stage \ Components \ oracle.ntoledb.odp_net_2 \ 11.1.0.7.10 \ 1 \ DataFiles \ filegroup4.jar)
* oraociicus11.dll (in ODAC1110710beta.zip \ stage \ Components \ oracle.rdbms.ic \ 11.1.0.7.0 \ 1 \ DataFiles \ filegroup3.jar)
* OraOps11w.dll (in ODAC1110710beta.zip \ stage \ Components \ oracle.ntoledb.odp_net_2 \ 11.1.0.7.10 \ 1 \ DataFiles \ filegroup3.jar)
You may need the following dll's, but I didn't. I'd get them anyway, just to be safe, as some people say they're needed:
* orannzsbb11.dll (in ODAC1110710beta.zip \ stage \ Components \ oracle.ldap.rsf.ic \ 11.1.0.7.0 \ 1 \ DataFiles \ filegroup1.jar)
* oraocci11.dll (in ODAC1110710beta.zip \ stage \ Components \ oracle.rdbms.rsf.ic \ 11.1.0.7.0 \ 1 \ DataFiles \ filegroup3.jar)
* ociw32.dll (called 'ociw32.dll.dbl' in ODAC1110710beta.zip \ stage \ Components \ oracle.rdbms.rsf.ic \ 11.1.0.7.0 \ 1 \ DataFiles \ filegroup2.jar)
If you get the exception 'The provider is not compatible with the version of Oracle client', don't stress, simply retrace your steps and make sure you get ALL those DLL's from the same ODP.Net / ODAC distribution to avoid version number conflicts, and put them all in the same folder as your EXE (or, in the Bin folder if its an Asp.Net application, then try restarting IIS).
If you download a newer version of ODP.Net, the jar files that enclose the dll's may have moved, so you'll have to manually search through them all, don't worry it won't take *too* long!
Good luck!

Don't forget to rename the ".dll.dbl" files to ".dll"; otherwise you'll get the exception.
Thank you Chris. This was very helpful.
Thankyou Chris, this solution is great and works really well. In fact, my multithreaded app (which does a LOT of queries) performs 57% faster when using your redist pack
dude you are my hero i cant thank you enough great tip!!!
Hi Chris, thanks for the tip. this is really great.
I do however have a question, we only include the dll and not referencing it through the project, i.e. but instantiate it using the System.Data.provider factories, then we do need to use gacutil to install it in the global assemblycache. Is that correct?
SO as an example if I refer this dll in my config as:
Now if I call using the .NET standard classes (System.Data), I can instantiate the oracle connection/command etc by getting its provider factory through below call:
DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings[_dbName].ProviderName);
where _dbName just some variable of the database name.
However, this means that the DLL stills needs to be installed in the GAC using gacutil.exe.
THanks in advance for reading ths.
Hi 'Kts',
I believe you're on the right track there. That does give you the flexibility to use the same code for any database (sql, oracle, postgres, etc). But i think you'd then have to work with the System.Data.Common.* types (eg System.Data.Common.DbConnection). These types are a bit more generic and may have less of the oracle-specific data types, however if you can get it to work then its a great idea!
Also, i'm personally not a fan of the GAC but if it works for you then go for it.
Hi Chris
Thanks for the informative write up. I downloaded the XCOPY version of Oracle 11g ODAC 11.1.0.7.20 and with that the only large file is the oraociei11.dll which is 114MB and looks like that is reqd in the EXE folder. Did you notice the same thing ?
thanks
Sunit
Hi Sunit,
I wasn't aware of an XCOPY version. Give it a try with only that file, maybe it'll work? Let us know if it works.
114megs is pretty big though, the files i described above are only ~30megs.
Still, maybe it supports features that my bare-bones method doesn't. Could be worth remembering!
Cheers
Ok I did find the ClientLite version and could get the files. Now it works in interactive mode, however when I start it as a scheduled job, I get this error
TNS:listener was not given the SERVICE_NAME in CONNECT_DATA
I did add a TNS_ADMIN variable pointing to the tnsnames.ora folder. My connection string is
string.Format("Data Source={0};User Id=/;", server);
Any hints are greatly appreciated.
thanks
Sunit
Update…If I set the TNS_ADMIN variable in code, then it seems to be working. This is what I do for my process's env variables before I inoke any Oracle calls;
Environment.SetEnvironmentVariable("PATH", Environment.CurrentDirectory, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("TNS_ADMIN", tnsAdmin, EnvironmentVariableTarget.Process);
In my case I have Oracle Client 10.2.0.4 installed on 64-bit Vista. I'm using OPD.NET 11.1.0.7
I'm going to test the release version and let you know.
thanks
Sunit
Sunit,
The way you've written your connection string is making oracle look for a TNSNAMES.ORA file.
If you write your connection string like the way i did it in the blog entry, you won't have that problem.
Eg a connection string like this:
Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=1527))
(CONNECT_DATA=(SID=mysid)));User Id=myuserid;Password=mypassword;
Hi Chris,
I tried all the things you mentioned above step by step and it still doesn't work for me.
I keep getting the exception, 'The provider is not compatible with the version of Oracle client' no matter what.
In my case, it appears that the Oracle Data Access components need to be installed on the target machine for this code to work and the reason for this is that it still relies on the ODP.NET 2.111.7.20 registry key being in place. As far as I can see, the only useful thing within that key is the path to the DLLs: C:\ORACLE\11.1\odac\bin. As soon as I remove that key from the registry, the code stops working.
I was wondering when you mentioned “Simple Xcopy deployment” as one of the benefits of this whether you take the registry entry into consideration or not. Does it need to be there for this to work? Can you please clarify it for me?
Hi thomas,
I had the same problem that you're describing. There are 3 things to check:
* Did you get all the dll's from the same download from oracle's site?
* Did you place all these dll's in the same folder as your C# executable?
* Did you rename the .dbl files to .dll as described in my post?
Let me know how you get on.
hi
i m using oracle 10.1.0.2 so what can i do
use the way you mentioned above????
Harshad - that should work just fine. As far as i know, if you're using the latest client dll's then you should be able to connect to any version of oracle.
Give it a try and let us know.
hi
Chris Hulbert,
thanks it works for me tooo……….
Hi Chris,
I did three checks you suggested for Thomas but still gets the same error " 'The provider is not compatible with the version of Oracle client'. I have Oracle client 10.0.2 version installed together with 11g. Is that causing the problem, you think?
hi
chris
i have developed wpf app in Microsoft Visual Studio Team System 2008 Development Edition in C# and oracle 10 g and deployed app as per you told it works fine it gives error to view crystal report
error :-
login failed
plz helppp…..
Hi Harshad, as far as i know crystal reports connects to the database using its own code so this technique is a bit too low-level to help with it. I don't have much crystal experience, but you could try asking on StackOverflow.com they're pretty helpful there.
Hi Chris and Kts,
I am working on the database application, where we have to support different databses (Oracle, MS SQL etc) and in your discussion on this article, you wrote something about system.data.common namespace which one can use to connect to any database. Could you kindly give me some kind of code snippet ?
G'day Wagner,
Here's some code that i think is what you want. Everything uses the system.data.common, and the only oracle specific part is the value of the 'provider' string:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
namespace OdpTest
{
class Program
{
static void Main(string[] args)
{
string connectionString = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=MYHOST)(PORT=1527))(CONNECT_DATA=(SID=MYSERVICE)));User Id=MYUSER;Password=MYPASS;";
string provider = "Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess";
Console.WriteLine("Connecting");
using (DbConnection conn = (DbConnection)Activator.CreateInstance(Type.GetType(provider), connectionString))
{
conn.Open();
Console.WriteLine("Connected");
string sql = @"
select distinct owner
from sys.all_objects
order by owner";
Console.WriteLine("Looking for all DB owners, wait a few seconds:");
using (DbCommand comm = conn.CreateCommand())
{
comm.CommandText = sql;
using (DbDataReader rdr = comm.ExecuteReader())
{
while (rdr.Read())
{
string owner = rdr.GetString(0);
Console.WriteLine("{0}", owner);
}
}
}
}
}
}
}
Thanks Chris… But I am doing it in the other way, by saving providername in the config file and reading the config file during runtime. I want to have one generic class that take care of atleast SQ Server and Oracle. Oracle gives back a ref cursor where as SQL Server returns integer value back. The problem is how to fill dataset with ref cursor. any idea ?
Hi Wagner,
If you modify the code above so that the value of the 'provider' string came from a config file, you'd be half way there.
The generic class you're asking about is above in the 'DbConnection conn' variable, which will handle both SQL and Oracle (and more).
As for filling a dataset, i'm not sure if you can directly create a 'DbDataAdapter' so you'd have to use the specific oracle or sql data adapters. Again, you could put the class name in a config file and instantiate it using Activator.CreateInstance, similarly to above.
Anyway, hope that helps. I'm confident you could achieve what you're attempting.
Hi Chris. I have just read this from oracle website
"For the Fill method to populate the DataSet properly, the SelectCommand of the OracleDataAdapter must be bound with an output parameter of type OracleDbType.RefCursor. If the Fill method is successful, the DataSet is populated with a DataTable that represents a REF CURSOR."
but there is no code example on HOW to do it ? do you have some idea ?
"
Hi,
Great post, exactly what i needed to know. Also for me only oci.dll, oraociicus11.dll and OraOps11w.dll wore needed. I hope for the 64bit version the same files are ok.
Thanks
Hi Wagner,
Sorry mate, you've lost me there, i don't think i can help.
Having said that, i avoid using datasets and data adapters for precisely the reason that you are having problems with them. And i've managed to do just fine without them.
Anyway good luck.
And Eti, that's great, glad to hear.
Thanks wagner for your reply.. Could you please guide me on ho you could have obtained data from SQL Server and Oracle without using data adapters and other things ? If possible a piece of code will prevent further questions.
to make it a bit clear, the stored procedures are called which specify REF CURSOR as outputparameter (only in oracle's case)
sorry mate about the name mistake in my first post… it should be like Thanks Chris ad not wagner
Hi Wagner,
Something like this would do the trick. The FindAll function returns a list of people. This list would be usable to bind to gridviews or the like so would be almost as useful as a dataset, minus all the complication. Hope that helps.
public class People FindAll()
list = new List
();
{
public static List
{
string connectionString = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=MYHOST)(PORT=1527))(CONNECT_DATA=(SID=MYSID)));User Id=MYUSERID;Password=MYPASSWORD;";
string provider = "Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess";
List
using (DbConnection conn = (DbConnection)Activator.
CreateInstance(Type.GetType(provider), connectionString))
{
conn.Open();
using (DbCommand comm = conn.CreateCommand())
{
comm.CommandText = "select id,first_name,last_name from people";
using (DbDataReader rdr = comm.ExecuteReader())
{
while (rdr.Read())
{
Person p = new Person();
p.id = rdr.GetInt32(0);
p.firstName = rdr.GetString(1);
p.lastName = rdr.GetString(2);
list.Add(p);
}
}
}
}
return list;
}
}
public class Person
{
public int id { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
}
Was having the same problem and tried all of the above but could not get it to work. I eventually restarted IIS (wish I'd thought of it earlier) and all was fine!
Good for you gareth, I expect that was due to the DLLs not being loaded dynamically because they're native code not managed.
Having said that, i've only used this code in a console app, not a asp.net web site.
Chris,
Please forgive what may be an obvious question from a newbie, but I'm having trouble with the simple deployment method described in this blog post. I'm still getting "The provider is not compatible with the version of Oracle client" exceptions. Could there be a problem if there is a different Oracle client version already installed on the target machine?
Hi Otto,
Is this a winforms or asp.net or console application?
If winforms/console, can you list the contents of the folder where your executable is placed?
If asp.net, can you list the contents of the BIN folder underneath your application root?
When you say 'target machine' do you mean the oracle server, or the computer your application is running on?
You can also try stackoverflow.com if you need a quicker answer than i may be able to provide.
All the best
Problem was an issue with my deployment manifest file, which was keeping the dll's from being included in the ClickOnce deployment. Manifest file is straightened out, and all is working well now, even on target machines with other Oracle clients already installed.
Thanks.
That's good to hear otto, thanks for the feedback.
I was looking for the above DLLs in my locally installed Oracle Client home, and copying to web server's BIN folder. I could not find oraociicus11.dll. So I just copied the other DLLs. It still worked.
your post helps me a lot. thanks
Hi,
I try to make the same thing with a 10.2.0.4 client version.
I've take the 10.2.0.4 Instant Client Basic Lite dll's and the 10.204 Oracle.DataAcess.dll,but I still gets the same error " 'The provider is not compatible with the version of Oracle client'.
But when I test your configuration on a pc with a 10.2.0.4 client installed, it's work.
All the dll are in my exe directory. I don't understand that is wrong.
Can you help me ?
Sylvain,
First up, what are the name of all the dll's in the same folder as your EXE? Maybe you're missing one or two, and so it looks in the system folder for the missing dll/dlls and on your pc it finds an incompatible version, and on the other pc it finds a compatible version.
Cheers
Thank you Chris, This solution is great and works really well. I cant thank you enough great tip.
Thanks for this post, man!
Finally i got everything working.
But there is an more easy way to get the required .dlls. Yout can download ODAC1110720Xcopy.zip, extract it, and search in it for *.dll - every .dll you need is somewhere in this directory… most of them in instantclient_11_1.
I got the error "provider not compatible", but as i deleted the file oraociei11.dll, the error was gone.
Thanks!
Thanks mojo, very helpful.
However, i tried that method, and it wouldn't work without the 'oraociei11.dll' file. Which is an issue to me, because that file is 114 megs! Thats huge for just a database driver!
The people where I work are hesitant to install 11g client along side the current 10g client so I tried your method here but it didn't work as hoped.
I'm trying to use ODP.NET is an ASP.NET application. I don't have any access to the server and IIS unfortunately. I created a Bin folder, dumped the files you mentioned there, and tried it. Trying to connect using ODP.NET only returns a blank exception (the most unhelpful kind really). On top of that the way I was connecting, using System.Data.OracleClient, stopped working. It now says OCIEnvCreate returns -1. And finally, oci.dll can't be deleted from the Bin folder. It says it's in use. What is ASP.NET doing with that file that it'd be in constant use?
Ah, and lest I forget, I did get someone to restart IIS and that didn't work.
Do you have any ideas? Since I found this through Stackoverflow I figure you also know I asked this question there as well: http://stackoverflow.com/questions/2142877/oracle-oci-dll-in-asp-net-bin-directory-cant-be-deleted-doesnt-work
Hi ,
I was getting the error " 'The provider is not compatible with the version of Oracle client'. just after I copy msvcr71.dll it worked
finally a working solution!!! you're a savior man. many thanks!
thanks so much, after I spent 1.5 days trying to connect to Oracle 10g from visual studio 2008…
Thanks for the example.
Brilliant,
Works well, but on a fresh machine build we HAD to include msvcr71.dll also.
This file is not required for 64-bit.
We use only the following files from the Oracle 11.2.0.1 distro;
msvcr71.dll - 340Kb
oci.dll - 964Kb
Oracle.DataAccess.dll - 992Kb
oraociicus11.dll - 32,152Kb
OraOps11w.dll - 404Kb
Overall a 40Mb increase in application size.
For 64-bit servers, just replace all the same files from the 64bit distro with the exception of msvcr71.dll.
Find this method to be about 10% faster over the Microsoft provider.
Thanks for the blog. Saved us a lot of hassle.
Thanks dude. This worked for me. Saved me a lot of time and pain
The XCopy Instant Client seems to work for me during compilcation. But, the OracleConnection.Open is throwing a Object Reference not set exception.
My Connection string looks like this,
"DATA SOURCE=//testservice.edu:1605/hscp;PASSWORD=userid;USER ID=password"
Please help!
Sundeep, your connection string should be the following:
"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=testservice.edu)(PORT=1605))(CONNECT_DATA=(SID=hscp)));User Id=userid;Password=password;"
Chris,
Still no luck. I am getting a blank exception when trying to Open the connection and the inner exception is saying 'Object Reference Not set Exception'. I will be happy to provide any information you want. Please help me figure this out.
Thank You
Sundeep
Hi Sundeep,
You should ask on stackoverflow.com - you'll definitely get an answer there, much quicker than i can help you. I suspect you're missing some of the oracle DLL's.
Good luck