protected override void OnConnectionClosed(object sender, DuplexChannelEventArgs e) { using (EneterTrace.Entering()) { // Release all pending RPC calls. RemoteCallContext[] aPendingCalls; using (ThreadLock.Lock(myPendingRemoteCalls)) { aPendingCalls = myPendingRemoteCalls.Values.ToArray(); } if (aPendingCalls != null) { RpcException anException = new RpcException("Connection was broken or closed.", "", ""); foreach (RemoteCallContext aRemoteCallContext in aPendingCalls) { aRemoteCallContext.Error = anException; aRemoteCallContext.RpcCompleted.Set(); } } // Forward the event. myThreadDispatcher.Invoke(() => Notify(ConnectionClosed, e)); } }
// This method is called when a message from the service is received. // This can be either the response for a request or it can be an event raised in the service. protected override void OnResponseMessageReceived(object sender, DuplexChannelMessageEventArgs e) { using (EneterTrace.Entering()) { RpcMessage aMessage = null; try { aMessage = mySerializer.ForResponseReceiver(e.ResponseReceiverId).Deserialize <RpcMessage>(e.Message); } catch (Exception err) { EneterTrace.Error(TracedObject + "failed to deserialize incoming message.", err); return; } // If it is a response for a call. if (aMessage.Request == ERpcRequest.Response) { EneterTrace.Debug("RETURN FROM RPC RECEIVED"); // Try to find if there is a pending request waiting for the response. RemoteCallContext anRpcContext; using (ThreadLock.Lock(myPendingRemoteCalls)) { myPendingRemoteCalls.TryGetValue(aMessage.Id, out anRpcContext); } if (anRpcContext != null) { if (string.IsNullOrEmpty(aMessage.ErrorType)) { anRpcContext.SerializedReturnValue = aMessage.SerializedReturn; } else { RpcException anException = new RpcException(aMessage.ErrorMessage, aMessage.ErrorType, aMessage.ErrorDetails); anRpcContext.Error = anException; } // Release the pending request. anRpcContext.RpcCompleted.Set(); } } else if (aMessage.Request == ERpcRequest.RaiseEvent) { EneterTrace.Debug("EVENT FROM SERVICE RECEIVED"); if (aMessage.SerializedParams != null && aMessage.SerializedParams.Length > 0) { // Try to raise an event. // The event is raised in its own thread so that the receiving thread is not blocked. // Note: raising an event cannot block handling of response messages because it can block // processing of an RPC response for which the RPC caller thread is waiting. // And if this waiting caller thread is a thread where events are routed and if the routing // of these events is 'blocking' then a deadlock can occur. // Therefore ThreadPool is used. EneterThreadPool.QueueUserWorkItem(() => myThreadDispatcher.Invoke(() => RaiseEvent(aMessage.OperationName, aMessage.SerializedParams[0]))); } else { // Note: this happens if the event is of type EventErgs. // The event is raised in its own thread so that the receiving thread is not blocked. EneterThreadPool.QueueUserWorkItem(() => myThreadDispatcher.Invoke(() => RaiseEvent(aMessage.OperationName, null))); } } else { EneterTrace.Warning(TracedObject + "detected a message with unknown flag number."); } } }