我在数据库中设置了多个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>
㼼浸敶獲潩㵮ㄢ〮•㸿†††䴼獥慳敧ാ
†††㰠慍档湩乥浡㹥桔畓数畄数慍档湩㱥䴯捡楨敮慎敭ാ
†††㰠潃汬捥楴湯慎敭猾汮〰㌱㱤䌯汯敬瑣潩乮浡㹥
††††䄼瑣潩㹮湉瑳污㱬䄯瑣潩㹮
††††䔼瑮祲慄整楔敭䨾汵†‹〲㤰†㨵〱䵐⼼湅牴䑹瑡呥浩㹥
†††⼼敍獳条㹥
下面是我用来将消息放入队列并选择它的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;
答案 0 :(得分:7)
好的,这个答案不是主题,但我必须:请不要与服务经纪人做fire and forget。 begin-send-end消息模式存在许多问题,从无法解决对数据库的故障响应到脱机。后者是由于SSB(SQL Service Broker)中的一个错误,但我看到它发生了,它是由fire和forget消息模式引起的。
哦,还有一件事:我不知道DBArtisan是什么,但它认为你的ASCII消息是有效的,那么它意味着它将message_body列转换为varchar(max),这就是全部。
既然我的帖子已经很大了,那么我还要深入研究一下XML编码和SSB。您可能知道,如果您将消息类型[SAPP_MSG_MessageType]
声明为VALIDATION = WELL_FORMED_XML
,则SSB会提供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验证响应使对话失败,您将会错过这个响应,因为......您正在做“即发即弃”:) / p>
在我的实践中(我是MS的SQL Service Broekr团队的成员之一)我发现避免任何麻烦的最好方法是将包含sent(@ msg)的变量声明为类型xml ,不是varchar也不是nvarchar 。这样可以解决所有问题,并正确解决BOM in your XML的需要和存在问题。这也适用于传入的C#参数,最佳匹配是使用SqlXml类型和/或System.Data.SqlDbType.Xml枚举值。
同样在队列的接收端(您的激活过程或读取目标队列的进程),您应该将消息体转换为XML类型,而不是varchar / nvarchar。当我们讨论这个主题时,请确保在接收期间不要强制,但只有在接收之后才会因为XML error handling interacts with activation的方式而投射。
答案 1 :(得分:5)
我不知道是不是这样,但我看到你使用nvarchar文字而是分配给varchar变量......