0

我正在我的 .Net 代码中连接到 IBM Websphere MQ 服务器,并且我想确保在使用“finally”时遵循最佳实践。

我目前有以下代码块,我相信可以将其修改为仅在 finally 子句中包含关闭部分。那是对的吗?(我在应用程序的调用部分发现错误)。

    Hashtable properties = new Hashtable();
    properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_CLIENT);
    properties.Add(MQC.CHANNEL_PROPERTY, channel);
    properties.Add(MQC.HOST_NAME_PROPERTY, host);
    properties.Add(MQC.PORT_PROPERTY, port);

    MQQueueManager qmgr = new MQQueueManager(queueManager, properties);

    try
    {
        var queueDepth = qmgr.AccessQueue(userQueue,
                                          MQC.MQOO_INPUT_AS_Q_DEF +
                                          MQC.MQOO_FAIL_IF_QUIESCING +
                                          MQC.MQOO_INQUIRE).CurrentDepth;
        if (qmgr.IsOpen)
            qmgr.Close();

        return queueDepth;
    }
    finally
    {
        if (qmgr.IsOpen)
            qmgr.Close();
    }

现在是这个

    Hashtable properties = new Hashtable();
    properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_CLIENT);
    properties.Add(MQC.CHANNEL_PROPERTY, channel);
    properties.Add(MQC.HOST_NAME_PROPERTY, host);
    properties.Add(MQC.PORT_PROPERTY, port);

    MQQueueManager qmgr = new MQQueueManager(queueManager, properties);

    try
    {
        var queueDepth = qmgr.AccessQueue(userQueue,
                                          MQC.MQOO_INPUT_AS_Q_DEF +
                                          MQC.MQOO_FAIL_IF_QUIESCING +
                                          MQC.MQOO_INQUIRE).CurrentDepth;

        return queueDepth;
    }
    finally
    {
        if (qmgr.IsOpen)
            qmgr.Close();
    }

编辑: Renan 提出了一个很好的建议。我不认为 MQQueueManger 是一次性的。听起来我可能会这样做:

        using(MQQueueManager qmgr = new MQQueueManager(queueManager, properties))
    {
        var queueDepth = qmgr.AccessQueue(userQueue,
                              MQC.MQOO_INPUT_AS_Q_DEF +
                              MQC.MQOO_FAIL_IF_QUIESCING +
                              MQC.MQOO_INQUIRE).CurrentDepth;

        return queueDepth;
    }

编辑:在阅读了 Renan 的建议后,我做了一些研究,发现了以下内容。听起来他们确实把它变成了一次性的。

MQ.Net

4

3 回答 3

4

你说的对。即使 try 块中的代码返回异常,finally 子句也会执行。

您还可以对连接使用“使用”构造(如果它实现了 IDisposable,它应该实现)。

using(qmgr){
    //do stuff
}
于 2013-09-12T22:33:28.257 回答
2

没事儿。

块由finallyCLR 保证被调用(除了在一些非常罕见的边缘情况下,IIRC 是内部 CLR 错误,例如调用FailFast或调用ExecutingEngineException)。通过从 中删除它try,您正在删除冗余代码。

于 2013-09-12T22:31:16.533 回答
2

首先,应用程序需要知道队列的深度是没有正当理由的。应用程序应该处理队列中的所有消息,直到它为空。

其次,不要使用 IsOpen 方法,因为它们不会像您预期的那样工作。IsOpen 方法实际上并不检查队列句柄是否打开 - 它只检查内部标志。因此,请勿使用它。

第三,您不关闭队列管理器对象,而是断开与队列管理器的连接。

第四,当连接到队列管理器时,该语句需要在 try/catch 中,因为如果连接失败,它将抛出 MQException。

这是一个更好的代码布局,可以捕获和处理错误:

MQQueueManager qMgr = null;
MQQueue queue = null;
int openOptions = MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING + MQC.MQOO_INQUIRE;

try
{
   qMgr = new MQQueueManager(qMgrName);
   System.Console.Out.WriteLine("Successfully connected to " + qMgrName);

   queue = qMgr.AccessQueue(qName, openOptions, null, null, null);
   System.Console.Out.WriteLine("Successfully opened " + qName);

   System.Console.Out.WriteLine("Current queue depth is " + queue.CurrentDepth);
}
catch (MQException mqex)
{
   System.Console.Out.WriteLine("Exception CC=" + mqex.CompletionCode + " : RC=" + mqex.ReasonCode);
}
catch (System.IO.IOException ioex)
{
   System.Console.Out.WriteLine("Exception ioex=" + ioex);
}
finally
{
   try
   {
      if (queue !=null)
      {
         queue.Close();
         System.Console.Out.WriteLine("Successfully closed " + qName);
      }

   }
   catch (MQException mqex)
   {
      System.Console.Out.WriteLine("Exception on close CC=" + mqex.CompletionCode + " : RC=" + mqex.ReasonCode);
   }
   try
   {
      if (qMgr !=null)
      {
         qMgr.Disconnect();
         System.Console.Out.WriteLine("Disconnected from " + qMgrName);
      }
   }
   catch (MQException mqex)
   {
      System.Console.Out.WriteLine("Exception on disconnect CC=" + mqex.CompletionCode + " : RC=" + mqex.ReasonCode);
   }
}
于 2013-09-13T16:26:56.610 回答