How to: Create a Compensating Resource Manager (CRM)
A compensating resource manager (CRM) is a service provided by COM+ that enables you to include nontransactional objects in Microsoft Distributed Transaction Coordinator (DTC) transactions. Although CRMs do not provide the capabilities of a full resource manager, they do provide transactional atomicity (all-or-nothing behavior) and durability through the recovery log.
To create a Compensating Resource Manager
Import the EnterpriseServices and CompensatingResourceManager namespaces.
Imports System.EnterpriseServices Imports System.EnterpriseServices.CompensatingResourceManager
using System.EnterpriseServices; using System.EnterpriseServices.CompensatingResourceManager;
Enable CRM support for the assembly.
<assembly: ApplicationCrmEnabled>
[assembly: ApplicationCrmEnabled]Define a CRM worker class that derives from the ServicedComponent class. For example, the following code shows a class CRMWorker that derives directly from ServicedComponent.
<Transaction> Public Class CRMWorker Inherits Servicedcomponent End Class
[Transaction] public class CRMWorker:ServicedComponent { }
Implement a public method that creates a Clerk object and commits or aborts the transaction. The method must update the CRM log by using the Clerk object. For example, the following code shows a method CRMMethod that updates the CRM log and commits or aborts the transaction.
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(); }
Define a class that derives from the Compensation class.
JustInTimeActivation() Public Class CRMCompensator Inherits Compensator End Class
[JustInTimeActivation] public class CRMCompensator:Compensator { }
Conclusion
Note: |
|---|
You must apply the JustInTimeActivation attribute to the compensator; otherwise abort is called twice. |
Override the BeginPrepare, PrepareRecord, EndPrepare, BeginCommit, CommitRecord, EndCommit, BeginAbort, AbortRecord, and EndAbort members of the Compensator class.
Create a client application to test the CRM Worker and Compensator components.
Import the required names, such as the System.EnterpriseServices and the namespace that implements the CRM Worker and Compensator classes.
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;
Define a class and implement the Main method to create an instance of the CRM worker class, and call that method that creates the CRM Clerk object. For example, the following code creates an object of the CRMWorker type and calls the method CRMMethod to create the CRM Clerk object.
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; } }
Generate a strong key and compile the following example.
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
Note: