예제 #1
0
        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));
            }
        }
예제 #2
0
        // 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.");
                }
            }
        }