This is a discussion on Transaction Scope in DotNet using C#. within the C# Programming forums, part of the Software Development category; System.Transactions API gives flexibility to shift between local database server transactions and distributed database server transactions. The Systems.Transactions ...
| |||||||
| Register | FAQ | Members List | Calendar | Mark Forums Read |
| |||
| System.Transactions API gives flexibility to shift between local database server transactions and distributed database server transactions. The Systems.Transactions API, when used with SQL Server 2005, uses the Promotable Transactions feature through the Lightweight Transactions Manager. It does not create a distributed transaction when not required, resulting in improved performance. For more see the following, J.D. Meier's Blog : Performance Guideline: Use Promotable Transactions when Working with SQL Server 2005 this might be helpful.
__________________ S.VinothkumaR Behind me is infinite power, Before me is Endless Possibility, Around me is Boundless Opportunity, Why should I fear! |
| Sponsored Links |
| |||
| Hi, You need to handle event for those outcome. To receive the outcome of a specific transaction you can use the TransactionCompletedEvent event which is on the Transaction object. here is the sample code for using TransactionCompletedEvent event, Code: using System;
using System.Transactions;
try
{
//Create the transaction scope
using (TransactionScope scope = new TransactionScope())
{
//Register for the transaction completed event for the current transaction
Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(Current_TransactionCompleted);
//Call complete on the TransactionScope or not based on input
ConsoleKeyInfo c;
while (true)
{
Console.Write("Complete the transaction scope? [Y|N] ");
c = Console.ReadKey();
Console.WriteLine();
if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))
{
scope.Complete();
break;
}
else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))
{
break;
}
}
}
}
catch (System.Transactions.TransactionException ex)
{
Console.WriteLine(ex);
}
catch
{
Console.WriteLine("Cannot complete transaction");
throw;
}
static void Current_TransactionCompleted(object sender, TransactionEventArgs e)
{
Console.WriteLine("A transaction has completed:");
Console.WriteLine("ID: {0}", e.Transaction.TransactionInformation.LocalIdentifier);
Console.WriteLine("Distributed ID: {0}", e.Transaction.TransactionInformation.DistributedIdentifier);
Console.WriteLine("Status: {0}", e.Transaction.TransactionInformation.Status);
Console.WriteLine("IsolationLevel: {0}", e.Transaction.IsolationLevel);
}
__________________ cheers Aman |
| |||
| Enlisting allows you to receive transaction notifications and take appropriate action. If you want to build a resource manager or simply vote on the outcome of a transaction you'll need to enlist on that transaction. |
| |||
| Enlisting in Web Service There are two steps to enlist on a transaction: - First, you will need to enlist on a transaction. If your enlistment will not log state information and cannot recover from a failure, call the EnlistVolatile method on the Transaction object. If your enlistment will log state information and can recover from a failure, call the EnlistDurable method on the Transaction object. - Second, your enlistment will need to implement the IEnlistmentNotification interface. The methods implemented will be called for each of the possible transaction notifications: Prepare, Commit, Rollback, and InDoubt. |
| |||
| Hi Ramesh, Do u have any samples for enlisting the webservices
__________________ Krishnakumar.S Beware of Everything -that is un true; stick to the Truth shall succeed slowly but steadily |
| |||
| Krishna, Here is the sample code for enlisting in web service. Code: using System;
using System.Transactions;
namespace myTransaction
{
// A simple usage of transactions with the using statement
class VolatileEnlist
{
static void Main(string[] args)
{
try
{
using (TransactionScope scope = new TransactionScope())
{
//Create an enlistment object
myEnlistmentClass myElistment = new myEnlistmentClass();
//Enlist on the current transaction with the enlistment object
Transaction.Current.EnlistVolatile(myElistment, EnlistmentOptions.None);
//Perform transactional work here.
//Call complete on the TransactionScope or not based on inputt
ConsoleKeyInfo c;
while(true)
{
Console.Write("Complete the transaction scope? [Y|N] ");
c = Console.ReadKey();
Console.WriteLine();
if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))
{
scope.Complete();
break;
}
else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))
{
break;
}
}
}
}
catch (System.Transactions.TransactionException ex)
{
Console.WriteLine(ex);
}
catch
{
Console.WriteLine("Cannot complete transaction");
throw;
}
}
class myEnlistmentClass : IEnlistmentNotification
{
public void Prepare(PreparingEnlistment preparingEnlistment)
{
Console.WriteLine("Prepare notification received");
//Do work to be included in the transaction
//If work finished correctly, reply prepared
preparingEnlistment.Prepared();
}
public void Commit(Enlistment enlistment)
{
Console.WriteLine("Commit notification received");
//Do any work needed when receiving commit notification
//Declare done on the enlistment
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
Console.WriteLine("Rollback notification received");
//Do any work needed when receiving a rollback notification
//Declare done on the enlistment
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
Console.WriteLine("In doubt notification received");
//Do any work needed in case of in doubt notification
//Declare done on the enlistment
enlistment.Done();
}
}
}
} ![]() |
| |||
| The instantiation of the CommittableTransaction object and the EnlistTransaction method provides an explicit way to create and enlist in a distributed transaction. Note that the application must call Commit or Rollback on the CommittableTransaction object. Here is the sample code for that, Code: using System;
using Oracle.DataAccess.Client;
using System.Data;
using System.Data.Common;
using System.Transactions;
class psfEnlistTransaction
{
static void Main()
{
int retVal = 0;
string providerName = "Oracle.DataAccess.Client";
string constr =
@"User Id=scott;Password=tiger;Data Source=oracle;enlist=dynamic";
// Get the provider factory.
DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);
try
{
// Create a committable transaction object.
CommittableTransaction cmtTx = new CommittableTransaction();
// Open a connection to the DB.
DbConnection conn1 = factory.CreateConnection();
conn1.ConnectionString = constr;
conn1.Open();
// enlist the connection with the commitable transaction.
conn1.EnlistTransaction(cmtTx);
// Create a command to execute the sql statement.
DbCommand cmd1 = factory.CreateCommand();
cmd1.Connection = conn1;
cmd1.CommandText = @"insert into emp (empno, ename, job) values
(1234, 'emp1', 'dev1')";
// Execute the SQL statement to insert one row in DB.
retVal = cmd1.ExecuteNonQuery();
Console.WriteLine("Rows to be affected by cmd1: {0}", retVal);
// commit/rollback the transaction.
cmtTx.Commit(); // commits the txn.
//cmtTx.Rollback(); // rolls back the txn.
// close and dispose the connection
conn1.Close();
conn1.Dispose();
cmd1.Dispose();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
} ![]()
__________________ S.VinothkumaR Behind me is infinite power, Before me is Endless Possibility, Around me is Boundless Opportunity, Why should I fear! |
| |||
| EnlistTransaction This method enlists the connection to the specified transaction. Supported Only in ADO.NET 2.0-Compliant ODP.NET Declaration // C# public override void EnlistTransaction(Transaction transaction) Parameters transaction A System.Transactions.Transaction object. Exceptions InvalidOperationException - The connection is part of a local transaction or the connection is closed. Remarks Invocation of this method immediately enlists the connection to a distributed transaction that is specified by the provided transaction parameter. If OracleConnection is still associated with a distributed transaction that has not completed from a previous EnlistTransaction method invocation, calling this method will cause an exception to be thrown. In general, for distributed transaction enlistments to succeed, the "enlist" connection string attribute must be set to either "true" or "dynamic" before invoking the Open method. Setting the "enlist" connection string attribute to "true" will implicitly enlist the connection when the Open method is called, if the connection is within a transaction context. Setting it to "dynamic" allows the connection to dynamically enlist in distributed transactions when an EnlistTransaction or EnlistDistributedTransaction method is called. The "enlist" attribute should be set to "false" only if the connection will never enlist in a distributed transaction.
__________________ S.VinothkumaR Behind me is infinite power, Before me is Endless Possibility, Around me is Boundless Opportunity, Why should I fear! |
| |||
| The Microsoft .NET 2.0 platform introduces a new namespace called System.Transactions that brings in a lightweight, simplified transaction model. This article discusses the shortcomings of current transaction models and introduces System.Transactions for .NET Framework 2.0 beta 2. Currently there are two transaction models available in the .NET world, both of which are suited for certain situations. The first is part of the rich ADO.NET data providers. The second is the enterprise services transaction. Before we examine System.Transactions, let’s have a look at the current models. The ADO.NET transaction model The transaction handling model available as part of the .NET data providers is very simple. A general update statement might consist of the following steps: C# Code SqlConnection con = new SqlConnection("Connection String"); SqlTransaction tr = con.BeginTransaction(); SqlCommand cmd = new SqlCommand("Update Account set Balance=500 where AccountId=52", con, tr); try { cmd.ExecuteNonQuery(); tr.Commit(); } catch (Exception exc) { tr.Rollback(); } finally { con.Close(); } We created a transaction with the connection object and associated the transaction objects with the command objects. After executing the commands, we specified whether the transaction should commit or rollback. If there is an exception, we select a rollback, and if not, we are committing the transaction. Enterprise services transactions Enterprise services transactions address most of the shortcomings of the ADO.NET transactions by providing a two-phase commit protocol and a distributed transaction manager. These two features enable you to have transactions independent of the database, and provide transactions in a declarative manner. The following code shows a simple AccountManager class that accepts two accounts and performs a transfer between the two. The transfer is completed by depositing cash into one account and withdrawing cash from the other, with each method separately updating the balances of the accounts in the database. If any of these methods generates an error, the entire transfer method will be rolled back. C# Code [Transaction(TransactionOption.Required)] class AccountManager : ServicedComponent { [AutoComplete()] void TransferCash(Account from, Account to, double amt) { from.Withdraw(amt); to.Deposit(amt); } } If you look at the above code block, we are not explicitly creating any transaction objects. We are using declarative transactions to mark areas where transactions will be used. The Autocomplete attribute specifies that the transaction should be commited if no errors are generated. The Transaction attribute paired with TransactionOption.Required specifies that the objects we create from AccountManager will be transactional and will always run under a transaction. |
| |||
| Hi, I'm developing an application that performs the operation of file copy,IIS web site creation, etc... Since if one of this operation fails, all others have to be rollbacked, I started to look at the transactionscope class and IEnlistmentNotification interface. How can I maintain the transaction with these process?
__________________ J.Saravanan |
| |||
| The inbuilt .Net framework classes won't do it for ya...! you have to write your own implementation. I suggest u to visit here for more.... ![]() System.Transactions - Beta2 Changes - and other good stuff - Sahil Malik: New Blog - http://blah.winsmarts.com
__________________ cheers Aman |
| |||
| There are no Resources Managers for the such things like file copy end etc. The solution for this is the STM - software transacted memory, where we can operate the set of memory block, like files or arrays, within transations unfortunatelly there is no standart implementations yet I suggest u to read this Software Transactional Memory - Making multithreading easier - Ralf's Sudelbücher to understand the deep of the problem ![]()
__________________ S.VinothkumaR Behind me is infinite power, Before me is Endless Possibility, Around me is Boundless Opportunity, Why should I fear! |
| |||
| Yes its working with fine.... Thanks for the link, it seems to be a usefull reading. And what is DepedentTransaction in Transaction? can u explain it ?
__________________ J.Saravanan |
| |||
| Hi, The DependentTransaction is a clone of a Transaction object created using the DependentClone method. Its sole purpose is to allow the application to come to rest and guarantee that the transaction cannot commit while work is still being performed on the transaction... When the work done within the cloned transaction is finally complete and ready to be committed, it can inform the creator of the transaction using the Complete method. Thus you can preserve the consistency and correctness of data. The DependentCloneOption enumeration is used to determine the behavior on commit. This behavior control allows an application to come to rest, as well as provides concurrency support.
__________________ Krishnakumar.S Beware of Everything -that is un true; stick to the Truth shall succeed slowly but steadily |
| |||
| If you want to start asynchronous threads and have them participate in a transaction, use the DepedentTransaction object. DependentTransction objects can be obtained by called the DependentClone method on a Transaction object. A thread can use a DependentTransaction in a TransactionScope or use the transaction explicitly to perform transacted work. When the thread is done with the transaction, it simply calls the complete method on the DependentTransaction. In case of failure, the rollback method can be called. The code starting the thread has two options when using a DependentClone: BlockCommitUntilComplete: The transaction will not commit until the Complete method is called on the DependentTransaction or the transaction times out, even if the commit method is called on the transaction. Choose this option if you want to wait for the thread to finish before committing the transaction but don't want to manually track when the thread is complete. RollbackIfNotComplete: The transaction will rollback if the Commit method is called on the transaction before the Complete method is called on the DepedentTransaction. Choose this option if you expect the thread to be done when you call commit. The transaction will be aborted if the thread is not done with it's transacted work before Commit is called. Code: using System;
using System.Transactions;
using System.Threading;
try
{
using (TransactionScope scope = new TransactionScope())
{
// Perform transactional work here.
//Queue work item
ThreadPool.QueueUserWorkItem(new WaitCallback(WorkerThread), Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete));
//Print the transaction information
Console.WriteLine("Transaction information:");
Console.WriteLine("ID: {0}", Transaction.Current.TransactionInformation.LocalIdentifier);
Console.WriteLine("status: {0}", Transaction.Current.TransactionInformation.Status);
Console.WriteLine("isolationlevel: {0}", Transaction.Current.IsolationLevel);
//Call complete on the TransactionScope or not based on input
ConsoleKeyInfo c;
while (true)
{
Console.Write("Complete the transaction scope? [Y|N] ");
c = Console.ReadKey();
Console.WriteLine();
if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))
{
//Call complete on the scope
scope.Complete();
break;
}
else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))
{
break;
}
}
}
}
catch (System.Transactions.TransactionException ex)
{
Console.WriteLine(ex);
}
catch
{
Console.WriteLine("Cannot complete transaction");
throw;
}
private static void WorkerThread(object transaction)
{
//Create the DependentTransaction from the object passed to the WorkerThread
DependentTransaction dTx = (DependentTransaction)transaction;
//Sleep for 1 second to force the worker thread to delay
Thread.Sleep(1000);
//Pass the DependentTransaction to the scope so work done in the scope will be part of the transaction passed to the worker thread
using (TransactionScope ts = new TransactionScope(dTx))
{
//Perform transactional work here.
//Call complete on the transaction scope
ts.Complete();
}
//Call complete on the dependent transaction
dTx.Complete();
}
__________________ S.VinothkumaR Behind me is infinite power, Before me is Endless Possibility, Around me is Boundless Opportunity, Why should I fear! |
| |||
| Hi all, I need to use existing transaction. I mean inherit an external transaction. Is there any possibilities? |
| |||
| Hi, yes... You can inherit an external transaction using BYOT. System.Transactions provides functionality that allows interoperability with EnterpriseServices transactions. What is BYOT? BYOT allows a component to be created with, or to inherit, an external transaction. That is, a component that does not already have an associated transaction can acquire a transaction. This is done by setting an arbitrary pre-existing transaction as the transaction property of a new component's context. In this case this is the transactions started with System.Transactions. Convert the transaction: Because it is necessary to use the BYOT functionality provided by the System.EnterpriseServices namespace, you must first convert the current transaction to be of the System.EnterpriseServices.Itransaction type. This can be done by the static TransactionInterop.GetDtcTransaction method as follows. Code: System.EnterpriseServices.ITransaction estx = null; estx = (System.EnterpriseServices.ITransaction) TransactionInterop.GetDtcTransaction(Transaction.C urrent); Associate a component with the transaction: You can use the CreateWithTransaction method of the System.EnterpriseServices.BYOT class to do the actual work. In this case, an object, SvcComp, inheriting from System.EnterpriseServices.ServicedComponent will receive a reference to the requested transaction. Code: SvcComp sc = (SvcComp) BYOT.CreateWithTransaction(estx, typeof(SvcComp)); Dim sc As SvcComp = New SvcComp System.EnterpriseServices.BYOT.CreateWithTransacti on(estx, sc.GetType) Obtain context information for the component: Next, the System.EnterpriseServices.ContextUtil class is used to obtain information about the context of the object that inherits this transaction. Specifically, the sample must determine the GUID of the current transaction, and whether the current context is transactional. The following properties are used to obtain this information. Console.WriteLine("IsInTransaction {0}", ContextUtil.IsInTransaction); Console.WriteLine("TransactionId {0}", ContextUtil.TransactionId);
__________________ Krishnakumar.S Beware of Everything -that is un true; stick to the Truth shall succeed slowly but steadily |