Как получить статус соединения Websphere MQ и как сбросить соединение:

1.) Как проверить, подключен ли клиент к серверу с помощью .net-клиента (то есть можно отправлять и получать)? Да, я могу отправить сообщение внутри блока try и поймать следующее исключение, но я 'Я надеюсь на более элегантное решение.

2) Как я могу открывать, закрывать и повторно открывать соединения? В моих попытках решить вопрос 1 выше я обнаружил, что если я открываю соединение, то вызываю connection.Close () Я не могу получить другое соединение от фабрики соединений (см. Фрагмент кода ниже). Я получаю сообщение об ошибке XMSCC0008

Я использую очень стандартную конфигурацию vanilla MQ. Вот как подключается мой клиент:

ISession session = MQAccess.GetSession(MQAccess.Connection);
IDestination destination = session.CreateTopic(SubTopicName);
Consumer = MQAccess.GetConsumer(session, destination);
Consumer.MessageListener = new MessageListener(HandleMQSubEvent);
MQAccess.Connection.Start();

где MQAccess - это небольшой служебный класс.

Отредактировал вопрос для добавления кода MQAccess:

public static class MQAccess
{
    public static readonly MQConfigurationSectionHandler ConfigSettings;
    public static readonly IConnectionFactory ConnectionFactory;

    private static readonly IConnection connection;
    public static IConnection Connection
    {
        get { return connection; }
    }

    static MQAccess()
    {
        ConfigSettings = (MQConfigurationSectionHandler)
            ConfigurationManager.GetSection("mq-configuration");

        XMSFactoryFactory factory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
        ConnectionFactory = factory.CreateConnectionFactory();
        ConnectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, ConfigSettings.Hostname);
        ConnectionFactory.SetIntProperty(XMSC.WMQ_PORT, ConfigSettings.Port);
        ConnectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, ConfigSettings.Channel);

        if (ConfigSettings.QueueManager == string.Empty)
        {
            ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, "");
        }
        else
        {
            ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, ConfigSettings.QueueManager);
        }

        connection = GetConnection();
    }

    public static IConnection GetConnection()
    {
        return ConnectionFactory.CreateConnection();
    }

    public static ISession GetSession(IConnection connection)
    {
        return connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
    }

    public static IMessageProducer GetProducer(ISession session, IDestination destination)
    {
        return session.CreateProducer(destination);
    }

    public static IMessageConsumer GetConsumer(ISession session, IDestination destination)
    {
        return session.CreateConsumer(destination);
    }

    public static void MQPub(string TopicURI, string message)
    {
        using (var session = GetSession(Connection))
        {
            using (var destination = session.CreateTopic(TopicURI))
            {
                using (var producer = GetProducer(session, destination))
                {
                    producer.Send(session.CreateTextMessage(message));
                }
            }
        }
    }

    public static void MQPub(string TopicURI, IEnumerable messages)
    {
        using (var session = GetSession(Connection))
        {
            using (var destination = session.CreateTopic(TopicURI))
            {
                using (var producer = GetProducer(session, destination))
                {
                    foreach (var message in messages)
                    {
                        producer.Send(session.CreateTextMessage(message));
                    }
                }
            }
        }
    }
}

Изменить: Переименованный класс MQAccess в MQClient. Сделал это экземпляром класса по предложению T Rob. Метод отсоединения все еще падает с сообщениями об ошибках, перечисленными выше

public class MQClient : IDisposable
{
    public MQConfigurationSectionHandler ConfigSettings { get; private set; }
    public IConnectionFactory ConnectionFactory { get; private set; }

    public IConnection Connection { get; private set;  }

    public IMessageConsumer Consumer { get; private set; }
    public IMessageProducer Producer { get; private set; }
    // Save sessions as fields for disposing and future subscription functionality
    private ISession ProducerSession;
    private ISession ConsumerSession;
    public string SubTopicName { get; private set; }
    public string PubTopicName { get; private set; }
    public bool IsConnected { get; private set; }
    public event Action ConnectionError;
    private Action IncomingMessageHandler;

    public MQClient(string subTopicName, string pubTopicName, Action incomingMessageHandler)
    {
        // Dont put connect logic in the constructor.  If we lose the connection we may need to connect again.
        SubTopicName = subTopicName;
        PubTopicName = pubTopicName;
        IncomingMessageHandler = incomingMessageHandler;
    }

    public string Connect()
    {
        IsConnected = false;
        string errorMsg = string.Empty;

        ConfigSettings = (MQConfigurationSectionHandler)
                ConfigurationManager.GetSection("mq-configuration");

        XMSFactoryFactory factory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
        ConnectionFactory = factory.CreateConnectionFactory();
        ConnectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, ConfigSettings.Hostname);
        ConnectionFactory.SetIntProperty(XMSC.WMQ_PORT, ConfigSettings.Port);
        ConnectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, ConfigSettings.Channel);

        if (ConfigSettings.QueueManager == string.Empty)
            ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, "");
        else
            ConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, ConfigSettings.QueueManager);

        Connection = ConnectionFactory.CreateConnection();


        if (!string.IsNullOrEmpty(PubTopicName))
        {
            ProducerSession = Connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
            Producer = ProducerSession.CreateProducer(ProducerSession.CreateTopic(PubTopicName));
        }

        if (!string.IsNullOrEmpty(SubTopicName) && IncomingMessageHandler != null)
        {
            ConsumerSession = Connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
            Consumer = ConsumerSession.CreateConsumer(ConsumerSession.CreateTopic(SubTopicName));
            Consumer.MessageListener = new MessageListener(IncomingMessageHandler);
        }

        try
        {
            Connection.Start();
            Connection.ExceptionListener = new ExceptionListener(ConnectionExceptionHandler);
            IsConnected = true;
        }
        catch (TypeInitializationException ex)
        {
            errorMsg = "A TypeInitializationException error occured while attempting to connect to MQ.  Check the Queue configuration in App.config. The error message is: " + ex.Message; 
        }
        catch (IllegalStateException ex)
        {
            errorMsg = "An IllegalStateException error occured while attempting to connect to MQ.  Check the Queue configuration in App.config. The error message is: " + ex.Message; 
        }

        return errorMsg;
    }

    public void Disconnect()
    {
        if (Producer != null)
        {
            Producer.Close();
            Producer.Dispose();
            Producer = null;
        }

        if (ProducerSession != null)
        {
            // Call Unsubscribe here if subscription is durable

            ProducerSession.Close();
            ProducerSession.Dispose();
            ProducerSession = null;
        }

        if (Connection != null)
        {
            Connection.Stop();

            //if (Connection.ExceptionListener != null)
            //    Connection.ExceptionListener = null;

            // Per Shashi............
            //if (Consumer.MessageListener != null)
            //    Consumer.MessageListener = null;

            Connection.Close();
            Connection.Dispose();
            Connection = null;
        }

        if (Consumer != null)
        {

            if (Consumer.MessageListener != null)
                Consumer.MessageListener = null;

            Consumer.Close();
            Consumer.Dispose();
            Consumer = null;
        }


        if (ConsumerSession != null)
        {
            // Call Unsubscribe here if subscription is durable
            ConsumerSession.Close();
            ConsumerSession.Dispose();
            ConsumerSession = null;
        }

        IsConnected = false;
    }


    public void Publish(string message)
    {
        Producer.Send(ProducerSession.CreateTextMessage(message));
    }


    public void Publish(string[] messages)
    {
        foreach (string msg in messages)
            Publish(msg);
    }

    public void ConnectionExceptionHandler(Exception ex)
    {
        Disconnect(); // Clean up

        if (ConnectionError != null)
            ConnectionError(ex);
    }

    #region IDisposable Members
    private bool disposed;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
                Disconnect();

            disposed = true;
        }
    }
    #endregion

}

Ответы на вопрос(2)

Добавление к комментариям от T.Rob.

Вопрос 1:

Я надеюсь, что у вас есть доступ к исходному кодуMQAccess, Если да, вы можете выставить недвижимость вMQAccess это указывает, является ли соединение активным или нет. Если у вас нет доступа, возможно, вам придется попросить автора этого класса добавить это свойство. Вы можете сделать следующее, чтобы установить / сбросить свойство.

1) Установите свойство послеCreateConnection метод возвращается успешно.

2) Установите прослушиватель Exception для соединения.

3) Сбросить свойство в обработчике исключений. Проверьте код причины и сбросьте свойство, если оноs ошибка разрыва соединения (XMSWMQ1107 и связанное исключение могут иметь MQRC 2009).

вопрос 2

Было бы полезно, если бы вы могли показать нам, как выclosing а такжеreopening соединения. Моя рекомендация закрыть соединение:

1) Сначала сделайте соединение. Stop ().

2) Удалите все прослушиватели сообщений, в основном сделайте consumer.MessageListener = null.

3) Затем сделайте соединение. Закрыть ().

4) сделать соединение = ноль

Дополнительная информация Вот образец, который я использовал для тестирования.

    private void OnException(Exception ex)
    {
        XMSException xmsex = (XMSException)ex;
        Console.WriteLine("Got exception");
        // Check the error code.
        if (xmsex.ErrorCode == "XMSWMQ1107")
        {
            Console.WriteLine("This is a connection broken error");
            stopProcessing = true; // This is a class member variable
        }
    }

В вашем методе, где создается соединение, установите прослушиватель исключений.

        // Create connection.
        connectionWMQ = cf.CreateConnection();
        connectionWMQ.ExceptionListener = new ExceptionListener(OnException);

Всякий раз, когда возникает ошибка соединения, слушатель исключения будет вызван, и флаг будет установлен в true.

Хорошей практикой является удаление объектов, когда они больше не нужны. Существует родительско-дочерние отношения, Consumer, Producer и т. Д. Являются дочерними объектами Session, который, в свою очередь, является дочерним объектом Connection. Так что порядок распоряжения может быть сначала дочерним, а затем родительским. Но если родитель избавляется, дети также удаляются автоматически.

 Sam27 окт. 2012 г., 01:26
Похоже, мой код такой же, как ваш. Я подключился и начал отправлять сообщения. Затем наш администратор прервал мой сеанс, но список исключений не сработал.
 Shashi24 мар. 2016 г., 11:24
Если вы не используете функцию автоматического переподключения клиента, вам необходимо заново создать каждый объект, созданный до разрыва соединения.
 Sam25 окт. 2012 г., 17:24
Спасибо, Шаши! Я надеюсь, что я не спрашиваю слишком много, но есть ли у вас пример кода, который иллюстрирует ваш ответ на вопрос 1? Поиск в Google для XMSWMQ1107 обнаруживает только этот пост!
 Sam26 окт. 2012 г., 00:01
Я реализовал ExceptionListener, однако он не обнаруживает разрыв соединения, и поэтому мой флаг IsConnected не устанавливается.
 Sam25 окт. 2012 г., 23:29
Нужно ли избавляться от продюсера, потребителя, сессий и слушателей? Смотрите этот пост:stackoverflow.com/questions/12508473/...  Какой правильный порядок для этого?
 Nawaz23 мар. 2016 г., 15:55
@ Шаши: Как только я обнаружу разорванное соединение, а затем снова подключу его, нужно ли мне снова создавать объекты сеанса, используя новое соединение? Или старые объекты сеанса продолжат работать (с новым подключением)? а как насчет прослушивателя сообщений / назначения / и т.д.? Нужно ли создавать их все снова?
 Sam29 окт. 2012 г., 17:06
Для завершения сеанса использовался обозреватель сервера (для каждого администратора MQ).
 Shashi27 окт. 2012 г., 07:01
Можете ли вы уточнить "админ прервал мой сеанс? Как это было сделано? Был ли остановлен канал SVRCONN со стороны администратора очередей или вы отключили сетевой кабель или завершили работу диспетчера очереди?
Решение Вопроса

Проблема здесь -> where MQAccess is a small utility class.

Первая часть вопроса спрашивает, как определить, активно ли соединение. Классы XMS для WebSphere MQ являются реализацией спецификации JMS для не-Java-платформ. Они довольно точно следуют спецификации JMS, а в спецификации JMS отсутствует метод соединения или сеанса, эквивалентныйisConnected следовательно, и XMS. Однако все действия GET и PUT должны происходить в блоке try / catch, чтобы перехватить исключения JMS. (Из которого тывсегда распечататьlinkedException, верно?) Когда выдается исключение JMS, приложение либо считает его фатальным и умирает, либо закрывает все объекты JMS, кроме фабрики соединений, ждет несколько секунд, а затем повторно запускает последовательность соединений.

ОБНОВЛЕНИЕ на основе новой информации в вопросе:

Спасибо за публикацию класса MQAccess. Это обеспечивает значительное понимание того, чтопроисходит, хотя до сих пор нетt любой код, показывающий, где соединение закрыто и вновь открыто в соответствии с частью # 2 вопроса.

Тем не менее, код показывает, чтоMQAccess класс создает частный экземплярICONNECTION connection как экземпляр класса построен, который затем публично выставляется какMQAccess.GetConnection,MQAccess Класс, опубликованный в настоящее время, не имеет метода открытого или закрытого класса, который когда-либо заменял бы дескриптор соединенияconnection так что еслиMQAccess.Connection.Close() когда-либо называется, чтоIConnection экземпляр объекта в пределахMQAccess класс будет всегда после удержания недопустимого дескриптора соединения. Как только соединение закрыто, этот экземплярMQAccess фактически мертв. Вы'пришлось бы удалить и восстановитьMQAccess чтобы получить новое соединение.

MQAccess класс публично выставляет фабрику соединений, так что теоретически можно было бы назватьMQAccess.GetConnection из-за пределов класса и получить действительный новыйIConnection объект, даже после закрытия исходного. Однако этот экземпляр будет существовать вне сферы действияMQAccess класс и, следовательно, любые последующие вызовыMQAccess будет ссылаться на его несуществующую переменную экземпляраconnection а не новый экземпляр соединения, созданный вне класса.

Если вам нужно закрыть и воссоздать соединения, вы можете рассмотреть возможность управления этим изнутриMQAccess, Низкотехнологичным подходом может быть написаниеMQAccess.Close() метод для соединения, которое закроет существующее соединение, затем немедленно вызоветconnection = GetConnection(); так что частныйconnection переменная всегда содержит действительный дескриптор соединения.

Если это неЧтобы решить проблему, пожалуйста, отправьте код, который закрывает и воссоздает соединения.

Кстати, нетранзакционный сеанс через сетевое соединение открывает возможность потерять или продублировать сообщения для любого провайдера JMS, включая WMQ. Это было то, что вы хотели? Я'я объяснил, почему это в другом посте SOВот.

 Sam25 окт. 2012 г., 17:19
Спасибо Т Роб, это действительно полезно. Вы правы - класс не должен запускать MQ в contstructor. Что вы подразумеваете под связным исключением?
 Sam25 окт. 2012 г., 18:35
О, неважно, я вижу, что connectedException является свойством IllegalStateException.
 Sam01 нояб. 2012 г., 21:06
Я отметил это как ответ на вопрос 2. Спасибо за вашу помощь!
 T.Rob25 окт. 2012 г., 18:07
Исключения JMS (и, следовательно, исключения XMS, поскольку они моделируют JMS) представляют собой многоуровневую структуру. В JMS верхний уровень содержит общие исключения типа "не удалось подключиться но последующий уровень содержит данные о конкретном поставщике, такие какQMgr не найден " или же "неправильное имя QMgr ", Если присутствует связанное исключение, оно, вероятно, содержит информацию, которая поможет с диагностикой. Посмотри пожалуйстаLinkedException

Ваш ответ на вопрос