【问题标题】:Missing conversation handle in Service BrokerService Broker 中缺少对话句柄
【发布时间】:2018-12-28 11:14:42
【问题描述】:

我正在使用以下命令在 Service Broker (SQL 2016) 上为我的队列创建对话:

BEGIN TRANSACTION

BEGIN DIALOG CONVERSATION @NotificationDialog 
FROM SERVICE ChangeNotifications 
TO SERVICE 'ChangeNotifications' 
ON CONTRACT [http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification] 
WITH ENCRYPTION = OFF; 

-- Send the message 
-- 
SEND ON CONVERSATION @NotificationDialog  
MESSAGE TYPE [http://schemas.microsoft.com/SQL/Notifications/QueryNotification] (@Message)      

COMMIT TRANSACTION

我正在使用以下代码在 Windows 服务中接收消息:

using (SqlCommand cmd = new SqlCommand("WAITFOR ( RECEIVE * FROM dbo.NotificationsQueue);", cnn))
{
    cmd.CommandTimeout = 0;
    cnn.Open();

    // Execute the command - we will wait here until a new entry appears in the Notification Queue
    //
    SqlDataReader reader = cmd.ExecuteReader();

    // Get the message text from the reader
    //
    while (reader.Read())
    {
        // Get the message body text and convert into a legible format
        //
        messageText = reader.GetString(reader.GetOrdinal("message_body"));
        messtype = reader.GetString(reader.GetOrdinal("message_type_name"));
        convhandle = reader.GetGuid(reader.GetOrdinal("conversation_handle"));
    }

    reader.Close();
    reader = null;

    if (messtype == @"http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog" ||
        messtype == @"http://schemas.microsoft.com/SQL/ServiceBroker/Error" ||
        messtype == @"http://schemas.microsoft.com/SQL/Notifications/QueryNotification" )
    {
        var cmd2 = new SqlCommand("end conversation '" + convhandle.ToString() + "'", cnn);

        cmd2.ExecuteNonQuery();

        cmd2.Dispose();
    }
}

当代码尝试执行结束对话时,我收到错误消息“找不到对话句柄。”。如果我在 sys.conversation_endpoints 中搜索句柄,它也不存在。我不会在任何地方主动结束谈话。 为什么没有记录?

【问题讨论】:

  • 您是否正在运行存储过程?使用如下:cmd2.CommandType = System.Data.CommandType.StoredProcedure;
  • @jdweng,代码显然没有执行存储过程。
  • 我在您发布的代码中看不到任何明显会导致此错误的内容,尽管我建议参数化 END CONVERSATION 查询并像外部查询一样将其包围在 using 块中。跨度>

标签: c# sql-server-2016 service-broker


【解决方案1】:

经过一番折腾后,我找到了解决问题的方法。首先,sql 端需要一个结束对话:

BEGIN TRANSACTION

BEGIN DIALOG CONVERSATION @NotificationDialog 
FROM SERVICE ChangeNotifications 
TO SERVICE 'ChangeNotifications' 
ON CONTRACT [http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification] 
WITH ENCRYPTION = OFF; 

-- Send the message 
-- 
SEND ON CONVERSATION @NotificationDialog  
MESSAGE TYPE [http://schemas.microsoft.com/SQL/Notifications/QueryNotification] (@Message)      

-- ** Was missing from original code **
--
END CONVERSATION @NotificationDialog;   

COMMIT TRANSACTION

然后我需要修改接收代码以处理当我调用结束对话时在队列中收到额外的结束对话消息的事实:

using (SqlConnection cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["MetricBroadcast.Properties.Settings.TargetConnectionString"].ToString()))
{
    string messtype = "";
    Guid convhandle = new Guid();

    cnn.Open();
    trans = cnn.BeginTransaction("queuetrans");

    // Create the command to monitor the Notifications Queue
    //
    using (SqlCommand cmd = new SqlCommand("WAITFOR ( RECEIVE * FROM dbo.NotificationsQueue);", cnn, trans))
    {
        cmd.CommandTimeout = 0;

        // Execute the command - we will wait here until a new entry appears in the Notification Queue
        //
        SqlDataReader reader = cmd.ExecuteReader();

        // Get the message text from the reader
        //
        while (reader.Read())
        {
            // Get the message body text and convert into a legible format
            //
            messtype = reader.GetString(reader.GetOrdinal("message_type_name"));
            convhandle = reader.GetGuid(reader.GetOrdinal("conversation_handle"));

            if (messtype == @"http://schemas.microsoft.com/SQL/Notifications/QueryNotification")
            {
                messageText = System.Text.UTF8Encoding.Unicode.GetString(reader.GetSqlBinary(reader.GetOrdinal("message_body")).Value);
            }
        }

        reader.Close();
        reader = null;


        if (messtype == @"http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog" ||
            messtype == @"http://schemas.microsoft.com/SQL/ServiceBroker/Error")
        {
            var cmd2 = new SqlCommand("end conversation '" + convhandle.ToString() + "'", cnn, trans);

            cmd2.ExecuteNonQuery();

            cmd2.Dispose();
        }

        trans.Commit();
    }
}

现在它运行良好,我可能会按照 Dan Guzman 的建议进行操作,并将结束对话查询参数化,并将其包围在 using 查询中。

希望这可以帮助其他遇到问题的人。

罗伯

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    • 2010-11-21
    • 2014-11-14
    • 1970-01-01
    • 2012-08-01
    • 2011-02-18
    • 1970-01-01
    相关资源
    最近更新 更多