如何:创建补偿资源管理器 (CRM)

代码示例

补偿资源管理器 (CRM) 是 COM+ 提供的一项服务,使您可以在 Microsoft 分布式事务处理协调器 (DTC) 事务中包括非事务性对象。尽管 CRM 不提供完整资源管理器的功能,但它们通过恢复日志提供事务性原子性(全部行为或没有任何行为)和持久性。

创建补偿资源管理器

  1. 导入 EnterpriseServices 和 CompensatingResourceManager 命名空间。

    Imports System.EnterpriseServices
    Imports System.EnterpriseServices.CompensatingResourceManager
    
    using System.EnterpriseServices;
    using System.EnterpriseServices.CompensatingResourceManager;
    
  2. 为程序集启用 CRM 支持。

    <assembly: ApplicationCrmEnabled>
    
    [assembly: ApplicationCrmEnabled]
    
  3. 定义一个从 ServicedComponent 类派生的 CRM Worker 类。例如,以下代码显示了从 ServicedComponent 直接派生的类 CRMWorker

    <Transaction> Public Class CRMWorker
          Inherits Servicedcomponent
    
    End Class
    
    [Transaction]
    public class CRMWorker:ServicedComponent
    {
    }
    
  4. 实现一个公共方法,该方法创建 Clerk 对象并提交或中止事务。该方法必须通过使用 Clerk 对象更新 CRM 日志。例如,以下代码显示了更新 CRM 日志并提交或中止事务的方法 CRMMethod

    Public Sub CRMMethod(filename As String, bCommit As Boolean)
         ' Create the clerk object.
         Dim myclerk As Clerk=New Clerk(GetType(CRMCompensator), _
                   "CRMCompensator", CompensatorOptions.AllPhases)
         myclerk.WriteLogRecord(filename)
         myclerk.ForceLog()
         If bCommit=true Then
             ContextUtil.SetComplete()
         Else
             ContextUtil.SetAbort()
         End If
    End Sub
    
    public void CRMMethod(string fileName, bool bCommit)
    {
          // Create clerk object.
          Clerk clerk = new Clerk(typeof(CRMCompensator), 
                                "CRMCompensator",
                                CompensatorOptions.AllPhases);
          clerk.WriteLogRecord(fileName);
          clerk.ForceLog();
          if (bCommit)
               ContextUtil.SetComplete();
          else
               ContextUtil.SetAbort();
          }
    
  5. 定义一个从 Compensation 类派生的类。

    JustInTimeActivation()
    Public Class CRMCompensator
            Inherits Compensator
    End Class
    
    [JustInTimeActivation]
    public class CRMCompensator:Compensator
    {
    }
    
Note注意:

必须对 Compensator 应用 JustInTimeActivation 属性;否则将两次调用中止。

  1. 重写 Compensator 类的 BeginPreparePrepareRecordEndPrepareBeginCommitCommitRecordEndCommitBeginAbortAbortRecordEndAbort 成员。

  2. 创建一个客户端应用程序以测试 CRM Worker 和 Compensator 组件。

    1. 导入所需的名称(例如 System.EnterpriseServices)以及实现 CRM Worker 和 Compensator 类的命名空间。

      Imports System
      Imports System.IO
      Imports System.EnterpriseServices
      Imports CrmServer
      Imports System.Runtime.InteropServices
      
      using System;
      using System.IO;
      using System.EnterpriseServices;
      using CrmServer;
      using System.Runtime.InteropServices;
      
    2. 定义一个类并实现 Main 方法,以创建 CRM Worker 类的实例,并调用创建 CRM Clerk 对象的方法。例如,以下代码创建了一个 CRMWorker 类型的对象,并调用方法 CRMMethod 以创建 CRM Clerk 对象。

      Public Class CRM
          Public Shared Sub Main()                        
             dim logfilename As String = "crm.log"
             Console.WriteLine("Creating a managed CRM worker"+ _ 
                                                   "object...")
             dim crmworker As CRMWorker = new CRMWorker()
             Console.WriteLine("Demonstrating a worker commit...")
             crmworker.CRMMethod(logfilename, True)
             Console.WriteLine("Demonstrating a worker abort...")
             crmworker.CRMMethod(logfilename, False)
             Console.WriteLine("DONE!")
          End Sub
      End Class
      
      class CRM
      {
          public static int Main()
          { 
             string logfilename = "crm.log";
             Console.WriteLine("Creating a managed CRM worker 
                                                object...");
             CRMWorker crmworker = new CRMWorker();
             Console.WriteLine("Demonstrating a worker commit...");
             crmworker.CRMMethod(logfilename, true);
             Console.WriteLine("Demonstrating a worker abort...");
             crmworker.CRMMethod(logfilename, false);
             Console.WriteLine("DONE!");
             return 0;   
          }
      }
      
  3. 生成强密钥并编译以下示例。

    sn –k crm.key
    vbc /t:library /r:System.EnterpriseServices.dll crm.vb
    vbc /r:crm.dll /r:System.EnterpriseServices.dll crmclient.vb
    
    sn –k crm.key
    csc /t:library /r:System.EnterpriseServices.dll crm.cs
    csc /r:crm.dll crmclient.cs
    

示例

Imports System
Imports System.IO
Imports System.Reflection
Imports System.EnterpriseServices
Imports System.EnterpriseServices.CompensatingResourceManager

<assembly: ApplicationActivation(ActivationOption.Server)>
<assembly: ApplicationCrmEnabled>
<assembly: AssemblyKeyFile("crm.key")>

Namespace CrmServer
' Create a Worker class.
<Transaction> Public Class CRMWorker
    Inherits Servicedcomponent
          Public Sub CRMMethod(filename As String, bCommit As Boolean)
              ' Create the clerk object.
              Dim myclerk As Clerk=New Clerk(GetType(CRMCompensator), _ 
                        "CRMCompensator", CompensatorOptions.AllPhases)
              myclerk.WriteLogRecord(filename)
              myclerk.ForceLog()
              If bCommit=true Then
                    ContextUtil.SetComplete()
              Else
                    ContextUtil.SetAbort()
              End If
        End Sub
    End Class

    ' Create a class derived from the Compensator class.
    JustInTimeActivation()
    Public Class CRMCompensator
      Inherits Compensator
            Dim bBeginPrepareCalled As Boolean = False
            Dim bPrepareRecordCalled As Boolean = False
            Dim bBeginCommitCalled As Boolean = False
            Dim bCommitRecordCalled As Boolean = False
            Dim bBeginAbortCalled As Boolean = False
            Dim bAbortRecordCalled As Boolean = False
            Dim _filename as String

            Public Overrides Sub BeginPrepare()
                  bBeginPrepareCalled = True
            End Sub

            Public Overrides Function PrepareRecord(rec As LogRecord) _
                                                           As Boolean
                  dim o as Object = rec.Record
                  _fileName = o.ToString()
                  bPrepareRecordCalled = True
                  Return False
            End Function

            Public Overrides Function EndPrepare() As Boolean
                  if not bBeginPrepareCalled then Return False   

                  if not bPrepareRecordCalled then Return False
                  if _fileName="" then Return False
                  ' This is a Prepare Phase success.
                  Return True
            End Function

            Public Overrides Sub BeginCommit(fRecovery As Boolean)
                  bBeginCommitCalled = True
            End Sub

            Public Overrides Function CommitRecord(rec As LogRecord) _
                                                          As Boolean
                  bCommitRecordCalled = True
                  Return True
            End Function

            Public Overrides Sub EndCommit()
                  if not bBeginCommitCalled then Return 
                  if not bCommitRecordCalled then Return 
                  if _fileName="" then Return 
                  ' This is a Commit Phase success.
            End Sub

            Public Overrides Sub BeginAbort(fRecovery As Boolean)
                  bBeginAbortCalled = True
            End Sub
            
            Public Overrides Function AbortRecord(rec As LogRecord) _
                                                          As Boolean
                  bAbortRecordCalled = True
                  dim o as Object = rec.Record
                  _fileName = o.ToString()
                  Return True
            End Function

            Public Overrides Sub EndAbort()
                  if not bBeginAbortCalled then Return 
                  if not bAbortRecordCalled then Return 
                  if _fileName="" then Return
                  ' This is an Abort Phase success.
            End Sub
      End Class
End Namespace
      
      
using System;
using System.IO;
using System.Reflection;
using System.EnterpriseServices;
using System.EnterpriseServices.CompensatingResourceManager;

[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationCrmEnabled]
[assembly: AssemblyKeyFile("crm.key")]

namespace CrmServer 
{
      [Transaction]
      // Create a Worker class.
      public class CRMWorker:ServicedComponent
      {
            public void CRMMethod(string fileName, bool bCommit)
            {
                  // Create clerk object.
                  Clerk clerk = new Clerk(typeof(CRMCompensator),
                       "CRMCompensator", CompensatorOptions.AllPhases);
                  clerk.WriteLogRecord(fileName);
                  clerk.ForceLog();
                  if (bCommit)
                        ContextUtil.SetComplete();
                  else
                        ContextUtil.SetAbort();
            }
      
      }
      // Create class derived from Compensator class.
      [JustInTimeActivation]
      public class CRMCompensator:Compensator
      {
            bool bBeginPrepareCalled = false;
            bool bPrepareRecordCalled = false;
            bool bBeginCommitCalled = false;
            bool bCommitRecordCalled = false;
            bool bBeginAbortCalled = false;
            bool bAbortRecordCalled = false;
      
            String _fileName;
      
            public override void BeginPrepare()
            {
                  bBeginPrepareCalled = true;
            }
      
            public override bool PrepareRecord(LogRecord rec)
            {
                  Object o = rec.Record;
                  _fileName = o.ToString();
                  bPrepareRecordCalled = true;
                  return false;
            }
      
            public override bool EndPrepare()
            {
                  if (!bBeginPrepareCalled)
                  {return false;}   
                  if (!bPrepareRecordCalled)
                  {return false;}   
                  if (_fileName==null)
                  {return false;}
                  // This is a Prepare Phase success.
                  return true;
            }
      
            public override void BeginCommit(bool fRecovery)
            {
                  bBeginCommitCalled = true;
            }
      
            public override bool CommitRecord(LogRecord rec)
            {
                  bCommitRecordCalled = true;
                  return true;
            }
      
            public override void EndCommit()
            {
                  if (!bBeginCommitCalled)
                  {return;}   
                  if (!bCommitRecordCalled)
                  {return;}
                  if (_fileName==null)
                  {return;}
                  // This is a Commit Phase success.
            }
      
            public override void BeginAbort(bool fRecovery)
            {
                  bBeginAbortCalled = true;
            }
      
            public override bool AbortRecord(LogRecord rec)
            {
                  bAbortRecordCalled = true;
                  Object o = rec.Record;
                  _fileName = o.ToString();
                  return true;
            }
      
            public override void EndAbort()
            {
                  if (!bBeginAbortCalled)
                  {return;}   
                  if (!bAbortRecordCalled)
                  {return;}               
                  if (_fileName==null)
                  {return;}
                  // This is an Abort Phase success.
            }
      
      }

}

请参见

参考

System.EnterpriseServices Namespace

概念

可用的 COM+ 服务摘要

Footer image

版权所有 (C) 2007 Microsoft Corporation。保留所有权利。