[Note: This topic is pre-release documentation and is subject to change in future releases. Blank topics are included as placeholders.] Code Example
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
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.
}
}
}
Summary of Available COM+ Services
System.EnterpriseServices Namespace