3

在 C# 中,我有一个更新数据库的 OracleConnection,以及对 C# 调用以更新数据库的旧版 VB6 DLL 的引用(在 DLL 中,它使用 ADODB.Connection 对象)。

我需要将它们都包装在一个大事务中,以便托管和非托管更新一起回滚或提交。

我尝试切换 C# 类,使其继承自 System.EnterpriseServices.ServicedComponent 并用 [Transaction(TransactionOption.Required)] 装饰,然后在启动调用序列的方法上使用 [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)

我已经验证我的类是公共的、具体的,并且有一个无参数的构造函数。不过,它不会实例化。

我是否需要对我的程序集进行强类型化并将其放入 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 代码,我需要将遗留 VB6 COM 对象添加到我的托管代码所在的 COM+ 应用程序中。因为这个 VB6 代码在调用 Oracle 时,我必须修改 VB6 代码用来设置 DistribTX=1 和 PROMOTABLE TRANSACTION=PROMOTABLE 的连接字符串。之后,代码将托管和非托管数据库更改作为单个事务提交和回滚。

耶!

我确实在调试会话结束时抛出了一个错误,这对我来说没有意义。希望它只影响调试而不是发布代码。错误是:

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 回答