2009-07-17 68 views
2

在C#應用程序中,我使用下面的語句從SQL服務代理隊列中取出消息。選擇語句獲取字節[]和字符串,但不是XML

當試圖將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(); 
} 
+0

你可以發佈隊列的定義嗎?另外,發生異常的確切位置在哪裏?請發佈完整的異常(ex.ToString()的輸出)。 – 2009-07-17 18:22:44

+0

@JohnSaunders你是什麼意思的隊列的定義? – ahsteele 2009-07-17 18:34:12

回答

0

由於SqlBytes似乎沒有工作,所以我堅持使用byte []。

最後,將XML反序列化爲對象的問題與EntryDateTime中的值不是ISO 8601格式有關。通過進行轉換,我能夠以適當的格式獲取日期。

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

d on'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使用,而不是字節[ ]。然後,您可以利用SqlBytes.Stream在此流的頂部構建一個XmlReader。或者你可以直接讀入一個XmlDocument。

不要將強類型的DataTable與RECEIVE一起使用,它與Visual Studio構建器所期望的表語義不匹配,並且會導致您不必要的痛苦。使用SqlDataReader。

更新

不要從字符串補丁手動構建發送XML。使用SQL Server本身構建XML,通過FOR XML子句(通常使用PATH),並將結果分配給你發送一個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編碼或任何東西。