e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
203 lines
5.6 KiB
C#
203 lines
5.6 KiB
C#
//------------------------------------------------------------------------------
|
|
// <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; }
|
|
}
|
|
}
|
|
}
|
|
}
|