public virtual void DetachDuplexInputChannel(string channelId)
        {
            using (EneterTrace.Entering())
            {
                using (ThreadLock.Lock(myDuplexInputChannelContextManipulatorLock))
                {
                    // Get the context of the requested input channel.
                    TDuplexInputChannelContext aDuplexInputChannelContext = myDuplexInputChannelContexts.FirstOrDefault(x => x.AttachedDuplexInputChannel.ChannelId == channelId);
                    if (aDuplexInputChannelContext != null)
                    {
                        try
                        {
                            // Go via all connections with clients and close them.
                            CloseConnections(aDuplexInputChannelContext.OpenConnections);

                            // Stop listening to the duplex input channel.
                            aDuplexInputChannelContext.AttachedDuplexInputChannel.StopListening();
                        }
                        finally
                        {
                            aDuplexInputChannelContext.AttachedDuplexInputChannel.ResponseReceiverDisconnected -= OnDuplexInputChannelResponseReceiverDisconnected;
                            aDuplexInputChannelContext.AttachedDuplexInputChannel.MessageReceived -= OnMessageReceived;

                            myDuplexInputChannelContexts.RemoveWhere(x => x.AttachedDuplexInputChannel.ChannelId == aDuplexInputChannelContext.AttachedDuplexInputChannel.ChannelId);
                        }
                    }
                }
            }
        }
        private IDuplexOutputChannel GetAssociatedDuplexOutputChannel(string duplexInputChannelId, string responseReceiverId, string duplexOutputChannelId)
        {
            using (EneterTrace.Entering())
            {
                using (ThreadLock.Lock(myDuplexInputChannelContextManipulatorLock))
                {
                    TDuplexInputChannelContext aDuplexInputChannelContext = myDuplexInputChannelContexts.FirstOrDefault(x => x.AttachedDuplexInputChannel.ChannelId == duplexInputChannelId);
                    if (aDuplexInputChannelContext == null)
                    {
                        string anError = TracedObject + "failed to return the duplex output channel associated with the duplex input channel '" + duplexInputChannelId + "' because the duplex input channel was not attached.";
                        EneterTrace.Error(anError);
                        throw new InvalidOperationException(anError);
                    }

                    TConnection aConnection = aDuplexInputChannelContext.OpenConnections.FirstOrDefault(x => x.ResponseReceiverId == responseReceiverId && x.ConnectedDuplexOutputChannel.ChannelId == duplexOutputChannelId);
                    if (aConnection == null)
                    {
                        IDuplexOutputChannel anAssociatedDuplexOutputChannel = MessagingSystemFactory.CreateDuplexOutputChannel(duplexOutputChannelId);

                        try
                        {
                            anAssociatedDuplexOutputChannel.ResponseMessageReceived += OnResponseMessageReceived;
                            anAssociatedDuplexOutputChannel.OpenConnection();
                        }
                        catch (Exception err)
                        {
                            anAssociatedDuplexOutputChannel.ResponseMessageReceived -= OnResponseMessageReceived;

                            EneterTrace.Error(TracedObject + "failed to open connection for the duplex output channel '" + duplexOutputChannelId + "'.", err);
                            throw;
                        }


                        aConnection = new TConnection(responseReceiverId, anAssociatedDuplexOutputChannel);
                        aDuplexInputChannelContext.OpenConnections.Add(aConnection);
                    }

                    return(aConnection.ConnectedDuplexOutputChannel);
                }
            }
        }
        protected void SendResponseMessage(string duplexOutputChannelResponseReceiverId, object message)
        {
            using (EneterTrace.Entering())
            {
                using (ThreadLock.Lock(myDuplexInputChannelContextManipulatorLock))
                {
                    TConnection anAssociatedConnection = null;
                    TDuplexInputChannelContext aDuplexInputChannelContext = myDuplexInputChannelContexts.FirstOrDefault(x =>
                    {
                        anAssociatedConnection = x.OpenConnections.FirstOrDefault(xx => xx.ConnectedDuplexOutputChannel.ResponseReceiverId == duplexOutputChannelResponseReceiverId);
                        return(anAssociatedConnection != null);
                    });

                    if (aDuplexInputChannelContext == null)
                    {
                        string anError = TracedObject + "failed to send the response message because the duplex input channel associated with the response was not found.";
                        EneterTrace.Error(anError);
                        throw new InvalidOperationException(anError);
                    }

                    if (anAssociatedConnection == null)
                    {
                        string anError = TracedObject + "failed to send the response message because the duplex output channel with the given response receiver id was not found.";
                        EneterTrace.Error(anError);
                        throw new InvalidOperationException(anError);
                    }

                    try
                    {
                        aDuplexInputChannelContext.AttachedDuplexInputChannel.SendResponseMessage(anAssociatedConnection.ResponseReceiverId, message);
                    }
                    catch (Exception err)
                    {
                        EneterTrace.Error(TracedObject + "failed to send the response message for the response receiver '" + anAssociatedConnection.ResponseReceiverId + "' through the duplex input channel '" + aDuplexInputChannelContext.AttachedDuplexInputChannel.ChannelId + "'.", err);
                        throw;
                    }
                }
            }
        }