Select 语句获取字节 [] 和字符串,但不获取 XML
Posted
技术标签:
【中文标题】Select 语句获取字节 [] 和字符串,但不获取 XML【英文标题】:Select Statement Gets byte[] and string but not XML 【发布时间】:2010-11-11 19:23:03 【问题描述】:在 C# 应用程序中,我使用以下语句从 SQL 服务代理队列中提取消息。
当尝试将 message_body 转换为 SqlBytes 和其他类型时,会引发异常。在运行时 message_body 似乎总是以 byte[] 类型开始。
将 message_body 保留为 byte[] 有效,但在尝试反序列化以键入 SccmAction 时,我收到一个异常,抱怨我的 XML 文档中存在错误。
我的最终目标是以任何形式将 message_body 反序列化到我的应用程序的接口中。
RECEIVE TOP (1)
conversation_handle as ConversationHandle
,message_body
,message_body as MessageBody
,convert(xml, message_body) as MessageBodyXml
FROM [dbo].[MY_QUEUE_SubmitQueue]
using (SqlConnection connection =
new SqlConnection(ConnectionString))
SqlCommand command = new SqlCommand(ReceiveString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
SqlBytes sb = (SqlBytes)reader["message_body"];
SccmAction sa = DeserializeObject<SccmAction>(sb);
IDelivery iD = DeserializeObject<IDelivery>(sb);
reader.Close();
public static T DeserializeObject<T>(byte[] ba)
XmlSerializer xs = new XmlSerializer(typeof(T));
MemoryStream memoryStream = new MemoryStream(ba);
XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
return (T)xs.Deserialize(memoryStream);
<SccmAction>
<MachineName>Godzilla</MachineName>
<CollectionName>cn324321</CollectionName>
<Action>Install</Action>
<EntryDateTime>Jul 17 2009 12:15PM</EntryDateTime>
</SccmAction>
编辑:附加信息
队列定义
CREATE MESSAGE TYPE [MY_MSG_MessageType] AUTHORIZATION
[dbo] VALIDATION = WELL_FORMED_XML
CREATE CONTRACT [MY_CONTRACT_Contract] AUTHORIZATION [dbo]
([MY_MSG_MessageType] SENT BY INITIATOR)
CREATE QUEUE [dbo].[MY_QUEUE_SubmitQueue] WITH STATUS = ON ,
RETENTION = OFF ON [PRIMARY]
CREATE QUEUE [dbo].[MY_QUEUE_ResponseQueue] WITH STATUS = ON ,
RETENTION = OFF ON [PRIMARY]
CREATE SERVICE [MY_QUEUE_SubmitService] AUTHORIZATION [dbo]
ON QUEUE [dbo].MY_QUEUE_SubmitQueue([MY_CONTRACT_Contract])
CREATE SERVICE [MY_QUEUE_ResponseService] AUTHORIZATION [dbo] ON
QUEUE [dbo].[MY_QUEUE_ResponseQueue]([DEFAULT])
例外情况
Type of value has a mismatch with column type Couldn't store <<SccmAction> <MachineName>Godzilla</MachineName><CollectionName>cn324321</CollectionName> <Action>Install</Action> <EntryDateTime>Jul 17 2009 12:15PM</EntryDateTime> </SccmAction>> in MessageBodyXml Column. Expected type is SqlXml.
无法转换类型的对象 'System.Byte[]' 输入 'System.Data.SqlTypes.SqlBytes'。
“XML 文档中存在错误 (1, 165)。”
消息被放置在队列中
'<?xml version="1.0" encoding="utf-8"?>
<SccmAction>
<MachineName>' + @machine_name + '</MachineName>
<CollectionName>' + @collection_name + '</CollectionName>
<Action>' + @action + '</Action>
<EntryDateTime>' + CAST(getdate() AS VARCHAR(100)) + '</EntryDateTime>
</SccmAction>'
我想反序列化到的最终对象
public class SccmAction : IDelivery
public string MachineName get; set;
public string CollectionName get; set;
public string Action get; set;
public DateTime EntryDateTime get; set;
public void Deliver()
throw new NotImplementedException();
public interface IDelivery
void Deliver();
【问题讨论】:
你能发布队列的定义吗?另外,异常到底发生在哪里?请发布完整的异常(ex.ToString() 的输出)。 @JohnSaunders 队列的定义是什么意思? [dbo].[MY_QUEUE_SubmitQueue]的定义 现在我很困惑。如果你知道 message_body 是 byte[],那为什么不把它读成 byte[] 呢? @JohnSaunders 添加了您请求的队列定义。我试图按照 Remus 的建议将其解读为 SqlBytes。 【参考方案1】:Don't cast the VARBINARY(MAX) message_body to XML in the RECEIVE statement itself。这是一个不好的做法,因为如果在 CAST 期间发生 XML 验证异常,它可以欺骗 Service Broker 相信 RECEIVE 从未发生过。详情见链接。
我建议您在投影列表中将该列保留为 VARBINARY(MAX)(即 RECEIVE ...,message_body FROM ...),并在您的 C# 客户端中将该列作为 SqlBytes 使用,而不是作为 byte[] .然后,您可以利用SqlBytes.Stream 在此流之上构造一个 XmlReader。或者您可以直接读入 XmlDocument。
不要使用带有 RECEIVE 的强类型数据表,它与 Visual Studio 构建器所期望的表语义不匹配,并且会给自己带来不必要的痛苦。使用 SqlDataReader。
更新
不要从字符串补丁手动构建发送的 XML。使用 SQL Server 本身通过 FOR XML 子句(通常使用 PATH)构建 XML,并将结果分配给您发送的 XML 变量:
declare @machine_name sysname
, @collection_name sysname
, @action sysname;
select @machine_name = 'Ice Cream'
, @collection_name = 'Baseball Cards'
, @action = 'open';
declare @x xml;
select @x = (
select @machine_name as MachineName
, @collection_name as CollectionName
, @action as Action
, getdate() as EntryDateTime
for xml path('SccmAction'), type);
send on conversation @h message type [MyMessageType] (@x);
您不必担心 XML 日期格式、UTF 编码或任何类似的东西。
【讨论】:
转换仍有问题,请参阅上面已编辑的问题。 顺便说一句,如果不先检查 message_type_name,就无法像那样反序列化消息正文。您总是会收到一条错误消息,并且不会是您在反序列化中期望的 XML 模式...【参考方案2】:我坚持使用 byte[],因为 SqlBytes 似乎不起作用。
最后,将 XML 反序列化为对象的问题与 EntryDateTime 中的值不是 ISO 8601 格式有关。通过进行转换,我能够以适当的格式获取日期。
select CONVERT(varchar(30), GETDATE(), 126)
【讨论】:
以上是关于Select 语句获取字节 [] 和字符串,但不获取 XML的主要内容,如果未能解决你的问题,请参考以下文章