ODP.NETのバージョン問題
はじめに
ADO.NETのOracle製接続プロバイダであるODP.NETには、バージョン問題が存在する。ここで言うバージョン問題とは、アプリケーションの開発者が意図しないバージョンのODP.NETが、アプリケーションの実行時に使用されてしまうことを指す。
本エントリでは、その問題の原因と解決策(案)を述べる。
なお、ODP.NETのバージョニング体系については、『Oracle Data Provider for .NET開発者ガイド』の該当ページ(リンクは11g)を参照されたい。
問題の原因
ODP.NETと同時にGACにインストールされる発行者ポリシー*1の仕様*2によって、バージョン問題が発生する。
.NETの基本的なバージョン管理
.NETでは、side-by-side実行と呼ばれるバージョン管理が基本である。この仕組みは、@ITの連載記事でわかりやすく解説されている。
簡単に言うと、.NETアプリケーションは、アプリケーションをビルドした際に参照していたバージョンのアセンブリを、実行時にも使うという仕組みだ。この仕組みは、例えばあるアプリケーションが参照するアセンブリについて、複数の異なるバージョンがアプリケーション実行時に参照可能な場合に活きる。side-by-side実行により、アプリケーションが互換性のない別バージョンのアセンブリを参照してしまう*3ことを防げる。
発行者ポリシーとは
発行者ポリシーとは、side-by-side実行の原則を崩す仕組みである。発行者ポリシーにより、アセンブリの開発者が、アプリケーションの開発者がアプリケーションをビルドした際に参照していたのと異なるバージョンのアセンブリを、アプリケーションの実行時に参照させることができる。この仕組みは、@ITの連載記事でわかりやすく解説されている。
なぜそんな仕組みが必要かと言うと、アセンブリ開発者の「最新バージョンを使って欲しい」という希望を満たすためだ。
そして、OracleはODP.NETでこの仕組みを利用している。アプリケーションの実行マシンに複数バージョンのOracle Clientをインストールしている場合、ODP.NETは「基本的に」互換性のある最新バージョンが参照される。なぜ、「基本的に」を強調したか。例外があるからだ。この例外は、悪夢である。
ODP.NETの発行者ポリシー
「発行者ポリシーとは」で説明したのが、ODP.NETの発行者ポリシーの基本だ。しかし、この基本に反する例外が、数多くあるのがODP.NETの現実だ。一言で言うと、「バグとしか言えない仕様が盛り沢山」である。
その結果どうなるか。ODP.NETについては、以下のどちらも成り立たない。マシンにインストールされているODP.NETのバージョンの組み合わせにより、アプリケーションからどのバージョンのODP.NETが参照されるかが変化する。
- 常にside-by-side実行
- 常に互換性のある最新バージョンが参照される
発行者ポリシー自体のバージョンの問題
.NETの仕様で、複数バージョンの発行者ポリシーがGACにインストールされている場合、最新バージョンが適用される。この仕様自体は問題ないのだが、ODP.NETの発行者ポリシーのバージョンの付け方に問題がある。それは、以下のようなものである。
ODP.NETのバージョン | アセンブリバージョン | アセンブリバージョンの例 |
10.2.0.2.20より前 | ODP.NETのバージョンと同じ | 10.2.0.100 |
10.2.0.2.20以降 | メジャーバージョンが.NET Frameworkのものと同じ | 2.102.2.20 |
バージョンの付け方がこのようであるため、10.2.0.2.20より前の発行者ポリシー(「旧発行者ポリシー」とする)がGACにインストールされている状態で、10.2.0.2.20以降のODP.NET(「新ODP.NET」とする)をインストールしても、10.2.0.2.20以降のODP.NETの発行者ポリシーが使用されない。当然、旧発行者ポリシーは新ODP.NETを知らないので、新ODP.NETへのリダイレクトは行われない。この状態を脱するには、旧発行者ポリシーをGACから手動でアンインストールする必要がある。
GACへのインストールの問題
発行者ポリシーは基本的にGACにインストールするものだ。しかし、ODP.NETの発行者ポリシーは、ODP.NETのバージョンによって、自動的にGACにインストールされたりされなかったりする。発行者ポリシーが自動インストールされないバージョンを使う場合、その発行者ポリシーを有効にするためには、手動でGACにインストールすることになる。
Oracle Clientのバージョン | ODP.NETのバージョン*4 | 発行者ポリシーのGACへの自動登録 |
10.1.0.2 | 10.1.0.2 | |
10.2.0.1 | 10.2.0.1 | V |
また、ODAC(Oracle Data Access Components)*5についても同様である。
ODACのバージョン | ODP.NETのバージョン*6 | 発行者ポリシーのGACへの自動登録 |
9.2.0.4 | 9.2.0.4.01 | V |
9.2.0.7 | 9.2.0.7 | V |
10.1.0.3 | 10.1.0.3.01 | V |
10.1.0.4 | 10.1.0.4 | V |
10.2.0.2.21 | 10.2.0.2.21 | |
11.1.0.6.21 | 11.1.0.6.20 |
解決策(案)
保証しない
まず第一に考えたいのが、複数バージョンのOracle Clientをインストールしたマシンでの動作を保証しないということだ。
エンタープライズ開発であれば、アプリケーションの実行環境を限定できることも多いはずなので、不可能な解決策ではない。もし実行環境の限定ができなくても、「動作保証するためには動作検証が必要なので動作保証はできないが、Oracle社が『動作するはずである』という見解なので、動作する『はずである』」といったニュアンスを伝えれば、顧客に認められる可能性がある。
発行者ポリシーを無効にする
アプリケーション構成ファイルで、発行者ポリシーを無効にできるので、それを利用するという手もある。これは消極的解決策と言えよう。開発サイドの立場が弱い*7ことを前提にした解決策だからだ。
その方法については、「アセンブリ バージョンのリダイレクト」(MSDN)の「発行者ポリシーの省略」に説明が、「構成ファイル内でのアセンブリ バインディングの指定」に例が示されている。念のため、以下に簡単なサンプルを示す。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <runtime> <asm:assemblyBinding xmlns:asm="urn:schemas-microsoft-com:asm.v1"> <asm:dependentAssembly> <asm:assemblyIdentity name="Oracle.DataAccess" culture="neutral" publicKeyToken="89b483f429c47342"/> <!--バージョンリダイレクトを有効にするには、この要素のapply属性をyesにする--> <asm:publisherPolicy apply="no"/> </asm:dependentAssembly> </asm:assemblyBinding> </runtime> </configuration>