internal ImmutableDispatchRuntime(DispatchRuntime dispatch) { this.authenticationBehavior = AuthenticationBehavior.TryCreate(dispatch); this.authorizationBehavior = AuthorizationBehavior.TryCreate(dispatch); this.concurrency = new ConcurrencyBehavior(dispatch); this.error = new ErrorBehavior(dispatch.ChannelDispatcher); this.enableFaults = dispatch.EnableFaults; this.inputSessionShutdownHandlers = EmptyArray<IInputSessionShutdown>.ToArray(dispatch.InputSessionShutdownHandlers); this.instance = new InstanceBehavior(dispatch, this); this.isOnServer = dispatch.IsOnServer; this.manualAddressing = dispatch.ManualAddressing; this.messageInspectors = EmptyArray<IDispatchMessageInspector>.ToArray(dispatch.MessageInspectors); this.requestReplyCorrelator = new RequestReplyCorrelator(); this.securityImpersonation = SecurityImpersonationBehavior.CreateIfNecessary(dispatch); this.requireClaimsPrincipalOnOperationContext = dispatch.RequireClaimsPrincipalOnOperationContext; this.impersonateOnSerializingReply = dispatch.ImpersonateOnSerializingReply; this.terminate = TerminatingOperationBehavior.CreateIfNecessary(dispatch); this.thread = new ThreadBehavior(dispatch); this.validateMustUnderstand = dispatch.ValidateMustUnderstand; this.ignoreTransactionFlow = dispatch.IgnoreTransactionMessageProperty; this.transaction = TransactionBehavior.CreateIfNeeded(dispatch); this.receiveContextEnabledChannel = dispatch.ChannelDispatcher.ReceiveContextEnabled; this.sendAsynchronously = dispatch.ChannelDispatcher.SendAsynchronously; this.parameterInspectorCorrelationOffset = (dispatch.MessageInspectors.Count + dispatch.MaxCallContextInitializers); this.correlationCount = this.parameterInspectorCorrelationOffset + dispatch.MaxParameterInspectors; DispatchOperationRuntime unhandled = new DispatchOperationRuntime(dispatch.UnhandledDispatchOperation, this); if (dispatch.OperationSelector == null) { ActionDemuxer demuxer = new ActionDemuxer(); for (int i = 0; i < dispatch.Operations.Count; i++) { DispatchOperation operation = dispatch.Operations[i]; DispatchOperationRuntime operationRuntime = new DispatchOperationRuntime(operation, this); demuxer.Add(operation.Action, operationRuntime); } demuxer.SetUnhandled(unhandled); this.demuxer = demuxer; } else { CustomDemuxer demuxer = new CustomDemuxer(dispatch.OperationSelector); for (int i = 0; i < dispatch.Operations.Count; i++) { DispatchOperation operation = dispatch.Operations[i]; DispatchOperationRuntime operationRuntime = new DispatchOperationRuntime(operation, this); demuxer.Add(operation.Name, operationRuntime); } demuxer.SetUnhandled(unhandled); this.demuxer = demuxer; } this.processMessage1 = new MessageRpcProcessor(this.ProcessMessage1); this.processMessage11 = new MessageRpcProcessor(this.ProcessMessage11); this.processMessage2 = new MessageRpcProcessor(this.ProcessMessage2); this.processMessage3 = new MessageRpcProcessor(this.ProcessMessage3); this.processMessage31 = new MessageRpcProcessor(this.ProcessMessage31); this.processMessage4 = new MessageRpcProcessor(this.ProcessMessage4); this.processMessage41 = new MessageRpcProcessor(this.ProcessMessage41); this.processMessage5 = new MessageRpcProcessor(this.ProcessMessage5); this.processMessage6 = new MessageRpcProcessor(this.ProcessMessage6); this.processMessage7 = new MessageRpcProcessor(this.ProcessMessage7); this.processMessage8 = new MessageRpcProcessor(this.ProcessMessage8); this.processMessage9 = new MessageRpcProcessor(this.ProcessMessage9); this.processMessageCleanup = new MessageRpcProcessor(this.ProcessMessageCleanup); this.processMessageCleanupError = new MessageRpcProcessor(this.ProcessMessageCleanupError); }
internal void CheckIfTxCompletedAndUpdateAttached(ref MessageRpc rpc, bool isConcurrent) { if (rpc.Transaction.Current == null) { return; } lock (this.mutex) { if (!isConcurrent) { if (this.shouldReleaseInstance) { this.shouldReleaseInstance = false; if (rpc.Error == null) //we don't want to mask the initial error { rpc.Error = TransactionBehavior.CreateFault(SR.GetString(SR.SFxTransactionAsyncAborted), FaultCodeConstants.Codes.TransactionAborted, true); DiagnosticUtility.TraceHandledException(rpc.Error, TraceEventType.Error); if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxCompletionStatusCompletedForAsyncAbort, SR.GetString(SR.TraceCodeTxCompletionStatusCompletedForAsyncAbort, rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } } } if (rpc.Transaction.IsCompleted || (rpc.Error != null)) { if (DiagnosticUtility.ShouldTraceInformation) { if (rpc.Error != null) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxCompletionStatusCompletedForError, SR.GetString(SR.TraceCodeTxCompletionStatusCompletedForError, rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } else { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxCompletionStatusCompletedForAutocomplete, SR.GetString(SR.TraceCodeTxCompletionStatusCompletedForAutocomplete, rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } } this.Attached = null; if (!(waiting == null)) { // tx processing requires failfast when state is inconsistent DiagnosticUtility.FailFast("waiting should be null when resetting current"); } this.current = null; } else { this.Attached = rpc.Transaction.Current; if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxCompletionStatusRemainsAttached, SR.GetString(SR.TraceCodeTxCompletionStatusRemainsAttached, rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } } } else if (!this.pending.ContainsKey(rpc.Transaction.Current)) { //transaction has been asynchronously aborted if (rpc.Error == null) //we don't want to mask the initial error { rpc.Error = TransactionBehavior.CreateFault(SR.GetString(SR.SFxTransactionAsyncAborted), FaultCodeConstants.Codes.TransactionAborted, true); DiagnosticUtility.TraceHandledException(rpc.Error, TraceEventType.Error); if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxCompletionStatusCompletedForAsyncAbort, SR.GetString(SR.TraceCodeTxCompletionStatusCompletedForAsyncAbort, rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } } } } }
internal void CheckIfTxCompletedAndUpdateAttached(ref MessageRpc rpc, bool isConcurrent) { if (rpc.Transaction.Current != null) { lock (this.mutex) { if (!isConcurrent) { if (this.shouldReleaseInstance) { this.shouldReleaseInstance = false; if (rpc.Error == null) { rpc.Error = TransactionBehavior.CreateFault(System.ServiceModel.SR.GetString("SFxTransactionAsyncAborted"), "TransactionAborted", true); DiagnosticUtility.ExceptionUtility.TraceHandledException(rpc.Error, TraceEventType.Error); if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, 0xe0009, System.ServiceModel.SR.GetString("TraceCodeTxCompletionStatusCompletedForAsyncAbort", new object[] { rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name })); } } } if (rpc.Transaction.IsCompleted || (rpc.Error != null)) { if (DiagnosticUtility.ShouldTraceInformation) { if (rpc.Error != null) { TraceUtility.TraceEvent(TraceEventType.Information, 0xe0006, System.ServiceModel.SR.GetString("TraceCodeTxCompletionStatusCompletedForError", new object[] { rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name })); } else { TraceUtility.TraceEvent(TraceEventType.Information, 0xe0005, System.ServiceModel.SR.GetString("TraceCodeTxCompletionStatusCompletedForAutocomplete", new object[] { rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name })); } } this.Attached = null; if (this.waiting != null) { DiagnosticUtility.FailFast("waiting should be null when resetting current"); } this.current = null; } else { this.Attached = rpc.Transaction.Current; if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, 0xe000a, System.ServiceModel.SR.GetString("TraceCodeTxCompletionStatusRemainsAttached", new object[] { rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name })); } } } else if (!this.pending.ContainsKey(rpc.Transaction.Current) && (rpc.Error == null)) { rpc.Error = TransactionBehavior.CreateFault(System.ServiceModel.SR.GetString("SFxTransactionAsyncAborted"), "TransactionAborted", true); DiagnosticUtility.ExceptionUtility.TraceHandledException(rpc.Error, TraceEventType.Error); if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, 0xe0009, System.ServiceModel.SR.GetString("TraceCodeTxCompletionStatusCompletedForAsyncAbort", new object[] { rpc.Transaction.Current.TransactionInformation.LocalIdentifier, rpc.Operation.Name })); } } } } }
internal void ResolveTransaction(ref MessageRpc rpc) { if (rpc.Operation.HasDefaultUnhandledActionInvoker) { // we ignore unhandled operations return; } Transaction contextTransaction = null; //If we are inside a TransactedReceiveScope in workflow, then we need to look into the PPD and not the InstanceContext //to get the contextTransaction if (rpc.Operation.IsInsideTransactedReceiveScope) { // We may want to use an existing transaction for the instance. IInstanceTransaction instanceTransaction = rpc.Operation.Invoker as IInstanceTransaction; if (instanceTransaction != null) { contextTransaction = instanceTransaction.GetTransactionForInstance(rpc.OperationContext); } if (contextTransaction != null) { if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxSourceTxScopeRequiredUsingExistingTransaction, SR.GetString(SR.TraceCodeTxSourceTxScopeRequiredUsingExistingTransaction, contextTransaction.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } } } else { contextTransaction = this.GetInstanceContextTransaction(ref rpc); } Transaction transaction = null; try { transaction = TransactionMessageProperty.TryGetTransaction(rpc.Request); } catch (TransactionException e) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Error); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(TransactionBehavior.CreateFault(SR.GetString(SR.SFxTransactionUnmarshalFailed, e.Message), FaultCodeConstants.Codes.TransactionUnmarshalingFailed, false)); } if (rpc.Operation.TransactionRequired) { if (transaction != null) { if (this.isTransactedReceiveChannelDispatcher) { if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxSourceTxScopeRequiredIsTransactedTransport, SR.GetString(SR.TraceCodeTxSourceTxScopeRequiredIsTransactedTransport, transaction.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } } else { if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxSourceTxScopeRequiredIsTransactionFlow, SR.GetString(SR.TraceCodeTxSourceTxScopeRequiredIsTransactionFlow, transaction.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } if (PerformanceCounters.PerformanceCountersEnabled) { PerformanceCounters.TxFlowed(PerformanceCounters.GetEndpointDispatcher(), rpc.Operation.Name); } bool sameTransaction = false; if (rpc.Operation.IsInsideTransactedReceiveScope) { sameTransaction = transaction.Equals(contextTransaction); } else { sameTransaction = transaction == contextTransaction; } if (!sameTransaction) { try { transaction = transaction.DependentClone(DependentCloneOption.RollbackIfNotComplete); } catch (TransactionException e) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Error); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(TransactionBehavior.CreateFault(SR.GetString(SR.SFxTransactionAsyncAborted), FaultCodeConstants.Codes.TransactionAborted, true)); } } } } } else { // We got a transaction from the ChannelHandler. // Transport is transacted. // But operation doesn't require the transaction, so no one ever will commit it. // Because of that we have to commit it here. if (transaction != null && this.isTransactedReceiveChannelDispatcher) { try { if (null != rpc.TransactedBatchContext) { rpc.TransactedBatchContext.ForceCommit(); rpc.TransactedBatchContext = null; } else { TransactionInstanceContextFacet.Complete(transaction, null); } } finally { transaction.Dispose(); transaction = null; } } } InstanceContext context = rpc.InstanceContext; if (context.Transaction.ShouldReleaseInstance && !this.isConcurrent) { if (context.Behavior.ReleaseServiceInstanceOnTransactionComplete) { context.ReleaseServiceInstance(); if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxReleaseServiceInstanceOnCompletion, SR.GetString(SR.TraceCodeTxReleaseServiceInstanceOnCompletion, contextTransaction.TransactionInformation.LocalIdentifier) ); } } context.Transaction.ShouldReleaseInstance = false; if (transaction == null || transaction == contextTransaction) { rpc.Transaction.Current = contextTransaction; throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(TransactionBehavior.CreateFault(SR.GetString(SR.SFxTransactionAsyncAborted), FaultCodeConstants.Codes.TransactionAborted, true)); } else { contextTransaction = null; } } if (rpc.Operation.TransactionRequired) { if (transaction == null) { if (contextTransaction != null) { transaction = contextTransaction; if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxSourceTxScopeRequiredIsAttachedTransaction, SR.GetString(SR.TraceCodeTxSourceTxScopeRequiredIsAttachedTransaction, transaction.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } } else { transaction = TransactionBehavior.CreateTransaction(this.isolation, this.timeout); if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.TxSourceTxScopeRequiredIsCreateNewTransaction, SR.GetString(SR.TraceCodeTxSourceTxScopeRequiredIsCreateNewTransaction, transaction.TransactionInformation.LocalIdentifier, rpc.Operation.Name) ); } } } if ((this.isolation != IsolationLevel.Unspecified) && (transaction.IsolationLevel != this.isolation)) { throw TraceUtility.ThrowHelperError(TransactionBehavior.CreateFault (SR.GetString(SR.IsolationLevelMismatch2, transaction.IsolationLevel, this.isolation), FaultCodeConstants.Codes.TransactionIsolationLevelMismatch, false), rpc.Request); } rpc.Transaction.Current = transaction; rpc.InstanceContext.Transaction.AddReference(ref rpc, rpc.Transaction.Current, true); try { rpc.Transaction.Clone = transaction.Clone(); if (rpc.Operation.IsInsideTransactedReceiveScope) { //It is because we want to synchronize the dispatcher processing of messages with the commit //processing that is started by the completion of a TransactedReceiveScope. We need to make sure //that all the dispatcher processing is done and we can do that by creating a blocking dependent clone and only //completing it after all of the message processing is done for a given TransactionRpcFacet rpc.Transaction.CreateDependentClone(); } } catch (ObjectDisposedException e)//transaction may be async aborted { DiagnosticUtility.TraceHandledException(e, TraceEventType.Error); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(TransactionBehavior.CreateFault(SR.GetString(SR.SFxTransactionAsyncAborted), FaultCodeConstants.Codes.TransactionAborted, true)); } rpc.InstanceContext.Transaction.AddReference(ref rpc, rpc.Transaction.Clone, false); rpc.OperationContext.TransactionFacet = rpc.Transaction; if (!rpc.Operation.TransactionAutoComplete) { rpc.Transaction.SetIncomplete(); } } }