Service Broker中缺少对话句柄

时间:2018-12-28 11:14:42

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

我正在使用以下方法在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中搜索该句柄,则它也不存在。我没有在任何地方积极结束对话。 为什么没有记录?

1 个答案:

答案 0 :(得分:0)

经过一番忙碌之后,我找到了解决问题的方法。首先,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查询中。

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

Rob