File: Util\Transactions.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="Transactions.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
/*
 * Transactions support for ASP.NET pages
 * 
 * Copyright (c) 2000, Microsoft Corporation
 */
namespace System.Web.Util {
 
using System.Collections;
using System.EnterpriseServices;
using System.Security.Permissions;
 
//
//  Delegate to the transacted managed code
//
 
 
/// <devdoc>
///    <para>[To be supplied.]</para>
/// </devdoc>
public delegate void TransactedCallback();
 
//
//  Delegate for the internal transacted execution
//
 
internal enum TransactedExecState {
    CommitPending = 0,
    AbortPending = 1,
    Error = 2
}
 
internal delegate int TransactedExecCallback();  // return value 'int' for interop
 
//
//  Utility class with to be called to do transactions
//
 
 
/// <devdoc>
///    <para>[To be supplied.]</para>
/// </devdoc>
public class Transactions {
 
    /// <devdoc>
    ///    <para>[To be supplied.]</para>
    /// </devdoc>
    public static void InvokeTransacted(TransactedCallback callback, TransactionOption mode) {
        bool aborted = false;
        InvokeTransacted(callback, mode, ref aborted);
    }
 
 
    /// <devdoc>
    ///    <para>[To be supplied.]</para>
    /// </devdoc>
    public static void InvokeTransacted(TransactedCallback callback, TransactionOption mode, ref bool transactionAborted) {
        // check for hosting permission even if no user code on the stack
        HttpRuntime.CheckAspNetHostingPermission(AspNetHostingPermissionLevel.Medium, SR.Transaction_not_supported_in_low_trust);
 
        bool executeWithoutTransaction = false;
 
#if !FEATURE_PAL // FEATURE_PAL does not enable Transactions
        if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major <= 4)
            throw new PlatformNotSupportedException(SR.GetString(SR.RequiresNT));
#else // !FEATURE_PAL
        throw new NotImplementedException("ROTORTODO");
#endif // !FEATURE_PAL
 
 
        if (mode == TransactionOption.Disabled)
            executeWithoutTransaction = true;
 
        if (executeWithoutTransaction) {
            // bypass the transaction logic
            callback();
            transactionAborted = false;
            return;
        }
 
        TransactedInvocation call = new TransactedInvocation(callback);
        TransactedExecCallback execCallback = new TransactedExecCallback(call.ExecuteTransactedCode);
 
        PerfCounters.IncrementCounter(AppPerfCounter.TRANSACTIONS_PENDING);
 
        int rc;
        try {
            rc = UnsafeNativeMethods.TransactManagedCallback(execCallback, (int)mode);
        }
        finally {
            PerfCounters.DecrementCounter(AppPerfCounter.TRANSACTIONS_PENDING);
        }
 
        // rethrow the expection originally caught in managed code
        if (call.Error != null)
            throw new HttpException(null, call.Error); 
 
        PerfCounters.IncrementCounter(AppPerfCounter.TRANSACTIONS_TOTAL);
 
        if (rc == 1) {
            PerfCounters.IncrementCounter(AppPerfCounter.TRANSACTIONS_COMMITTED);
            transactionAborted = false;
        }
        else if (rc == 0) {
            PerfCounters.IncrementCounter(AppPerfCounter.TRANSACTIONS_ABORTED);
            transactionAborted = true;
        }
        else {
            throw new HttpException(SR.GetString(SR.Cannot_execute_transacted_code));
        }
    }
 
    // Class with wrappers to ContextUtil that don't throw
 
    internal class Utils {
        private Utils() {
        }
 
        /*
        internal static String TransactionId {
            get {
                String id = null;
 
                try {
                    id = ContextUtil.TransactionId.ToString();
                }
                catch {
                }
 
                return id;
            }
        }
        */
 
        internal static bool IsInTransaction {
            get {
                bool inTransaction = false;
 
                try {
                    inTransaction = ContextUtil.IsInTransaction;
                }
                catch {
                }
 
                return inTransaction;
            }
        }
 
        internal static bool AbortPending {
            get {
                bool aborted = false;
 
                try {
                    if (ContextUtil.MyTransactionVote == TransactionVote.Abort)
                        aborted = true;
                }
                catch {
                }
 
                return aborted;
            }
        }
    }
 
    // Managed class encapsulating the transacted call
 
    internal class TransactedInvocation {
        private TransactedCallback _callback;
        private Exception _error;
 
        internal TransactedInvocation(TransactedCallback callback) {
            _callback = callback;
        }
 
        internal int ExecuteTransactedCode() {
            TransactedExecState state = TransactedExecState.CommitPending;
 
            try {
                _callback();
 
                if (Transactions.Utils.AbortPending)
                    state = TransactedExecState.AbortPending;
            }
            catch (Exception e) {
                _error = e;  // remember exception to be rethrown back in managed code
                state = TransactedExecState.Error;
            }
 
            return (int)state;
        }
 
        internal Exception Error {
            get { return _error; }
        }
    }
}
}