2012-10-18 33 views
8

1.) Từ máy khách .net, làm cách nào để kiểm tra xem máy khách có được kết nối với máy chủ hay không. có thể gửi một tin nhắn bên trong một khối thử và bắt ngoại lệ tiếp theo nhưng tôi hy vọng cho một giải pháp thanh lịch hơn.Làm cách nào để nhận trạng thái kết nối Websphere MQ và cách đặt lại kết nối:

2) Làm cách nào để mở, đóng và mở lại kết nối? Trong nỗ lực của tôi để giải quyết câu hỏi 1 ở trên tôi phát hiện ra rằng nếu tôi mở một kết nối sau đó gọi connection.Close() Tôi không thể có được kết nối khác từ nhà máy kết nối (xem đoạn mã dưới đây). Tôi nhận được thông báo lỗi XMSCC0008

Tôi đang sử dụng cấu hình vanilla MQ rất chuẩn. Đây là cách khách hàng của tôi kết nối:

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

nơi MQAccess là một lớp tiện ích nhỏ.

Edited các câu hỏi để thêm mã 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<string> 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)); 
        } 
       } 
      } 
     } 
    } 
} 

Edit: đổi tên lớp MQAccess để MQClient. Làm cho nó một lớp thể hiện cho mỗi đề xuất T Rob. phương pháp Disconnect vẫn bị treo với thông điệp lỗi được liệt kê ở trên

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<Exception> ConnectionError; 
    private Action<IMessage> IncomingMessageHandler; 

    public MQClient(string subTopicName, string pubTopicName, Action<IMessage> 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 

} 

Trả lời

8

Vấn đề là ở đây ->where MQAccess is a small utility class.

Phần đầu của câu hỏi hỏi làm thế nào để nói nếu kết nối được kích hoạt. Các lớp XMS cho WebSphere MQ là việc triển khai đặc tả JMS cho các nền tảng không phải Java. Chúng tuân theo đặc tả JMS khá chặt chẽ và đặc tả JMS không có phương thức trên kết nối hoặc phiên tương đương với isConnected do đó không XMS. Tuy nhiên, tất cả hoạt động GET và PUT sẽ xảy ra trong một khối try/catch để nắm bắt các ngoại lệ của JMS. (Khi bạn luôn luôn in linkedException, phải không?) Khi ngoại lệ JMS được ném ứng dụng hoặc xử lý nó như là chết người hoặc chết hoặc người nào khác nó đóng tất cả các đối tượng JMS ngoại trừ Nhà máy kết nối, chờ một vài giây và sau đó lại điều khiển chuỗi kết nối.

CẬP NHẬT dựa trên thông tin mới trong câu hỏi:
Cảm ơn bạn đã đăng lớp MQAccess. Điều này cung cấp cái nhìn sâu sắc đáng kể vào những gì đang xảy ra, mặc dù vẫn không có bất kỳ mã nào hiển thị nơi kết nối được đóng và mở lại theo Phần # 2 của câu hỏi.

Tuy nhiên, mã cho thấy lớp MQAccess tạo cá thể riêng là ICONNECTION connection khi phiên bản lớp được xây dựng, sau đó được hiển thị công khai là MQAccess.GetConnection. Lớp MQAccess như hiện được đăng không có phương thức lớp công khai hoặc riêng tư nào có thể thay thế tay cầm kết nối được giữ bởi connection vì vậy nếu MQAccess.Connection.Close() được gọi là IConnection đối tượng trong lớp MQAccess sẽ mãi mãi sau khi giữ tay cầm kết nối không hợp lệ. Một khi kết nối được đóng lại, trường hợp của MQAccess là có hiệu quả chết. Bạn sẽ phải xóa và khôi phục MQAccess để nhận kết nối mới.

Lớp MQAccess không hiển thị nhà máy kết nối công khai, theo lý thuyết, có thể gọi MQAccess.GetConnection từ bên ngoài lớp và nhận đối tượng IConnection hợp lệ mới, ngay cả sau khi đóng đối tượng gốc.Tuy nhiên, trường hợp đó sẽ tồn tại bên ngoài phạm vi của lớp MQAccess và do đó bất kỳ cuộc gọi tiếp theo nào đến MQAccess sẽ tham chiếu đến biến phiên bản không còn tồn tại connection thay vì trường hợp kết nối mới được tạo bên ngoài lớp.

Nếu bạn cần đóng và tạo lại kết nối, bạn có thể cân nhắc quản lý kết nối từ bên trong MQAccess. Cách tiếp cận công nghệ thấp có thể là viết phương thức MQAccess.Close() cho kết nối sẽ đóng kết nối hiện tại rồi gọi ngay connection = GetConnection(); sao cho biến số connection riêng tư luôn giữ một kết nối hợp lệ.

Nếu cách này không giải quyết được sự cố, vui lòng đăng mã đang đóng và tạo lại kết nối. Bằng cách này, phiên giao dịch không giao dịch qua kết nối mạng sẽ mở ra khả năng mất hoặc sao chép tin nhắn cho bất kỳ nhà cung cấp JMS nào, bao gồm cả WMQ. Đây có phải là những gì bạn dự định không? Tôi đã giải thích tại sao điều này nằm trong một bài đăng SO khác here.

+0

Cảm ơn bạn T Rob điều này thực sự hữu ích.Bạn là đúng - lớp không nên bắt đầu MQ trong contstructor. Bạn có ý nghĩa gì bởi linkedException? – Sam

+0

Ngoại lệ JMS (và do đó ngoại lệ XMS vì chúng mô hình hóa JMS) là cấu trúc đa cấp. Trong JMS, cấp cao nhất chứa các ngoại lệ chung như "không kết nối" nhưng cấp tiếp theo chứa dữ liệu của nhà cung cấp cụ thể như "Không tìm thấy QMgr" hoặc "tên QMgr sai". Nếu có ngoại lệ được liên kết, có thể có thông tin sẽ giúp chẩn đoán. Vui lòng xem ['LinkedException'] (http://pic.dhe.ibm.com/infocenter/wmqv7/v7r5/topic/com.ibm.mq.msc.doc/sapiexcpt.html#sapiexcpt_getlkex) –

+0

Oh không sao tôi thấy rằng linkedException là một thuộc tính của IllegalStateException. – Sam

5

Thêm vào nhận xét từ T.Rob.

Câu hỏi 1:
Tôi hy vọng bạn có quyền truy cập vào mã nguồn của MQAccess. Nếu có, bạn có thể phơi bày một thuộc tính trong MQAccess cho biết kết nối có đang hoạt động hay không. Nếu bạn không có quyền truy cập thì bạn có thể phải yêu cầu tác giả của lớp đó thêm thuộc tính này. Bạn có thể thực hiện các bước sau để đặt/đặt lại thuộc tính.

1) Đặt thuộc tính sau phương thức createConnection trả về thành công.
2) Đặt trình nghe ngoại lệ cho kết nối.
3) Đặt lại thuộc tính trong Trình xử lý ngoại lệ. Kiểm tra mã lý do và đặt lại thuộc tính nếu đó là lỗi kết nối bị hỏng (XMSWMQ1107 và ngoại lệ được liên kết có thể có MQRC 2009).

Câu hỏi 2
Sẽ hữu ích nếu bạn có thể chỉ cho chúng tôi cách bạn đang thực hiện các kết nối closingreopening. Đề nghị đóng kết nối của tôi là:
1) Đầu tiên hãy thực hiện kết nối.Stop().
2) Xóa bất kỳ trình nghe tin nhắn nào, về cơ bản thực hiện consumer.MessageListener = null.
3) Sau đó thực hiện connection.Close().
4) Thực hiện kết nối = null

Thông tin bổ sung Đây là mẫu tôi đã sử dụng để kiểm tra.

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 
     } 
    } 

Trong phương thức tạo kết nối, hãy đặt trình xử lý ngoại lệ.

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

Bất cứ khi nào có lỗi kết nối, trình nghe ngoại lệ sẽ được gọi và cờ được đặt thành true.

Thực hành tốt khi vứt bỏ đồ vật khi không còn cần thiết nữa. Có mối quan hệ cha mẹ con, người tiêu dùng, nhà sản xuất vv là con của phiên mà lần lượt là một đứa trẻ của kết nối. Vì vậy, thứ tự xử lý có thể là con đầu tiên và cha mẹ tiếp theo. Nhưng nếu một phụ huynh được xử lý, trẻ em cũng được xử lý tự động.

+0

Cảm ơn Shashi! Tôi hy vọng tôi không hỏi quá nhiều, nhưng bạn có bất kỳ mã ví dụ nào cho thấy bạn trả lời cho câu hỏi 1 không? Tìm kiếm trên Google cho XMSWMQ1107 chỉ xuất hiện bài đăng này! – Sam

+0

Có cần phải vứt bỏ Nhà sản xuất, Người tiêu dùng, Phiên và người nghe không? Xem bài đăng này: http://stackoverflow.com/questions/12508473/ibm-mq-xms-subscription-not-closing Thứ tự chính xác để làm điều này là gì? – Sam

+0

Tôi đã triển khai ExceptionListener tuy nhiên nó không phát hiện khi kết nối bị hỏng và do đó cờ IsConnected của tôi không được đặt. – Sam