Microsoft 服务总线 REST 客户端 - 从 Queue 读取时出现问题

Microsoft Service Bus REST Client - Issues with reading from Queue

我们正在使用 Microsoft ServiceBus QueueClient 向服务总线发送消息。在接收消息时,我们正在使用 ServiceBus REST API。 body 的反序列化失败,我们无法找出根本原因。

发送消息的示例代码如下:

MessagingFactory messagingFactory =
    MessagingFactory.CreateFromConnectionString(....);

Console.WriteLine("Creating Service Bus Queue Client...");

QueueClient queueSendClient = messagingFactory.CreateQueueClient(.);

// Send message M1 to the topic.
Console.WriteLine("Sending message.. ");

BrokeredMessage bm = CreateMessage();
queueSendClient.Send(bm);

CreateMessage 实例化一个具有序列化 object 实例的 BrokeredMessage。

private static BrokeredMessage CreateMessage()
{
    JObject o1 = JObject.Parse(File.ReadAllText(@"..\..\requestJson.json"));

    string jsonMessage = JsonConvert.SerializeObject(o1);

    CommandMessage commandMessage = new CommandMessage();
    JsonCommand content = new JsonCommand("abc", "def", jsonMessage);

    List<Command> list = new List<Command>();
    list.Add(content);
    commandMessage.Initialize(list, false, false);

    var message = new BrokeredMessage(commandMessage);

    return message;
}

注意:CommandMessage、JsonCommand、Command 都装饰有[DataContract]。

如果我们也使用QueueClient 进行接收,那么消息的接收工作正常。但在我们的例子中,我们使用的是服务总线 Rest 客户端。

接收消息代码如下:

const string ServiceBusNamespace = "mysb2015-ns";
string baseAddressHttp = "https://" + ServiceBusNamespace + ".servicebus.windows.net/";
string queueAddress = baseAddressHttp + QueueName;

HttpResponseMessage response = await this.httpClient.PostAsync(address + "/messages/head?timeout=60", new ByteArrayContent(new Byte[0]));

byte[] body = response.Content.ReadAsByteArrayAsync().Result;

DataContractSerializer deserializer = new DataContractSerializer(typeof(CommandMessage));
using (MemoryStream ms = new MemoryStream(body))
{
CommandMessage cmdMsg = (CommandMessage)deserializer.ReadObject(ms); 
}

读取 object 失败,但根级别的数据无效:

System.Runtime.Serialization.SerializationException 未处理 HResult=-2146233076 Message=反序列化 CommandMessage 类型的 object 时出错。根级别的数据无效。第 1 行,位置 1。 来源=System.Runtime.Serialization

我们查看了响应中的 content-type header 是 application/xml;utf-8.

Initializes a new instance of the BrokeredMessage class from a given object by using DataContractSerializer with a binary XmlDictionaryWriter.

当您将 BrokeredMessage 发送到队列时,XmlDictionaryWriter 正在添加其类型指示。如果使用QueueClient接收,就没有问题。因为它可以解决这个类型指示。但是,如果您使用的不是 QueueClient,您将遇到反序列化问题。

解决方案:

  1. Remove indicator before deserialize.
  2. Use other constructor of BrokeredMessage. BrokeredMessage(Stream messageBodyStream, bool ownsStream) and control the message body yourself.

在这个 article 中,他们解释了问题和解决方案。