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)
好的,这个答案不是主题,但我必须:请不要做火,忘记与服务经纪人.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 错误处理与激活交互的方式.