Skip to content

Instantly share code, notes, and snippets.

@vivmishra
Created October 23, 2015 18:09
Show Gist options
  • Save vivmishra/1e7ddf47979f62fdd4a1 to your computer and use it in GitHub Desktop.
Save vivmishra/1e7ddf47979f62fdd4a1 to your computer and use it in GitHub Desktop.
Sample for System.Transactions updates in .NET 4.6.1
using System;
using System.Transactions;
namespace YourNamespaceGoesHere
{
public class NonMSDTCPromoterEnlistment : IPromotableSinglePhaseNotification
{
Guid promoterType;
Guid distributedTxId;
Transaction enlistedTransaction;
bool promoted;
public NonMSDTCPromoterEnlistment(Guid promoterType)
{
this.promoterType = promoterType;
this.distributedTxId = Guid.Empty;
this.enlistedTransaction = null;
this.promoted = false;
}
// This is a method that a program would call to create a Promotable Single Phase Enlistment on the specified
// transaction. If no parameter is passed or null is passed, Transaction.Current is used.
public bool Enlist(Transaction txToEnlist = null)
{
if (txToEnlist == null)
{
txToEnlist = Transaction.Current;
}
// Attempt to create the Promotable Single Phase Enlistment with the promoter type specified to the constructor.
if (txToEnlist.EnlistPromotableSinglePhase(this, this.promoterType))
{
// We have successfully created the promotable single phase enlistment with System.Transactions.
// This is where you would do the work to do the single phase enlistment with the resource manager.
// How that is done is beyond the scope of this sample.
// RM.SinglePhaseEnlist(...);
}
else
{
// There is either already a promotable single phase enlistment on the transaction, or the transaction
// is already promoted. You can return false and let the caller decide what to do.
return false;
// Or you can check to see if the promoter type for the transaction matches the promoter type provided in
// the constructor and if it does, tell the resource manager to enlist directly with the non-MSDTC transaction manager identified
// by that promoter type. The work to do that enlistment is beyond the scope of this sample.
// if (this.promoterType == txToEnlist.PromoterType)
// {
// // Get the promoted token from the transaction. This will cause
// // promotion if it is not already promoted.
// byte[] promotedToken = txToEnlist.PromotedToken;
// RM.EnlistDistributed(..., promotedToken, ...);
// }
}
// If we get here, we have successfully enlisted, so remember the transaction for later use.
this.enlistedTransaction = txToEnlist;
return true;
}
// This is the implementation of IPromotableSinglePhaseNotification.Initialize, which is called by
// System.Transactions when Transaction.EnlistPromotableSinglePhase is called.
public void Initialize()
{
// Perform any initialization work for the enlistment here.
return;
}
// This is the implementation of the IPromotableSinglePhaseNotification.Rollback method.
public void Rollback(SinglePhaseEnlistment singlePhaseEnlistment)
{
if (this.promoted)
{
// This is where you would need to tell the non-MSDTC transaction manager to rollback the transaction.
// How that is done is beyond the scope of this sample.
// TxMgr.Rollback(..., this.distributedTxId, ...);
}
else
{
// This is where you would tell the resource manager to rollback.
// How that is done is beyond the scope of this sample.
// RM.Rollback(...);
}
singlePhaseEnlistment.Done();
}
// This is the implementation of the IPromotableSinglePhaseNotification.SinglePhaseCommit method.
public void SinglePhaseCommit(SinglePhaseEnlistment singlePhaseEnlistment)
{
TransactionStatus commitResponse;
if (this.promoted)
{
// This is where you would tell the non-MSDTC transaction manager to
// commit the transaction. How that is done is beyond the scope of this sample.
// commitResponse = TxMgr.Commit(..., this.distributedTxId, ...);
}
else
{
// This is where you would tell the resource manager to
// perform a SinglePhaseCommit because they are the only resource manager involved in the transaction.
// How that is done is beyond the scope of this sample.
// commitResponse == RM.SinglePhaseCommit(...);
}
switch (commitResponse)
{
case TransactionStatus.Committed:
{
singlePhaseEnlistment.Committed();
break;
}
case TransactionStatus.Aborted:
{
singlePhaseEnlistment.Aborted(new ApplicationException("Aborted by NonMSDTCPromoterEnlistment.SinglePhaseCommit"));
break;
}
case TransactionStatus.InDoubt:
{
singlePhaseEnlistment.InDoubt(new ApplicationException("InDoubt by NonMSDTCPromoterEnlistment.SinglePhaseCommit"));
break;
}
default:
{
throw new ApplicationException("InDoubt by NonMSDTCPromoterEnlistment.SinglePhaseCommit because of invalid TransactionStatus outcome value.");
}
}
}
// This is the implementation of the IPromotableSinglePhaseNotification.Promote method, which comes from the ITransactionPromoter derivation.
public byte[] Promote()
{
byte[] promotedToken;
// This is where you would tell the non-MSDTC transaction manager to create a distributed transaction.
// This call needs to give you back the id of the distributed transaction (assuming it is a Guid) and the byte[]
// promoted token that can be used by resource managers to directly enlist with the distributed transaction manager.
// How that is done is beyond the scope of this sample.
// this.distributedTxId = TxMgr.CreateTransaction(..., out promotedToken, ...);
this.promoted = true;
// We now need to tell the resource manager to modify its enlistment to be with the distributed transaction manager
// instead of just being a SinglePhase enlistment. How that is done is beyond the scope of this sample.
// RM.PromoteEnlistment(..., promotedToken, ...);
// We need to set the distributed transaction id on the Transaction. This MUST be done inside this Promote method.
// Note that we are passing "this" as the promotableSinglePhaseNotification parameter because that is what was
// passed to Transaction.EnlistPromotableSinglePhase in the Enlist method above.
this.enlistedTransaction.SetDistributedTransactionId(this, this.distributedTxId);
return promotedToken;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment