В приложении С# я вытаскиваю сообщение из очереди брокера службы SQL с помощью инструкции ниже.
При попытке конвертировать message_body в SqlBytes и другие типы генерируется исключение. Во время выполнения message_body всегда начинается с типа байта [].
Оставление message_body в качестве байта [] работает, но я получаю исключение, жалующееся на ошибку в моем XML-документе при попытке десериализации для ввода SccmAction.
Моя конечная цель - десериализировать 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();
}
Я застрял с байтом [], поскольку SqlBytes, похоже, не работал.
Наконец, проблема десериализации XML для объекта связана с тем, что значение в EntryDateTime не соответствует формату ISO 8601. Сделав конвертер, я смог получить дату в соответствующем формате.
select CONVERT(varchar(30), GETDATE(), 126)
D не вводить сообщение VARBINARY (MAX) message_body в XML в самом заявлении RECEIVE. Его плохая практика, поскольку он может обмануть Service Broker, полагая, что RECEIVE никогда не возникало, если во время CAST возникает исключение проверки XML. Подробнее см. Ссылку.
Я рекомендую вам оставить столбец как VARBINARY (MAX) (то есть RECEIVE..., message_body FROM...) в списке прогнозов и на вашем С# -кодате использовать столбец как SqlBytes, а не как байт [], Затем вы можете использовать SqlBytes.Stream для создания XmlReader поверх этого потока. Или вы можете читать непосредственно в XmlDocument.
Не используйте строго типизированные DataTables с RECEIVE, он не соответствует семантике таблицы, ожидаемой разработчиками Visual Studio, и вы вызовете себе ненужную боль. Используйте SqlDataReader.
Update
Не создавайте отправленный 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 или любом из этих материалов.