Select Statement获取byte []和字符串,但不获取XML

时间:2009-07-17 18:19:30

标签: c# sql sql-server xml xml-serialization

在C#app中,我使用以下语句从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();
}

2 个答案:

答案 0 :(得分:1)

d on't cast the VARBINARY(MAX) message_body to XML in the RECEIVE statement itself。这是一个不好的做法,因为它可以诱使Service Broker相信如果在CAST期间发生XML验证异常,RECEIVE从未发生过。有关详细信息,请参阅链接。

我建议您将列保留为投影列表中的VARBINARY(MAX)(即RECEIVE ...,message_body FROM ...),并在C#客户端中将列作为SqlBytes使用,而不是作为byte [] 。然后,您可以利用SqlBytes.Stream在此流的顶部构建XmlReader。或者您可以直接阅读XmlDocument。

不要将强类型DataTable与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编码或其他任何内容。

答案 1 :(得分:0)

我坚持使用byte [],因为SqlBytes似乎不起作用。

最后,将XML反序列化为对象的问题与EntryDateTime中的值不是ISO 8601格式有关。通过转换,我能够以适当的格式获取日期。

select CONVERT(varchar(30), GETDATE(), 126)