I am trying to write a visual studio C# .net app which i can put on a subversion repository. The program runs on oracle drivers (Oracle.dataAccess) and should be easily managed and developed by anybody trying to access it. The problem is that Visual Studio finds the Oracle.DataAccess installed on the developer's computer and some random user with any version of oracle, or no oracle drivers installed, will have to change a lot of configurations after downloading the file to edit it. I'm trying to find a way to get around that, any help will be fine.
I don't want to package any instant client DLLs with the project because the server the repository is on is very slow.
You don't need to worry as long as the other machines have the minimum version you originally linked against installed.
When you install the client drivers on your machine, it should register Oracle.DataAccess.dll in the Global Assembly Cache (GAC). You can see the contents of the GAC by browsing to C:\Windows\Assembly:
Notice that the installation also installs "policy" files in the GAC. These are binding redirect publisher policies, which, when a program that is linked against an earlier version of Oracle.DataAccess.dll tries to look it up in the GAC, it gets redirected to the newer version at runtime instead. In fact, even if you redistributed the driver with your program, it still might load up a newer version from the GAC if it finds a newer one instead of the one you redistributed with your program.
I think the only way around the issue is
to package any instant client DLLs
with the project
Even with a slow server, you'd only have to get these files once (on checkout) and then just get updates, if any, or when checking out "clean".
Related
I have a c# console application which is scheduled to import bulk data from oracle to sql database. I am leaning towards using the oracle client dlls from the installation folder instead of having it installed on server. I read many existing SO answers on copying required dlls in installation folder.
https://jeremybranham.wordpress.com/2011/04/25/oracle-instant-client-with-odp-net/
The application works fine on my windows 10 machine where no oracle client is installed. But on Windows Server 2008 R2 it throws error saying OraOps12.dll is not found. Though I have the dll available. What can I do to troubleshoot the issue?
Make sure the dll is referenced in the project and it's set to copy to the output directory. I can't explain why, but I have had referenced dll's not set to copy and have run into similar issues as you are describing.
I think it is a bad idea to copy the DLL's from the Oracle Client manually. You may provide a copy of Oracle.DataAccess.dll - for all the rest ask your customer to install an appropriate Oracle Client, i.e. the version and architecture has to match the Oracle.DataAccess.dll.
Or use the ODP.NET Managed Driver (Oracle.ManagedDataAccess.dll), this is a stand-alone DLL which does not require any additional file.
Finally I could work it out without actually installing Oracle Client on the server. I was receiving error about not able to load OraOps12.dll but eventually I found out that the dll I was missing was msvcr120.dll. The dll is Microsoft Visual C++ Runtime. So now, I have following Oracle dlls in my deployment folder & the application is working. No changes in configuration are required.
msvcr120.dll
Oracle.DataAccess.dll
OraOps12.dll
oraociei12.dll
oraons.dll
oci.dll
I have a multi-project solution (C#) that I am trying to deploy to one of our test servers. All the projects are being built for x64, with the 'Prefer 32 bit' disabled where applicable.
Some of the projects reference a SQLite dll set that uses the SQLite Encryption Extension (not managed by nuget). When I build and install the solution on my local dev machine, the application and windows service are able to function properly, no problems.
When I try to install the same package on one of our test servers, running 64-bit Windows Server 2012, I get the "Unable to load DLL 'SQLite.Interop.dll': The specified module could not be found." whenever I try to communicate with the SQLite database. I have triple checked that all the appropriate DLLs are in the program folder after installation.
In my VS solution, I have tried creating the x86/x64 folders, setting Copy to Always, but to no avail. I have also copied the DLLs from my local install folder into the server folder just to see if something got messed up along the way.
Could it be a permissions issue? I'm an elevated user but not a full admin on the server, whereas I'm a full admin on my machine. I've tried manually modifying the permissions on the program folder to see if that was an issue, but had no luck with that either.
So to summarize, the project is being explicitly built for x64, it has the right DLLs in the right folders, and it works on a local install. I'm at a loss as to why it won't work on the server install. I've looked through countless threads on StackOverflow, MSDN, and SQLite's website, all usually suggesting the x86/x64 folders, but that hasn't been working for me. I'm hoping someone can help me out here.
Thanks!
Was actually able to figure it out after a bit more debugging. The Visual C++ runtime that was installed on the server wasn't the right version. I added the Merge Module to the installer for the version my project was expecting, reinstalled the app on the server, and now it's working beautifully.
For those who have this issue, look for the right version of the VC++ runtime in C:\Program Files(x86)\Common Files\Merge Modules. If you don't know what version you need, use something like dependency walker on the machine that is throwing the error. Mine told me I was missing VC140, so that's the module I copied into my project and added to the installer.
I have oracle 10g client(full) and 11g instant client installed on my machine.
I am trying to use ODP.NET 12c. Here is what I did.
Added Oracle.DataAccess.dll to References.
Copied OraOps12.dll to the folder where my executable is.
When running I got "Unable to load DLL 'OraOps12.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)".
I think it could be due to dependency issue. So I further copied 12c's
oci.dll
oraociei12.dll
orannzsbb12.dll
I then still got other dependency errors. I don't want to copy the whole InstantClient though.
My goal is to get the app to work with other versions of Oracle client.
Our customers have different version of Oracle client installed. So any way to get the app (ODAC12c) work with customers' current version of Oracle client without having to install 12c client?
Thanks,
Update:
I forgot to mention a few things
my ODAC is 32bit and I compiled my app on x86.
I didn't use Oracle.ManagedDataAccess.dll because it does not include BULKCOPY classs. If anyone knows a version of Oracle.ManagedDataAccess.dll that includes bulkcopy class please let me know.
Our customers already has different versions of Oracle client installed for other apps and they don't want to change their environment just for this new app. So my goal becomes to make one version of ODAC in my app work with different versions of existing Oracle client (each customer environment is different). Is this possible and if yes, how?
You know, I just spent 5 minutes looking for the guy that I remember attempting this before...and it turned out to be you shawn ;).
Honestly, to rely on what the client has installed is a crap-shoot. I would use the full xcopy package, get it working, and then work backwards, deleting what is not needed.
Don't run the install.bat that comes with it. Doing so adds registry entries that aid in locating the unmanaged binaries, but you also risk messing with a client installed copy.
Drop the whole xcopy install into your app's folder as a subfolder.
Instead, set the DllPath to this new subfolder
Example:
<oracle.dataaccess.client>
<settings>
<add name="DllPath" value="C:\app\user\product\11.1.0\client_1\BIN"/>
Then set the Oracle_Home environment variable
Example:
Environment.SetEnvironmentVariable("ORACLE_HOME", #"C:\app\user\product\11.1.0\client_1\");
This article does something similar:
http://dbaportal.eu/2013/02/22/true-xcopy-runtime-for-oracle-odp-net-application/
He even adds a policy to redirect in case he has referenced projects that reference a particular version of Oracle.DataAccess.dll
He adds his oracle home with a batch file though. The part I'm not so sure of is that he also adds his new xcopy install to the path with that same batch file. DllPath should take care of that, but if I'm wrong, you can also do that at runtime:
Environment.SetEnvironmentVariable("PATH", #"C:\app\user\product\11.1.0\client_1\BIN");
From here, I'd setup some basic unit tests using all the ODP.net functionality you are using and get some positive tests and then work backwards - start deleting what you don't need, running your tests each time. You might be able to use sysinternals procexp to show loaded dlls (or procmon to show access to the files). Just loading your tests might be enough to lock the files so you can delete all the ones that aren't locked.
I'm not sure doing this is supported. Then again Oracle does list "the current application's directory" in the unmanaged search order so they didn't close the door either.
EDIT:
Found one of the links of other people doing this:
http://alderprogs.blogspot.com/2009/04/deploying-odpnet-with-oracle-instant.html
I'm not sure why but they download the instant client separately (it's already part of the xcopy package).
EDIT 4/15/2016: If you're reading this these days note two things. 1) I don't think setting the environment variables are necessary if you are already setting DllPath. 2) I don't think this is worth doing when the managed provider now only requires one or two dlls.
It's a bad idea to copy single DLL's to different directories and hope it will work.
In general ODP.NET provider works only together with corresponding Oracle Client, i.e. in order to use ODP.NET 12 you must also install Oracle Client 12. Same applies for version 11 or 10.
Only exception is the ODP.NET Managed Driver, there you need only a single DLL (Oracle.ManagedDataAccess.dll).
Furthermore the architecture (32 bit vs. 64 bit) has to match.
In case you use OLEDB provider it's even not possible to have more than one provider installed (for each architecture) - unless you hack your system by manipulating PATH variable and Registry all the time.
My proposal would be: Remove all Oracle Clients from your machine and install only one (or one per architecture) Oracle Client properly. It's very unlikely that an application works with one Oracle Client version only. It is also a good approach to install both 32bit and 64bit on one machine, follow this instruction to do it: Install Oracle x86 and X64 on one machine
In case you really need to test your application with different Oracle Client version, setup a couple of test-PC (maybe in a Virtual-Box) each with a different Client version. Otherwise it will be very challenging to handle it.
Update:
I think each (Unmanaged) ODP.NET version works only with according version of Oracle Client. Maybe by chance there are some combinations which work out but in general the versions should match.
I see two different solutions:
(1) Ask your client to install his Oracle Client including ODP.NET. He can choose the version, only the architecture (32 bit or 64 bit) has to match. Then you don't supply any ODP.NET with your application.
In your *.csproj, resp. *.vbproj file define your reference like this:
<Reference Include="Oracle.DataAccess">
<SpecificVersion>False</SpecificVersion>
<Private>False</Private>
</Reference>
Attributes like Version=... or processorArchitecture=... are not required. Then your application should run with any Oracle/ODP.NET version.
Your customer can download ODP.NET provider from here: Oracle Data Access Components (ODAC) for Windows Downloads and install it on top of existing Oracle Client installation. In readme.txt it says "The files of this zip file is NOT to be installed on top of an existing
Oracle Universal Installer (OUI) based Oracle Home installation.", however I don't see any reason why not doing it. It works well, you just have to carefully provide correct folder for existing Oracle installation and correct ORACLE_HOME name and do not install dependencies.
(2) In your setup script/exe determine the Version of customer installed Oracle Client and copy according ODP.NET to customer machine.
In order to determine version of Oracle Client you can to search for file oci.dll in folders provided by PATH environment. oci.dll is a normal .NET assembly, so you can read out the version easily.
For a proper installation of ODP.NET follow the file configure.bat which is part of downloaded ODP.NET XCopy version. In my opinion this batch file is easy to understand.
Basically it does
1 - Copy file Oracle.DataAccess.dll to target machine
2 - Copy different resource files *\Oracle.DataAccess.resources.dll to target machen
3 - Add these DLL's to the GAC. This can be done by gacutil.exe or OraProvCfg.exe (included in downloader ZIP file) or your setup application provides this operation.
4 - Make a few Regristy entries. Newer ODP.NET versions write/read into HKLM\SOFTWARE\Wow6432Node\Oracle\ODP.NET (for 32 bit), resp. HKLM\SOFTWARE\Oracle\ODP.NET (for 64 bit). Older ODP.NET versions use HKLM\SOFTWARE\Oracle\KEY_{ORACLE_HOME_KEY}\ODP.NET\ (for 64 bit), resp HKLM\SOFTWARE\Wow6432Node\Oracle\KEY_{ORACLE_HOME_KEY}\ODP.NET\ (for 32 bit) instead
That's it, you should be able to include this in your setup.
My project makes use of the Oracle.DataAccess.dll DLL and when I build and run my application it works fine on my PC, as I have added the reference in my project to it C:\Oracle\instantclient_11_2_dc\odp.net\bin\4\Oracle.DataAccess.dll
However when I run on another machine without this reference it fails installation with the following message.
How do I include the DLL file in my project so it is deployed with it as as requirement, and doesn't reference my local file system?
You have to install the Oracle client on the client machine if this is a client/server application. If it is web based application then it should be installed there.
I don't use the instant client as I end up wanting to edit the connections in the TNSNames.ora so I use the full or Administrator install.
The client version will usually connect back or forward two Oracle versions but life is easier if you use the version appropriate to your database version.
You'll want to install the Oracle Data Access Components from here: http://www.oracle.com/technetwork/topics/dotnet/downloads/net-downloads-160392.html?ssSourceSiteId=ocomen on your dev machine AND any servers you plan on deploying to (or you can xcopy install per How can I deploy a .NET application that uses ODAC without installing the whole component to the user?). Also marked Q as duplicate to this one.
I have developed a C# winform application in Visual Studio 2010 that connects to a Access 2010 *.accdb database. It works fine on my pc but when I install it on another, It throws the error "The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine."
I tried to compile it to x86, as advised, without any succes.
Any help/advice is appreciated, I think that I should include this driver as part of my clickOnce install. If so, how do I do so? (It does not appear as an option in the checklist of requirements, in VS Properties > Publish > Previous requirements)
You will have to use a more advanced method of deploying the necessary driver - ClickOnce won't do it by itself as far as I know. I also don't think it's as simple as a single DLL. The driver needs to register with the system etc.
There is a big issue with the Access drivers because of the way they are set up. If the user has Microsoft Office with Access installed, they will already have the ACE driver. The problem is, if they have 32 bit Access installed on a 64 bit machine, your 64 bit application will not be able to talk to Access because the machine only has a 32 bit driver, and you cannot install both.
If none of your users have Microsoft Office with Access, then you should be able to deploy the standalone driver installer for 32/64 bit as necessary with each computer.
It is possible to include arbitrary assemblies and files as part of your ClickOnce install by adding them to the project and changing their file type to Content. They will then appear in the list of Application Files.
Note that you'll get a warning from Visual Studio if you do this, but it can be safely ignored.
You can build an msi instead of oneclick and create a custom action that would install ace driver in quiet mode. Since its an executable you can just run it in a process object