トランザクション キューで netMsmqBinding を使用しています。WCF サービスは問題なく呼び出されますが、サービスはメッセージが処理されてからわずか 60 秒後に MsmqException をスローします。
これは例外です:
System.ServiceModel.MsmqException (0xC00E0051): キューからメッセージを受信中にエラーが発生しました: 認識できないエラー -1072824239 (0xc00e0051)。MSMQ がインストールされ、実行されていることを確認します。キューが受信できることを確認してください。System.ServiceModel.Channels.MsmqInputChannelBase.TryReceive (TimeSpan タイムアウト、Message& メッセージ) で System.ServiceModel.Dispatcher.InputChannelBinder.TryReceive (TimeSpan タイムアウト、RequestContext& requestContext) で System.ServiceModel.Dispatcher.ErrorHandlingReceiver.TryReceive (TimeSpan タイムアウト、RequestContext& requestContext) )
いくつかの調査、デバッグ、トレースを行ったところ、新しいメッセージを受信すると 2 つのトランザクションが開かれ、最初のトランザクションはサービスの実行直後にコミットされますが、2 つ目のトランザクションは決してコミットされないため、60 以降秒後に、DTC は MsmqException をスローして中止します。これは操作の定義です:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SomeOperation(SomeParameter parameter)
{
// business logic
}
何が起こっているのか、どうすればこの問題を解決できますか?
アップデート:
構成:
<netMsmqBinding>
<binding name="TransactionalMsmqBinding" exactlyOnce="true" deadLetterQueue="System" receiveErrorHandling="Move">
<security mode="None"/>
</binding>
</netMsmqBinding>
...
<service name="SomeNamespace.SomeService">
<endpoint contract="SomeNamespace.ISomeService" bindingConfiguration="TransactionalMsmqBinding" binding="netMsmqBinding" address="net.msmq://localhost/private/services/someservice.svc">
</endpoint>
<endpoint contract="SomeNamespace.IAnotherService" bindingConfiguration="TransactionalMsmqBinding" binding="netMsmqBinding" address="net.msmq://localhost/private/services/anotherservice.svc">
</endpoint>
</service>
サービスの実装:
[ExceptionShieldingBehavior(typeof(ArgumentValidationException), typeof(ValidationServiceException))]
[AuthorizationAndAuditBehaviour]
[ServiceBehavior(Namespace = GlobalConstants.ServiceContractNamespace)]
public class SomeService: ISomeService, IAnotherService
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SomeOperation(SomeParameter parameter)
{
// business logic
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void AnotherOperation(AnotherParameter parameter)
{
// business logic
}
}
サービス契約:
[ServiceContract(Namespace = GlobalConstants.ServiceContractNamespace)]
public interface ISomeService
{
[OperationContract(IsOneWay = true)]
void SomeOperation(SomeParameter parameter);
}
[ServiceContract(Namespace = GlobalConstants.ServiceContractNamespace)]
public interface IAnotherService
{
[OperationContract(IsOneWay = true)]
void AnotherOperation(AnotherParameter parameter);
}
完全な動作:
- クライアントがメッセージを送信します
- サービスが有効化されました
- DTC は 2 つのトランザクションを開始します (DTC モニターと TransactionManager.DistributedTransactionStarted イベントで確認できます)。
- 操作が終了するとすぐに最初のトランザクションが終了します
- 2 番目のトランザクションは 60 秒後に中止されます (MsmqException がスローされます)。
- wcf ホスト (IIS) に障害が発生することがあります (自動的に回復するコードがいくつかあります。.net 4 でこの動作が変更されたようです)。
- ホストが壊れて自動的に回復した場合、次のメッセージですべてが再び発生します
- ホストが壊れていなければ、次回は 2 番目のトランザクションは開始されず、すべて問題なく動作します :)。
- AppPool をリサイクルすると、問題が再び発生します