【问题标题】:try/catch in TransactionScope in C#在 C# 中的 TransactionScope 中尝试/捕获
【发布时间】:2013-07-22 10:39:52
【问题描述】:

我在我的 C# 代码中使用事务。在 TransactionScope 中,我记录了几乎所有内容,以确保所有内容都在测试中完成。但是,如果事务中发生了某些事情并且它去捕获我的日志类不会写任何东西。在本地主机中,我将 TransactionScopeOption 更改为“Suppress”,因为数据库不在我的服务器中。当我调试一切正常时,我可以写入日志文件。但是当我更改为“Required”时,如果它给出错误,它会像往常一样取消一切,但它也不能先写入日志。 我该如何解决这个问题?

我的代码示例:

TransactionOptions tr = new TransactionOptions();
tr.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tr, System.Transactions.EnterpriseServicesInteropOption.Automatic))//System.TimeSpan.MaxValue))
{
    bool status = false;
    // this log must be written anyway but it won't when it gives an error.
    LogProcess log = new LogProcess(Ssession["DBNAME"], new Guid(), "Transaction begun.");
    try
    {
        // process 1
        // process 2
        .
        .
        .
        if(status)
        {
            LogProcess log1 = new LogProcess(Ssession["DBNAME"], new Guid(), "Transaction will complete soon.");
            scope.Complete();
            LogProcess log1 = new LogProcess(Ssession["DBNAME"], new Guid(), "Transaction completed.");
        }
        else
        {
            LogProcess log2 = new LogProcess(Ssession["DBNAME"], new Guid(), "Transaction will dispose.");
            scope.Dispose();
            LogProcess log2 = new LogProcess(Ssession["DBNAME"], new Guid(), "Transaction disposed.");
        }

    }
    catch(Exception ex)
    {
        LogProcess log1 = new LogProcess(Ssession["DBNAME"], new Guid(), "Transaction exception. Error: " + ex.Message);
        scope.Dispose();
    }
}

【问题讨论】:

  • 日志是否也写入数据库?如果是,那是你的问题。当出现错误时,日志也会被回滚。您需要将日志包装到另一个事务中或记录到其他地方,例如文本文件。
  • @tucaz 谢谢,你是对的。但即使在 scope.Complete() 之后一切正常,它也无法写入日志。
  • 这听起来像是日志记录的问题。什么是“日志处理”?我不熟悉它。它在您的应用程序的其他地方工作吗?
  • 出于性能原因,大多数日志提供程序“批量”将日志写入数据库,如果您等到发出一定数量的日志请求,那么您将看到它们全部在一起。
  • 我也担心 using 语句中的手动 scope.Dispose() 。您不需要它,因为它会在离开“使用”范围后立即被处置。

标签: c# asp.net transactionscope


【解决方案1】:

首先,我发现您的代码示例的结构相当混乱。使用 TransactionScope 时,通常不会在调用 scope.Complete() 或 scope.Dispose() 之后编写语句。此外, using 语句为您处理范围,因此恕我直言,如果您能提供帮助,您不应显式调用 scope.Dispose()。换句话说:尝试重构您的代码,使其看起来像这样:

private void PerformTransactionalOperation()
{
    Log.Write("Starting operation.");        

    try
    {
        using (var scope = CreateTransactionScope())
        {
            if (PerformTransactionalOperationCore())
            {
                Log.Write("Committing...");
                scope.Complete();
                Log.Write("Committed");
            }
            else
            {
                Log.Write("Operation aborted.");
            }
        }
    }
    catch (Exception exception)
    {
        Log.Write("Operation failed: " + exception.Message);
        throw;
    }
}

private bool PerformTransactionalOperationCore()
{
    // Perform operations and return status...
}

其次,事务范围专门设计为仅在未引发异常时完成,因此您的设计可以通过让 PerformTransactionalOperationCore 抛出特定异常而不是返回 false 来改进。

然后关于日志记录问题:确保您的日志记录框架不参与与您正在记录的操作相同的事务。您可以通过始终在带有选项 Suppress 的 TransactionScope 中登录来做到这一点(即,当您首先登录到事务感知的资源时,例如数据库)。顺便说一句,你为什么要通过实例化新的 LogProcess 实例来编写日志语句?

【讨论】:

  • 我要试试。谢谢你。我的日志类通常很宽。我的客户想看到几乎所有东西。那只是一个测试示例。
  • 我了解您的要求,如果您的客户需要,您需要放入大量日志语句,我只是好奇您为什么选择以您的方式实现它:实例化一个不是很传统每次需要记录新对象时(假设 LogProcess 构造器执行实际写入)。
猜你喜欢
  • 1970-01-01
  • 2015-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多