Ron*_*erg 1 c# transactions .net-4.0 workflow-foundation workflow-foundation-4
我在Windows服务中有一个工作流,它是一个定期执行工作的循环.这项工作是在一项TryCatch活动中完成的.该Try属性是一个TransactionScope活动,它包含一些读取和更新数据库的自定义活动.当事务失败时,我会指望任何导致它被捕获的异常TryCatch.但是,我的工作流程中止了.我的工作流程如下:
var wf = new While(true)
{
Body = new Sequence
{
Activities =
{
new TryCatch
{
Try = new TransactionScope
{
IsolationLevel = IsolationLevel.ReadCommitted,
Body = new Sequence
{
Activities = { ..custom database activities.. }
},
AbortInstanceOnTransactionFailure = false
},
Catches =
{
new Catch<Exception>
{
Action = new ActivityAction<Exception>
{
Argument = exception,
Handler = ..log error..
}
}
}
},
new Delay { Duration = new InArgument<TimeSpan>(duration) }
}
},
}
Run Code Online (Sandbox Code Playgroud)
在我的情况下,数据库有时可能不可用,所以显然事务不会提交.在这种情况下会发生的情况是工作流中止,但有以下异常:
System.OperationCanceledException:处理当前工作项的错误导致工作流中止.
内在的例外是:
System.Transactions.TransactionException:该操作对事务的状态无效.
这是有道理的,因为我刚刚关闭了数据库.但是,为什么我的TryCatch活动不会处理此异常?
编辑1:一些额外的信息.我使用WorkflowApplication该类运行工作流程.为了更好地了解发生了什么,我指定了属性Aborted和OnUnhandledException.当异常发生时,它会直接进入Aborted并被OnUnhandledException跳过(尽管这显然是一个未处理的异常).
编辑2:我启用了调试日志,这提供了一些额外的见解."自定义数据库活动"成功运行完成.指示出现错误的第一个事件日志条目是详细级别消息:运行时事务已完成,状态为"已中止".接下来我看到一条信息消息:WorkflowInstance Id:'dbd1ba5c-2d8a-428c-970d-21215d7e06d9'DME活动(不确定这意味着什么).之后的信息消息是:Activity'System.Activities.Statements.TransactionScope',DisplayName:'run for run immediately checks',InstanceId:'389'已在'Faulted'状态下完成.
在此消息之后,我看到每个父母(包括TryCatch活动)在"故障"状态下完成,以我的工作流程中止结束.
编辑3:要清楚,当任何"自定义数据库活动"发生异常时,一切都按预期工作.捕获异常并继续工作流程.只有在事务结束时无法提交时才会出错TransactionScope.请参阅从Aborted回调中记录的以下stacktrace :
at System.Transactions.TransactionStateInDoubt.Rollback(InternalTransaction tx, Exception e)
at System.Transactions.Transaction.Rollback(Exception e)
at System.Activities.Runtime.ActivityExecutor.CompleteTransactionWorkItem.HandleException(Exception exception)
Run Code Online (Sandbox Code Playgroud)
如果您按照来自的电话TransactionScope.OnCompletion(...),最终您将从ActivityExecutor堆栈跟踪到达课程.
事务以异步方式提交事务.由于资源管理器级别的问题,您无法对提交事务的失败作出反应.
正如您所指出的,您可以处理活动中发生的异常.如果您查看工作流程的跟踪记录,我猜您会在事务中止之前看到TryCatch活动已关闭.
很多年前,当我是COM +团队的项目经理时,我研究了这个问题,因为人们通常需要一个事务组件(或工作流),因为在这种情况下能够对事务中止作出反应.
事务解析的异步性质意味着您无法在组件本身中对其做出反应.解决方案是在调用者中做出反应,然后可以采取一些行动.
设计假设是,一旦事务中止,就不能安全地使用事务中的状态 - 它将全部被丢弃,因为事务被中止.