Partager via


Gestionnaires de ressources de compensation (CRM)

Un gestionnaire de ressources de compensation (CRM*, Compensating Resource Manager*) est un service fourni par COM+ et qui vous permet d'inclure des objets non transactionnels dans des transactions Microsoft DTC (Distributed Transaction Coordinator). Bien que les CRM n'offrent pas les mêmes fonctionnalités qu'un gestionnaire de ressources complet, ils assurent néanmoins l'atomicité transactionnelle (comportement de type tout ou rien) et la durabilité via le journal de récupération.

L'exemple suivant est constitué de deux parties, un client et un serveur. Il illustre la création d'un CRM personnalisé au moyen d'une classe Worker, d'une classe Compensator et d'un objet Clerk, ainsi que l'exécution d'une validation et d'un abandon.

Serveur

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.
      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
      
      
[C#]
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.
      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.
            }
      
      }

}

Client

Imports System
Imports System.IO
Imports System.EnterpriseServices
Imports CrmServer
Imports System.Runtime.InteropServices

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!")
                  Return            
      End Sub
End Class
      
[C#]
using System;
using System.IO;
using System.EnterpriseServices;
using CrmServer;
using System.Runtime.InteropServices;

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;   
      }
} 

Makefile.bat

Vous pouvez compiler le programme serveur et client comme suit :

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

Voir aussi

Résumé des services COM+ disponibles | System.EnterpriseServices, espace de noms