On this page
This site
Calendar
<August 2008>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456
Archives
Sitemap
Blogroll OPML
Disclaimer

Powered by: newtelligence dasBlog 1.9.6264.0

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Send mail to the author(s) E-mail

Theme design by Christoph Herold

TransactionHelper#

For the time being, I have built myself a helper class, that tries to fix the "timeout-bug" when using TransactionScope. And since I'm such a nice guy, I decided to let everyone have it ;-)

So here goes, completely commented including a usage example:

using System;
using System.Threading;
using System.Transactions;

namespace Succell.Framework.Utils
{
    /// <summary>
    /// This class is used to abort transactions when the timeout occurs.
    /// </summary>
    /// <remarks>
    /// <para>This class is required, because TransactionScopes do not abort processing, when they expire. Instead
    /// all actions done after the timeout occurs are not included in the transaction, but instead carried out
    /// normally. This can lead to inconsistencies in your data, when processing large amounts.</para>
    ///
    /// <para>This class can be used nestedly, i.e. methods called in the supplied working delegate can safely
    /// create instances of this class.</para>
    /// </remarks>
    /// <example><code>
    /// try
    /// {
    ///     using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 0, 2)))
    ///     {
    ///         new TransactionHelper(ts, delegate() {
    ///                 // do transactive work here
    ///             });
    ///         ts.Complete();
    ///     }
    /// }
    /// catch (TransactionAbortedException tae)
    /// {
    ///     // handle aborted transaction
    /// }
    /// </code>
    /// </example>
    public sealed class TransactionHelper
    {
        /// <summary>
        /// A tagging object to determine, whether the thread is aborted due to a transaction timeout
        /// </summary>
        private object _abortObject;

        /// <summary>
        /// The current thread executing the transactive work
        /// </summary>
        private Thread _currentThread;

        /// <summary>
        /// Creates a new TransactionHelper that executes transactive statements and aborts the process
        /// if a timeout occurs.
        /// </summary>
        /// <param name="toExecute">The delegate to call for processing</param>
        public TransactionHelper(ThreadStart toExecute)
        {
            if (null == toExecute)
                throw new ArgumentNullException("toExecute");

            // get current transaction
            Transaction tx = Transaction.Current;

            if (null == tx)
                throw new InvalidOperationException("You must create an ambient transaction before using the TransactionHelper");

            // Don't execute, if the transaction is already aborted
            if (tx.TransactionInformation.Status != TransactionStatus.Aborted)
            {
                // keep handle to current thread for aborting
                _currentThread = Thread.CurrentThread;

                // register completion handler
                tx.TransactionCompleted += new TransactionCompletedEventHandler(Current_TransactionCompleted);

                // execute transactive code
                try
                {
                    toExecute();
                }
                catch (ThreadAbortException tae)
                {
                    // was the thread aborted by our TransactionCompleted handler?
                    if (null != _abortObject && tae.ExceptionState == _abortObject)
                    {
                        Thread.ResetAbort();
                    }
                }
                // unregister completion handler (required when using multiple TxHelpers in one transaction,
                // otherwise multiple ThreadAbortExceptions are thrown on timeout)
                tx.TransactionCompleted -= new TransactionCompletedEventHandler(Current_TransactionCompleted);
            }
        }

        /// <summary>
        /// Transaction completion event handler, that checks, whether a timeout occured
        /// and, if so, causes the registered executing thread to abort
        /// </summary>
        /// <param name="sender">The originating transaction</param>
        /// <param name="e">The event args for this event</param>
        void Current_TransactionCompleted(object sender, TransactionEventArgs e)
        {
            // Is the transaction aborted (possibly due to timeout)?
            if (e.Transaction.TransactionInformation.Status == TransactionStatus.Aborted)
            {
                // Is the executing thread registered?
                if (null != _currentThread)
                {
                    // generate a new abortion tagging object
                    _abortObject = new object();

                    // abort the executing thread
                    _currentThread.Abort(_abortObject);
                }
            }
        }
    }
}

I hope, this helps some of you. Of course, I'll be updating my blog, as soon as some notice of how TransactionScope is supposed to be used reaches me. I know, that ThreadAbortExceptions aren't something to use lightly, but currently I see no other way.

Monday, November 27, 2006 11:28:20 AM (W. Europe Standard Time, UTC+01:00)
Comments [0]  | 

 

Installing multiple versions of IE#
One of the biggest pains for web developers is probably the fact, that Microsoft does not support installing multiple versions of IE in one Windows. But there is hope: The folks at tredosoft came up with a nice installer, that allows you to install most versions of IE. There are some small drawbacks, but it should suffice for most tests. You can get it here: http://tredosoft.com/Multiple_IE.

Monday, November 20, 2006 11:11:44 AM (W. Europe Standard Time, UTC+01:00)
Comments [0]  | 

 

TransactionScope, ADO.NET, and Timeouts#

Someone has finally found a dirty, yet working solution to the TransactionScope problem. You can register an event on the transaction, that fires, when the transaction finishes, which also happens on a timeout. You can then abort the main thread, to keep further commands from executing.

And this is also the dirty part: ThreadAbortExceptions are a little dangerous and can cause unexpected behavior. But for now it works for me, and as long as Microsoft does not come up with a better solution, I'll have to use this.

You can find more details here: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=876150&SiteID=1

Saturday, November 18, 2006 11:10:16 AM (W. Europe Standard Time, UTC+01:00)
Comments [0]  | 

 

All content © 2008 , Christoph Herold