1

我在数据库中设置了多个 SQL Service Broker 队列,但之前没有遇到过这个问题。包含 XML 的消息正在转换为似乎主要是中文字符的内容。当我在将 XML 放入消息队列之前检查存储 XML 的变量时,我可以看到它是英文的并且是良好的 XML 格式。当我从队列中选择时,我会收到汉字。当我使用外部 C# 应用程序从队列中拉出时,这些字符也是我收到的。奇怪的是,如果我使用 DBArtisan 查看队列,我会看到格式良好的 XML。

下面的 XML 放入队列时会转换为下面的汉字

<?xml version="1.0" ?>
<Message>
  <MachineName>The Super Duper Machine</MachineName>
  <CollectionName>snl0013d</CollectionName>
  <Action>Install</Action>
  <EntryDateTime>Jul  9 2009  4:47PM</EntryDateTime>
</Message>

㼼浸敶獲潩㵮ㄢ〮•㸿਍†††䴼獥慳敧ാ
 †††㰠慍档湩乥浡㹥桔⁥畓数⁲畄数⁲慍档湩㱥䴯捡楨敮慎敭ാ
 †††㰠潃汬捥楴湯慎敭猾汮〰㌱㱤䌯汯敬瑣潩乮浡㹥਍
 ††††䄼瑣潩㹮湉瑳污㱬䄯瑣潩㹮
 ਍††††䔼瑮祲慄整楔敭䨾汵†‹〲㤰†㨵〱䵐⼼湅牴䑹瑡呥浩㹥਍
†††⼼敍獳条㹥

下面是我用来将消息放入队列并选择它的 T-SQL。

declare @dialog_handle uniqueidentifier
       ,@msg varchar(max)
       ,@collection_name varchar(30)

set @collection_name = 'snl0013d'

set @msg =
N'<?xml version="1.0" ?>
  <Message>
    <MachineName>' + 'The Super Duper Machine' + '</MachineName>
    <CollectionName>' + @collection_name + '</CollectionName>
    <Action>' + 'Install' + '</Action>
    <EntryDateTime>' + CAST(getdate() AS VARCHAR(100)) + '</EntryDateTime>
  </Message>'

select @msg

set @dialog_handle = NEWID()
begin dialog conversation @dialog_handle
    from service [SAPP_QUEUE_ResponseService]
    to service 'SAPP_QUEUE_SubmitService'
    on contract [SAPP_CONTRACT_Contract]
    with encryption = off;

send on conversation @dialog_handle
  message type [SAPP_MSG_MessageType]
(
    @msg
);
end conversation @dialog_handle 
with cleanup

select message_body
      ,conversation_handle
      ,CONVERT(nvarchar(max), message_body) as msg
  from SAPP_QUEUE_SubmitQueue;
4

2 回答 2

7

好的,这个答案是题外话,但我必须:请不要与服务经纪人发生火灾并忘记。begin-send-end 消息模式有很多问题,从无法解决错误响应到您的数据库脱机。后者是由于 SSB(SQL 服务代理)中的一个错误,但我已经看到它发生了,它是由火灾和忘记消息模式引起的。

哦,还有一件事:我不知道 DBArtisan 是什么,但它认为您的 ASCII 消息是有效的,这意味着它将 message_body 列转换为 varchar(max),仅此而已。

由于我的帖子已经很大了,让我再深入研究一下 XML 编码和 SSB。您可能知道,如果您将消息类型声明[SAPP_MSG_MessageType]VALIDATION = WELL_FORMED_XML. 但是 ASCII 和 UNICODE 都是有效的 XML 编码,并且都受 SSB 支持。您可以发送一条消息N'<someTag>somecontent</someTag>''<someTag>somecontent</someTag>',它们都是有效的 XML 片段。您还可以添加显式 XML 处理指令来声明编码,例如<?xml version="1.0" encoding="utf-8"?>N<?xml version="1.0" encoding="utf-16"?>。但是,您将面临不匹配它们的风险,例如声明N<?xml version="1.0" encoding="utf-8"?>,这实际上是无效的 XML(因为声明的编码与文档编码不匹配)。您可能会遇到各种非常微妙且难以解决的问题。这是一个完美的问题示例,它可能导致目标服务拒绝消息并使用 XML 验证响应使对话框失败,您将错过该问题,因为...您正在执行即发即弃 :)

在我的实践中(我是 MS 的 SQL Service Broekr 团队的成员之一),我发现避免任何麻烦的最佳方法是将保存已发送 (@msg) 的变量声明为 xml 类型,而不是 varchar 或 nvarchar这可以解决所有问题,还可以正确解决XML 中 BOM的需要和存在。这也适用于传入的 C# 参数,最佳匹配是使用SqlXml类型和/或System.Data.SqlDbType.Xml枚举值。

Also on the receive side of the queue (your activated procedure or process that reads the target queue) your should cast the message body to XML type, not to varchar/nvarchar. And while we're on the subject, make sure you don't cast during the receive, but only after the receive because of the way XML error handling interacts with activation.

于 2009-07-09T23:48:11.667 回答
5

我不知道是不是这样,但我看到你使用 nvarchar 文字但分配给 varchar 变量......

于 2009-07-09T23:20:46.573 回答