atsukanrockのブログ

Microsoft系技術を中心にぼちぼち更新します

ODP.NETのバージョン問題

はじめに

ADO.NETOracle製接続プロバイダである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>

その他の情報

以下に、ODP.NETのバージョンに関係する、その他の情報を示しておく。

ODP.NETのアセンブリバージョンアップ

ODP.NETのアセンブリバージョンは、Oracle Clientのバージョンが少しでも違えば原則異なる。PSRやPatchXなど*8のパッチ適用でも変わる。

ODP.NET自体のGACへの登録

ODP.NET自体*9は、必ずGACに自動登録される。ただし、ODP.NET 10.2.0.2.20の.NET 2.0以降用アセンブリ(2.102.2.20)は、不具合によりGACに自動登録されないという報告がある。もし自動登録されなかったら、手動で登録することになる。

複数バージョンへの対応

そもそも、1台のマシンに複数バージョンのODP.NETがインストールされている状態での動作が保証されているのは、10.1.0.3.01以降である。それより古いバージョンのODP.NETは、動作保証されていない。

ただし、動作保証しているにも関わらず発行者ポリシーにまつわる数々の問題があるのは、前述のとおりである。ここでいう「動作保証」とは、Oracle Clientが別々のORACLE_HOMEにインストールされることを指しているように思える。

*1:この文言はMicrosoftの日本語。Oracleの日本語では「パブリッシャ・ポリシー」、Microsoftの英語では「Publisher Policy」となる

*2:Oracle側からすれば、あくまで「仕様」である

*3:そして、開発環境で再現しないエラーが起こる

*4:アセンブリバージョンではない

*5:Oracle Clientとの違いは何だろう?わかりにくい…

*6:アセンブリバージョンではない

*7:顧客に条件を強いることができない

*8:それが何なのか、詳しくは知らないが

*9:発行者ポリシーではなく、という意味で「自体」