我有一个典型的WCF 4.0服务,使用wsHttpBinding
设置transactionFlow="true"
:
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
[FaultContract(typeof(Invalid))]
void DoWork();
这是我的服务器端实现:
[ServiceBehavior(
ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.Single,
TransactionIsolationLevel = IsolationLevel.Serializable,
TransactionTimeout = "00:00:15",
ReleaseServiceInstanceOnTransactionComplete = false
)]
public class MyService: IMyService {
[OperationBehavior(TransactionScopeRequired = false)]
public void DoWork() {
if (System.Transactions.Transaction.Current == null)
Trace.TraceInformation("WTF?!");
}
}
和客户端电话:
channel.DoWork(); // `Transaction.Current` is null at server-side as expected
using (var tx = new TransactionScope()) {
channel.DoWork(); // Transaction.Current is still null at server-side! :(
// .......
}
当我将TransactionScopeRequired
更改为true
时,我在服务器端获得了我预期的分布式事务,但现在我在没有外部范围的情况下调用了事件:
channel.DoWork(); // Transaction.Current is not null
如果我返回Invalid
错误,最令人讨厌的是它会回滚我内部已完成的范围内的任何内容!这意味着在调用我的服务时我被迫总是使用显式事务范围TransactionFlowOption.Allowed
。那是为什么?
我尝试将TransactionAutoComplete = false
添加到OperationBehavior
声明,希望能解决问题但是
System.InvalidOperationException:T合同上的“创建”操作 'IUserIdentityStore'配置为TransactionAutoComplete设置为 false并且ConcurrencyMode未设置为Single。 TransactionAutoComplete设置为false需要ConcurrencyMode.Single。
这太荒谬了。
换句话说 - 当我返回声明的错误时,如何获得可选的事务流行为并且没有自动回滚?
答案 0 :(得分:2)
TransactionScopeRequired文档明确指出,如果TransactionScopeRequired为false,则该方法将在没有事务的情况下执行。
对于自动回滚问题,如果TransactionAutoComplete设置为true,则所有未处理的异常(Faults is Exceptions)确实会回滚事务,这是有道理的:分布式事务的此参与者出现问题,因此事务必须回滚。如果你说无效的故障确实不是一个错误,那么你应该使用另一种机制来指示成功或失败,比如从服务中返回结果代码。
接下来,您的服务定义对我来说有点奇怪: InstanceContextMode设置为Single,表示您的服务将是一个单例:只有一个服务实例正在运行。此外,ConcurrencyMode设置为Multiple,表示多个客户端可以同时使用该单个实例。
我建议您将InstanceContextMode设置为PerCall,将ConcurrencyMode设置为Single,这将为每个客户端调用创建一个新的专用服务实例。在Code Project上有一篇关于WCF并发的优秀文章。