public async Task Invoke(IAddressable target, IInvokable invokable, Message message) { try { // Don't process messages that have already timed out if (message.IsExpired) { message.DropExpiredMessage(MessagingStatisticsGroup.Phase.Invoke); return; } RequestContext.Import(message.RequestContextData); if (Config.Globals.PerformDeadlockDetection && !message.TargetGrain.IsSystemTarget) { UpdateDeadlockInfoInRequestContext(new RequestInvocationHistory(message)); // RequestContext is automatically saved in the msg upon send and propagated to the next hop // in RuntimeClient.CreateMessage -> RequestContext.ExportToMessage(message); } object resultObject; try { var request = (InvokeMethodRequest)message.GetDeserializedBody(this.SerializationManager); if (request.Arguments != null) { CancellationSourcesExtension.RegisterCancellationTokens(target, request, logger, this); } var invoker = invokable.GetInvoker(typeManager, request.InterfaceId, message.GenericGrainType); if (invoker is IGrainExtensionMethodInvoker && !(target is IGrainExtension)) { // We are trying the invoke a grain extension method on a grain // -- most likely reason is that the dynamic extension is not installed for this grain // So throw a specific exception here rather than a general InvalidCastException var error = String.Format( "Extension not installed on grain {0} attempting to invoke type {1} from invokable {2}", target.GetType().FullName, invoker.GetType().FullName, invokable.GetType().FullName); var exc = new GrainExtensionNotInstalledException(error); string extraDebugInfo = null; #if DEBUG extraDebugInfo = Utils.GetStackTrace(); #endif logger.Warn(ErrorCode.Stream_ExtensionNotInstalled, string.Format("{0} for message {1} {2}", error, message, extraDebugInfo), exc); throw exc; } #pragma warning disable 618 var invokeInterceptor = this.CurrentStreamProviderRuntime?.GetInvokeInterceptor(); #pragma warning restore 618 var requestInvoker = new GrainMethodInvoker(target, request, invoker, siloInterceptors, interfaceToImplementationMapping, invokeInterceptor); await requestInvoker.Invoke(); resultObject = requestInvoker.Result; } catch (Exception exc1) { if (invokeExceptionLogger.IsVerbose || message.Direction == Message.Directions.OneWay) { invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message, exc1); } if (exc1 is InconsistentStateException && target is Grain) { var activation = ((Grain)target).Data; invokeExceptionLogger.Info($"Deactivating {activation} due to inconsistent state."); this.DeactivateOnIdle(activation.ActivationId); } if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc1); } return; } if (message.Direction == Message.Directions.OneWay) { return; } SafeSendResponse(message, resultObject); } catch (Exception exc2) { logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2); if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc2); } } }
public async Task Invoke(IAddressable target, IInvokable invokable, Message message) { try { // Don't process messages that have already timed out if (message.IsExpired) { message.DropExpiredMessage(MessagingStatisticsGroup.Phase.Invoke); return; } RequestContextExtensions.Import(message.RequestContextData); if (schedulingOptions.PerformDeadlockDetection && !message.TargetGrain.IsSystemTarget) { UpdateDeadlockInfoInRequestContext(new RequestInvocationHistory(message.TargetGrain, message.TargetActivation, message.DebugContext)); // RequestContext is automatically saved in the msg upon send and propagated to the next hop // in RuntimeClient.CreateMessage -> RequestContextExtensions.ExportToMessage(message); } bool startNewTransaction = false; ITransactionInfo transactionInfo = message.TransactionInfo; if (message.IsTransactionRequired && transactionInfo == null) { // TODO: this should be a configurable parameter var transactionTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(10); // Start a new transaction transactionInfo = await this.transactionAgent.Value.StartTransaction(message.IsReadOnly, transactionTimeout); startNewTransaction = true; } if (transactionInfo != null) { TransactionContext.SetTransactionInfo(transactionInfo); } object resultObject; try { var request = (InvokeMethodRequest)message.GetDeserializedBody(this.serializationManager); if (request.Arguments != null) { CancellationSourcesExtension.RegisterCancellationTokens(target, request, this.loggerFactory, logger, this, this.cancellationTokenRuntime); } var invoker = invokable.GetInvoker(typeManager, request.InterfaceId, message.GenericGrainType); if (invoker is IGrainExtensionMethodInvoker && !(target is IGrainExtension)) { // We are trying the invoke a grain extension method on a grain // -- most likely reason is that the dynamic extension is not installed for this grain // So throw a specific exception here rather than a general InvalidCastException var error = String.Format( "Extension not installed on grain {0} attempting to invoke type {1} from invokable {2}", target.GetType().FullName, invoker.GetType().FullName, invokable.GetType().FullName); var exc = new GrainExtensionNotInstalledException(error); string extraDebugInfo = null; #if DEBUG extraDebugInfo = Utils.GetStackTrace(); #endif logger.Warn(ErrorCode.Stream_ExtensionNotInstalled, string.Format("{0} for message {1} {2}", error, message, extraDebugInfo), exc); throw exc; } var requestInvoker = new GrainMethodInvoker(target, request, invoker, GrainCallFilters, interfaceToImplementationMapping); await requestInvoker.Invoke(); resultObject = requestInvoker.Result; } catch (Exception exc1) { if (invokeExceptionLogger.IsEnabled(LogLevel.Debug) || message.Direction == Message.Directions.OneWay) { invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message, exc1); } transactionInfo = TransactionContext.GetTransactionInfo(); if (transactionInfo != null) { // Must abort the transaction on exceptions transactionInfo.IsAborted = true; if (startNewTransaction) { var abortException = (exc1 as OrleansTransactionAbortedException) ?? new OrleansTransactionAbortedException(transactionInfo.TransactionId.ToString(), exc1); this.transactionAgent.Value.Abort(transactionInfo, abortException); exc1 = abortException; } } // If a grain allowed an inconsistent state exception to escape and the exception originated from // this activation, then deactivate it. var ise = exc1 as InconsistentStateException; if (ise != null && ise.IsSourceActivation) { // Mark the exception so that it doesn't deactivate any other activations. ise.IsSourceActivation = false; var activation = (target as Grain)?.Data; if (activation != null) { invokeExceptionLogger.Info($"Deactivating {activation} due to inconsistent state."); this.DeactivateOnIdle(activation.ActivationId); } } if (message.Direction != Message.Directions.OneWay) { TransactionContext.Clear(); SafeSendExceptionResponse(message, exc1); } return; } transactionInfo = TransactionContext.GetTransactionInfo(); if (transactionInfo != null && !transactionInfo.ReconcilePending(out var numberOrphans)) { var abortException = new OrleansOrphanCallException(transactionInfo.TransactionId.ToString(), numberOrphans); // Can't exit before the transaction completes. TransactionContext.GetTransactionInfo().IsAborted = true; if (startNewTransaction) { this.transactionAgent.Value.Abort(TransactionContext.GetTransactionInfo(), abortException); } if (message.Direction != Message.Directions.OneWay) { TransactionContext.Clear(); SafeSendExceptionResponse(message, abortException); } return; } if (startNewTransaction) { // This request started the transaction, so we try to commit before returning. await this.transactionAgent.Value.Commit(transactionInfo); TransactionContext.Clear(); } if (message.Direction == Message.Directions.OneWay) { return; } SafeSendResponse(message, resultObject); } catch (Exception exc2) { logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2); try { if (exc2 is OrleansTransactionInDoubtException) { this.logger.LogError(exc2, "Transaction failed due to in doubt transaction"); } else if (TransactionContext.GetTransactionInfo() != null) { // Must abort the transaction on exceptions TransactionContext.GetTransactionInfo().IsAborted = true; var abortException = (exc2 as OrleansTransactionAbortedException) ?? new OrleansTransactionAbortedException(TransactionContext.GetTransactionInfo().TransactionId.ToString(), exc2); this.transactionAgent.Value.Abort(TransactionContext.GetTransactionInfo(), abortException); } } finally { TransactionContext.Clear(); if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc2); } } } finally { TransactionContext.Clear(); } }
public async Task Invoke(IGrainContext target, Message message) { try { // Don't process messages that have already timed out if (message.IsExpired) { this.messagingTrace.OnDropExpiredMessage(message, MessagingStatisticsGroup.Phase.Invoke); return; } RequestContextExtensions.Import(message.RequestContextData); bool startNewTransaction = false; ITransactionInfo transactionInfo = message.TransactionInfo; if (message.IsTransactionRequired && transactionInfo == null) { // TODO: this should be a configurable parameter var transactionTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(10); // Start a new transaction transactionInfo = await this.transactionAgent.StartTransaction(message.IsReadOnly, transactionTimeout); startNewTransaction = true; } if (transactionInfo != null) { TransactionContext.SetTransactionInfo(transactionInfo); } object resultObject; try { var request = (InvokeMethodRequest)message.BodyObject; if (request.Arguments != null) { CancellationSourcesExtension.RegisterCancellationTokens(target, request); } if (!this.invokers.TryGet(message.InterfaceType, out var invoker)) { throw new KeyNotFoundException($"Could not find an invoker for interface {message.InterfaceType}"); } messagingTrace.OnInvokeMessage(message); var requestInvoker = new GrainMethodInvoker(target, request, invoker, GrainCallFilters, interfaceToImplementationMapping); await requestInvoker.Invoke(); resultObject = requestInvoker.Result; } catch (Exception exc1) { if (message.Direction == Message.Directions.OneWay) { this.invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message + ": " + LogFormatter.PrintException(exc1), exc1); } else if (invokeExceptionLogger.IsEnabled(LogLevel.Debug)) { this.invokeExceptionLogger.Debug(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message + ": " + LogFormatter.PrintException(exc1), exc1); } if (transactionInfo != null) { transactionInfo.ReconcilePending(); // Record reason for abort, if not already set. transactionInfo.RecordException(exc1, serializationManager); if (startNewTransaction) { exc1 = transactionInfo.MustAbort(serializationManager); await this.transactionAgent.Abort(transactionInfo); TransactionContext.Clear(); } } // If a grain allowed an inconsistent state exception to escape and the exception originated from // this activation, then deactivate it. var ise = exc1 as InconsistentStateException; if (ise != null && ise.IsSourceActivation) { // Mark the exception so that it doesn't deactivate any other activations. ise.IsSourceActivation = false; this.invokeExceptionLogger.Info($"Deactivating {target} due to inconsistent state."); this.DeactivateOnIdle(target.ActivationId); } if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc1); } return; } OrleansTransactionException transactionException = null; if (transactionInfo != null) { try { transactionInfo.ReconcilePending(); transactionException = transactionInfo.MustAbort(serializationManager); // This request started the transaction, so we try to commit before returning, // or if it must abort, tell participants that it aborted if (startNewTransaction) { try { if (transactionException is null) { var(status, exception) = await this.transactionAgent.Resolve(transactionInfo); if (status != TransactionalStatus.Ok) { transactionException = status.ConvertToUserException(transactionInfo.Id, exception); } } else { await this.transactionAgent.Abort(transactionInfo); } } finally { TransactionContext.Clear(); } } } catch (Exception e) { // we should never hit this, but if we do, the following message will help us diagnose this.logger.LogError(e, "Error in transaction post-grain-method-invocation code"); throw; } } if (message.Direction != Message.Directions.OneWay) { if (transactionException != null) { SafeSendExceptionResponse(message, transactionException); } else { SafeSendResponse(message, resultObject); } } return; } catch (Exception exc2) { this.logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2); TransactionContext.Clear(); if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc2); } } finally { RequestContext.Clear(); } }
public async Task Invoke(IAddressable target, IInvokable invokable, Message message) { try { // Don't process messages that have already timed out if (message.IsExpired) { this.messagingTrace.OnDropExpiredMessage(message, MessagingStatisticsGroup.Phase.Invoke); return; } RequestContextExtensions.Import(message.RequestContextData); if (schedulingOptions.PerformDeadlockDetection && !message.TargetGrain.IsSystemTarget()) { UpdateDeadlockInfoInRequestContext(new RequestInvocationHistory(message.TargetGrain, message.TargetActivation)); // RequestContext is automatically saved in the msg upon send and propagated to the next hop // in RuntimeClient.CreateMessage -> RequestContextExtensions.ExportToMessage(message); } bool startNewTransaction = false; ITransactionInfo transactionInfo = message.TransactionInfo; if (message.IsTransactionRequired && transactionInfo == null) { // TODO: this should be a configurable parameter var transactionTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(10); // Start a new transaction transactionInfo = await this.transactionAgent.StartTransaction(message.IsReadOnly, transactionTimeout); startNewTransaction = true; } if (transactionInfo != null) { TransactionContext.SetTransactionInfo(transactionInfo); } object resultObject; try { var request = (InvokeMethodRequest)message.BodyObject; if (request.Arguments != null) { CancellationSourcesExtension.RegisterCancellationTokens(target, request, this.loggerFactory, logger, this, this.cancellationTokenRuntime); } var invoker = invokable.GetInvoker(typeManager, request.InterfaceId, message.GenericGrainType); if (invoker is IGrainExtensionMethodInvoker && !(target is IGrainExtension) && !TryInstallExtension(request.InterfaceId, invokable, message.GenericGrainType, ref invoker)) { // We are trying the invoke a grain extension method on a grain // -- most likely reason is that the dynamic extension is not installed for this grain // So throw a specific exception here rather than a general InvalidCastException var error = String.Format( "Extension not installed on grain {0} attempting to invoke type {1} from invokable {2}", target.GetType().FullName, invoker.GetType().FullName, invokable.GetType().FullName); var exc = new GrainExtensionNotInstalledException(error); string extraDebugInfo = null; #if DEBUG extraDebugInfo = Utils.GetStackTrace(); #endif this.logger.Warn(ErrorCode.Stream_ExtensionNotInstalled, string.Format("{0} for message {1} {2}", error, message, extraDebugInfo), exc); throw exc; } messagingTrace.OnInvokeMessage(message); var requestInvoker = new GrainMethodInvoker(target, request, invoker, GrainCallFilters, interfaceToImplementationMapping); await requestInvoker.Invoke(); resultObject = requestInvoker.Result; } catch (Exception exc1) { if (message.Direction == Message.Directions.OneWay) { this.invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message + ": " + LogFormatter.PrintException(exc1), exc1); } else if (invokeExceptionLogger.IsEnabled(LogLevel.Debug)) { this.invokeExceptionLogger.Debug(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message + ": " + LogFormatter.PrintException(exc1), exc1); } if (transactionInfo != null) { transactionInfo.ReconcilePending(); // Record reason for abort, if not alread set transactionInfo.RecordException(exc1, serializationManager); if (startNewTransaction) { exc1 = transactionInfo.MustAbort(serializationManager); await this.transactionAgent.Abort(transactionInfo); TransactionContext.Clear(); } } // If a grain allowed an inconsistent state exception to escape and the exception originated from // this activation, then deactivate it. var ise = exc1 as InconsistentStateException; if (ise != null && ise.IsSourceActivation) { // Mark the exception so that it doesn't deactivate any other activations. ise.IsSourceActivation = false; var activation = (target as Grain)?.Data; if (activation != null) { this.invokeExceptionLogger.Info($"Deactivating {activation} due to inconsistent state."); this.DeactivateOnIdle(activation.ActivationId); } } if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc1); } return; } OrleansTransactionException transactionException = null; if (transactionInfo != null) { try { transactionInfo.ReconcilePending(); transactionException = transactionInfo.MustAbort(serializationManager); // This request started the transaction, so we try to commit before returning, // or if it must abort, tell participants that it aborted if (startNewTransaction) { try { if (transactionException == null) { var status = await this.transactionAgent.Resolve(transactionInfo); if (status != TransactionalStatus.Ok) { transactionException = status.ConvertToUserException(transactionInfo.Id); } } else { await this.transactionAgent.Abort(transactionInfo); } } finally { TransactionContext.Clear(); } } } catch (Exception e) { // we should never hit this, but if we do, the following message will help us diagnose this.logger.LogError(e, "Error in transaction post-grain-method-invocation code"); throw; } } if (message.Direction != Message.Directions.OneWay) { if (transactionException != null) { SafeSendExceptionResponse(message, transactionException); } else { SafeSendResponse(message, resultObject); } } return; } catch (Exception exc2) { this.logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2); TransactionContext.Clear(); if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc2); } } finally { RequestContext.Clear(); } }
internal async Task Invoke(IAddressable target, IInvokable invokable, Message message) { try { // Don't process messages that have already timed out if (message.IsExpired) { message.DropExpiredMessage(MessagingStatisticsGroup.Phase.Invoke); return; } RequestContext.Import(message.RequestContextData); if (Config.Globals.PerformDeadlockDetection && !message.TargetGrain.IsSystemTarget) { UpdateDeadlockInfoInRequestContext(new RequestInvocationHistory(message)); // RequestContext is automatically saved in the msg upon send and propagated to the next hop // in RuntimeClient.CreateMessage -> RequestContext.ExportToMessage(message); } object resultObject; try { var request = (InvokeMethodRequest)message.BodyObject; if (request.Arguments != null) { CancellationSourcesExtension.RegisterCancellationTokens(target, request, logger); } var invoker = invokable.GetInvoker(request.InterfaceId, message.GenericGrainType); if (invoker is IGrainExtensionMethodInvoker && !(target is IGrainExtension)) { // We are trying the invoke a grain extension method on a grain // -- most likely reason is that the dynamic extension is not installed for this grain // So throw a specific exception here rather than a general InvalidCastException var error = String.Format( "Extension not installed on grain {0} attempting to invoke type {1} from invokable {2}", target.GetType().FullName, invoker.GetType().FullName, invokable.GetType().FullName); var exc = new GrainExtensionNotInstalledException(error); string extraDebugInfo = null; #if DEBUG extraDebugInfo = new StackTrace().ToString(); #endif logger.Warn(ErrorCode.Stream_ExtensionNotInstalled, string.Format("{0} for message {1} {2}", error, message, extraDebugInfo), exc); throw exc; } // If the target has a grain-level interceptor or there is a silo-level interceptor, intercept the call. var shouldCallSiloWideInterceptor = SiloProviderRuntime.Instance.GetInvokeInterceptor() != null && target is IGrain; var intercepted = target as IGrainInvokeInterceptor; if (intercepted != null || shouldCallSiloWideInterceptor) { // Fetch the method info for the intercepted call. var implementationInvoker = invocationMethodInfoMap.GetInterceptedMethodInvoker(target.GetType(), request.InterfaceId, invoker); var methodInfo = implementationInvoker.GetMethodInfo(request.MethodId); if (shouldCallSiloWideInterceptor) { // There is a silo-level interceptor and possibly a grain-level interceptor. var runtime = SiloProviderRuntime.Instance; resultObject = await runtime.CallInvokeInterceptor(methodInfo, request, target, implementationInvoker); } else { // The grain has an interceptor, but there is no silo-wide interceptor. resultObject = await intercepted.Invoke(methodInfo, request, invoker); } } else { // The call is not intercepted. // TODO: this await here is just grabbing the first exception of the AggregateException. As a framework we shouldn't do that. resultObject = await invoker.Invoke(target, request); } } catch (Exception exc1) { if (invokeExceptionLogger.IsVerbose || message.Direction == Message.Directions.OneWay) { invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message, exc1); } if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc1); } return; } if (message.Direction == Message.Directions.OneWay) { return; } SafeSendResponse(message, resultObject); } catch (Exception exc2) { logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2); if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc2); } } }
/// <summary> /// Handles the an InvokeMethodRequest message on given target. /// </summary> /// <remarks> /// Options when we receive a InvokeMethodRequest /// ---------------------------------------------- /// 1) Intercepted RPC /// 2) Request to start a reactive computation for this method invocation /// 3) KeepAlive request of the reactive computation for this method invocation /// 4) Normal Application RPC /// 5) System RPC /// </remarks> /// <returns></returns> internal async Task Invoke(IAddressable target, IInvokable invokable, Message message) { try { // Don't process messages that have already timed out if (message.IsExpired) { message.DropExpiredMessage(MessagingStatisticsGroup.Phase.Invoke); return; } RequestContext.Import(message.RequestContextData); if (Config.Globals.PerformDeadlockDetection && !message.TargetGrain.IsSystemTarget) { UpdateDeadlockInfoInRequestContext(new RequestInvocationHistory(message)); // RequestContext is automatically saved in the msg upon send and propagated to the next hop // in RuntimeClient.CreateMessage -> RequestContext.ExportToMessage(message); } object resultObject; try { var request = (InvokeMethodRequest)message.BodyObject; if (request.Arguments != null) { CancellationSourcesExtension.RegisterCancellationTokens(target, request, logger); } // Get the invoker for this invocation IGrainMethodInvoker invoker = GetGrainMethodInvoker(target, invokable, message, request); // Check whether this call should be intercepted var siloWideInterceptor = SiloProviderRuntime.Instance.GetInvokeInterceptor(); var grainWithInterceptor = target as IGrainInvokeInterceptor; // Silo-wide interceptors do not operate on system targets. var hasSiloWideInterceptor = siloWideInterceptor != null && target is IGrain; var hasGrainLevelInterceptor = grainWithInterceptor != null; // Normal Application Call = an application call made from grain to grain or from client to grain. // Some system-related calls such as the IReminderTable are encoded as Application messages, therefore we needed this check. var NormalApplicationCall = message.Category == Message.Categories.Application && message.TargetGrain.IsGrain && (message.SendingGrain.IsGrain || message.SendingGrain.IsClient); // 1) If the target has a grain-level interceptor or there is a silo-level interceptor, intercept the // call. if (hasGrainLevelInterceptor || hasSiloWideInterceptor) { resultObject = await InvokeWithInterceptors(target, request, invoker, hasSiloWideInterceptor, siloWideInterceptor, hasGrainLevelInterceptor, grainWithInterceptor); } else if (NormalApplicationCall) { // 2) Request to start a reactive computation for this method invocation if (message.IsRcExecute()) { HandleReactiveComputationExecute(target, request, message, invoker); return; // Does not expect a return (OneWay Message) } // 3) Refresh Reactive Computation Subscription else if (message.IsRcKeepAlive()) { HandleReactiveComputationExecute(target, request, message, invoker, true); return; // Does not expect a return (OneWay Message) } // 4) Normal application RPC call else { // Invoke the method resultObject = await invoker.Invoke(target, request); // Check if there are any active reactive computations in this grain that require recomputation after this call InsideRcManager.RecomputeSummaries(); } } // 5) System RPC call else { resultObject = await invoker.Invoke(target, request); } } catch (Exception exc1) { if (invokeExceptionLogger.IsVerbose || message.Direction == Message.Directions.OneWay) { invokeExceptionLogger.Warn(ErrorCode.GrainInvokeException, "Exception during Grain method call of message: " + message, exc1); } if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc1); } return; } if (message.Direction == Message.Directions.OneWay) { return; } SafeSendResponse(message, resultObject); } catch (Exception exc2) { logger.Warn(ErrorCode.Runtime_Error_100329, "Exception during Invoke of message: " + message, exc2); if (message.Direction != Message.Directions.OneWay) { SafeSendExceptionResponse(message, exc2); } } }