SQL Service Broker消息中的汉字

ahs*_*ele 1 t-sql sql-server service-broker

我在数据库中设置了多个SQL Service Broker队列,但之前没有看到过这个问题.包含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>
Run Code Online (Sandbox Code Playgroud)
?????????•??†††?????
?†††??????????????????????????
?†††??????????????????????
 ††††????????????
 ?††††?????????†‹??†????????????
†††?????
Run Code Online (Sandbox Code Playgroud)

下面是我用来将消息放入队列并选择它的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;
Run Code Online (Sandbox Code Playgroud)

Rem*_*anu 7

好的,这个答案不是主题,但我必须:请不要做火,忘记与服务经纪人.begin-send-end消息模式存在许多问题,从无法解决对数据库的故障响应到脱机.后者是由于SSB(SQL Service Broker)中的一个错误,但我发现它发生了,它是由fire和forget消息模式引起的.

哦,还有一件事:我不知道DBArtisan是什么,但它认为你的ASCII消息是有效的,那么它意味着它将message_body列转换为varchar(max),这就是全部.

既然我的帖子已经很大了,那么我也要深入研究一下XML编码和SSB.正如你可能知道,SSB如果你声明的消息类型提供了XML消息验证[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"?>ñ<?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枚举值.

同样在队列的接收端(您的激活过程或读取目标队列的进程),您应该将消息体转换为XML类型,而不是varchar/nvarchar.当我们讨论这个问题时,请确保接收期间进行强制转换,但仅在接收之后,因为XML 错误处理与激活交互的方式.


Joh*_*ers 5

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