True XCOPY runtime for Oracle ODP.NET application
I was struggling for quite some time with my colleague at work on migration of our legacy (ODAC 10g + .NET 2.0) client/server applications to centrally managed runtime environment. Applications that run flawlessly by the users with Windows XP SP3, stopped working on newer configurations with Windows 7 x64 and ODAC 11g R5.
This is a short memo on how to prepare runtime environment for Oracle ODAC based .NET application that can be run from a network drive. Oracle at the time of this writing does NOT have a proper document covering a “true” XCOPY based installation. With a “true” XCOPY installation I mean the one that doesn’t need any super user privilege to install application on client — we want totally GAC agnostic ODP.NET application runtime env. In short, we don’t want to run neither install.bat nor configure.bat script from ODAC client zip file shipped by Oracle.
(If you wonder why? Because GAC is utterly disgusting .NET “thing”, almost as disgusting as the windows registry, and a clear evidence that MS will never learn from *nix).
In summary the objective is:
- allow our end users with Windows XP SP3 (32-bit) or Windows 7 EE (32-bit or 64-bit) to run simple WinForms .NET applications in C/S mode
- some clients are also developers with local (“by-the-book”) installation of ODAC (10g, 11g) with GAC registrations, they should be able to run prod. applications in a complete isolation from their local environment.
- all .NET application must be installed centrally on our main file server and must as well use centrally installed Oracle client with ODAC
- all that is needed to install application on client workstation is to create shortcut that points to startup routine to launch application from file server. No super-user privilege is allowed as a prerequisite for application installation!
And here are the steps that we followed:
- Download “ODAC 11.2 Release 5 (22.214.171.124.20) with Xcopy Deployment” from OTN”
- Unzip ODAC1120320Xcopy_32bit.zip to some temporary directory, let’s say G:\TEMP. Then copy relevant directories (in our case instant client + ODP.NET 4.0) to network drive.
Do NOT run install.bat! Let’s say that our target network directory that’ll be used by all .NET apps is N:\ORACLE\ORA11odacR5.
// copy instant client and odp.net4 from temp directory
// to network based N:\ORACLE\ORA11odacR5
cmd> cd g:\temp
cmd> xcopy instantclient_11_2 N:\ORACLE\ora11odacR5 /I /E /F /R /Y
cmd> xcopy odp.net4 N:\ORACLE\ora11odacR5 /I /E /F /R /Y
- make sure that .NET application build is targeted at .NET 4.0 and x86 platform. We do NOT recommend using “Any CPU” for mix (32-bit & 64-bit) clients, sometimes we run into problems on x64. We also strongly recommend using 4.0 for the lowest .NET target framework. Previously (.NET 2.0 – 3.5) we needed to authorize client PC’s before users could run .NET apps from our file server. On .NET 4.0 this is not necessary any more. Since 4.0 is the highest .NET framework version still supported on XP SP3 the decision to deploy to 4.0 was trivial. Some screenshots showing our build instructions:
Note that on second picture application “build” is using locally installed Oracle.DataAccess.dll (framed in blue) and this is ok. Developers can use whatever Oracle.DataAccess.dll they want, even an older one (one of our application was developed with 10g Oracle.DataAccess.dll, but deployed to runtime env. with ODAC11g R5), because in the next step we’ll override developer “choice” with our network based (latest) ODAC 11g R5. And this can be done with app. config.
- Generate and then customize application config xml file (in our case OraDUAL.exe.config. And precisely here is where Oracle documentation is not clear and precise enough. How should application config look like that could be used on workstation without any Oracle client (more precisely on workstation where Oracle OUI or install.bat didn’t run, hence machine.config is untouched).
<?xml version="1.0" encoding="utf-8" ?> <configuration> <!-- configSections was copied here from one of our developer's machine.config where ODAC11g R5 was installed with install.bat. Note that you can not blindly copy this section because different ODAC version may have different PublicKeyToken. Always check what Oracle sets up! --> <configSections> <section name="oracle.dataaccess.client" type="System.Data.Common.DbProviderConfigurationHandler, System.Data, Version=126.96.36.199, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <section name="system.data.oracleclient" type="System.Data.Common.DbProviderConfigurationHandler, System.Data, Version=188.8.131.52, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </configSections> <!-- This section needs either properly edited machine.config from Oracle OUI (or install.bat from instant client) or manually added configSections (see above). Note that DllPath needs to point to the Instant client directory, not to the Oracle.DataAccess.dll directory! --> <oracle.dataaccess.client> <settings> <add name="DllPath" value="N:\ORACLE\ORA11odacR5"/> <add name="FetchSize" value="65536"/> <add name="PromotableTransaction" value="promotable"/> <add name="StatementCacheSize" value="0"/> <add name="TraceFileName" value="%TEMP%\odpnet.trc"/> <add name="TraceLevel" value="0"/> <add name="TraceOption" value="0"/> </settings> </oracle.dataaccess.client> <!-- Here we're telling .NET framework two things: - which version of Oracle.DataAccess.dll we want to be used - and from where exactly it should load the assembly. Any version of Oracle.DataAccess.dll between 0.0.0.0 and 184.108.40.206 will be replaced by 220.127.116.11. Note that publicKeyToken is "hash" dedicated to Oracle Corp. but might change in the future. We checked the token against GAC. --> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <publisherPolicy apply="no" /> <assemblyIdentity name="Oracle.DataAccess" publicKeyToken="89B483F429C47342" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-18.104.22.168" newVersion="22.214.171.124"/> <codeBase version="126.96.36.199" href="file:///N:\ORACLE\ORA11odacR5\odp.net4\odp.net\bin\4\Oracle.DataAccess.dll"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
In case the application is build with additional libraries that internally depends on Oracle data provider (Oracle.DataAccess.dll) the same kind of config file needs to be prepared for each library (for example if OraDUAL.exe needs OraAcme.dll and OraAcme.dll is referencing Oracle.DataAccess.dll, then OraAcme.dll.config must be present with redirecting directives already shown in app.config).
- The final step is to prepare batch routine to launch our application from network drive.
:: RunOraDUAL.bat :: Oracle11g [188.8.131.52] Instant Client with ODAC 184.108.40.206.20 :: :: Batch routine to launch OraDUAL.exe from newtork drive. :: :: --------------------------------------------------------- title Oracle11g Instant Client - ODAC 220.127.116.11.20 SET NLS_LANG=SLOVENIAN_SLOVENIA.EE8MSWIN1250 SET NLS_DATE_FORMAT=DD.MM.YYYY SET ORACLE_HOME=N:\ORACLE\ORA11ODACR5 SET TNS_ADMIN=N:\ORACLE\ORA11ODACR5 SET PATH=%ORACLE_HOME%;%ORACLE_HOME%\ODP.NET4\BIN;%ORACLE_HOME%\odp.net4\odp.net\bin\4;%PATH%; start OraDUAL.exe :: End
Make sure that you include both \BIN directories that belongs to ODP.NET4 to the path!
In our case we put RunOraDUAL.bat in the same directory with OraDUAL.exe and OraDUAL.exe.config.
Note that you do NOT need to place Oracle.DataAccess.dll to application directory even though VisualStudio will copy
Oracle.DataAccess.dll in \BUILD directory because we instructed this with “Copy Local = True” (refer to screenshot #2)!
The only thing we copied to network share N:\APPS\OraDual is exe and config file.