3

C# 内には、DB を更新する OracleConnection と、DB を更新するために C# が呼び出すレガシー VB6 DLL への参照があります (DLL 内では、ADODB.Connection オブジェクトを使用します)。

管理された更新と管理されていない更新の両方が一緒にロールバックまたはコミットされるように、両方を 1 つの大きなトランザクションにラップする必要があります。

System.EnterpriseServices.ServicedComponent から継承し、[Transaction(TransactionOption.Required)] で装飾されるように C# クラスを切り替えてから、呼び出しシーケンスを開始するメソッドで [AutoComplete] を使用して、最終的に OracleConnection と VB6 にヒットするようにしました。 DLL の呼び出し。

このような:

using System.EnterpriseServices;

{
    [Transaction(TransactionOption.Required)]
    public class MyClassTx: ServicedComponent
    {
        private MyClass1 _myClass1;

        public MyClassTx()
        {
        }

        // This method automatically commits the transaction if it succeeds.
        [AutoComplete]
        public void DoStuffTransactionally()
        {
        // Calls into different objects, doing some work that I'd like to have
        // a big transaction around.
        _MyClass1 = new MyClass1()
        _MyClass1.DoSomeStuff();
        }
    }
}

ただし、テスト ハーネスが MyClassTx をインスタンス化しようとすると、次のエラーが発生します。

{System.EnterpriseServices.RegistrationException: Invalid ServicedComponent-derived classes were found in the assembly.
(Classes must be public, concrete, have a public default constructor, and meet all other ComVisibility requirements)

クラスが public で具象的で、パラメーターのないコンストラクターを持っていることを確認しました。それでも、インスタンス化されません。

デバッグする前に、アセンブリを厳密に型指定して COM+ パッケージに入れる必要がありますか? VS2010 を使用すれば、ServicedComponent を継承するコードにステップインできると思っていたでしょう。

COM+ を使用してから約 8 年になりますが、C# で動作させるのはこれが初めてです。

また、ここでばかげた道を進んでいて、マネージド コードとアンマネージド コードを同じトランザクションに入れる簡単な方法がある場合は、教えてください!

数時間 Google を使用しても、あまり役に立ちませんでした。

どうもありがとう!!

4

1 に答える 1

3

わかりました、私はこれで大きな進歩を遂げたと思います。

これをすべて機能させるために必要な追加の手順:

  1. アセンブリは ComVisible として設定する必要がありました。
  2. [assembly: System.EnterpriseServices.ApplicationName("blahblah")] 値を設定する必要がありました... blahblah が COM+ パッケージの名前になります。
  3. アセンブリには厳密な名前を付ける必要があり、regsvcs.exe を使用して COM+ に登録する必要がありました。ライブラリのアクティベーションを使用するように設定されていますが、それが必要かどうかは完全にはわかりません。サーバーのアクティブ化として試しましたが、それを呼び出すコードが何らかの種類の COM 例外をスローしました。
  4. OracleConnection.EnlistDistributedTransaction を呼び出し、次のように ContextUtil.Transaction (トランザクションとしてキャスト) を渡す必要があります。

    connection.EnlistDistributedTransaction((ITransaction)ContextUtil.Transaction);

この後、コンポーネント サービス ウィンドウの COM+ アプリケーション リストにアセンブリが表示されました。わーい!

さらに良いことに、VS2010 でデバッグしたとき、DoStuffTransactionally メソッドに入ったとき、コンポーネント サービス エクスプローラーで新しいトランザクションがアクティブでした。

それで、それでデバッグを行うことができました。

ただし、マネージ コードだけでなく、DoStuffTransactionally の奥深くで呼び出される従来の VB6 コードも含むトランザクションを実際に取得するには、私のマネージ コードが含まれる COM+ アプリケーションに従来の VB6 COM オブジェクトを追加する必要がありました。 Oracle を呼び出していたので、VB6 コードが使用していた接続文字列を変更して、DistribTX=1 と PROMOTABLE TRANSACTION=PROMOTABLE を設定する必要がありました。その後、コードはマネージド DB とアンマネージド DB の変更を単一のトランザクションとしてコミットし、ロールバックしていました。

わーい!

デバッグ セッションの最後にエラーがスローされますが、これは意味がありません。デバッグにのみ影響し、コードのリリースには影響しないことを願っています。エラーは次のとおりです。

DisconnectedContext was detected
Message: Context 0x4452b0' is disconnected.  Releasing the interfaces from the current context (context 0x444fd0). This may cause corruption or data loss. To avoid this problem, please ensure that all contexts/apartments stay alive until the application is completely done with the RuntimeCallableWrappers that represent COM components that live inside them.

だから、これがいつか誰かに役立つことを願っています。

于 2011-01-20T20:51:57.160 に答える