Service Bus Explorer 时如何使用消息正文 C# 读取 重新提交消息时添加垃圾 http://schemas.microsoft.com/2003/10/Serialization -

How to Read with Message Body C# when Service Bus Explorer Adds junk http://schemas.microsoft.com/2003/10/Serialization when resubmitting messages -

我正在开发基于 Azure 服务总线和 Azure Functions 的系统。

我们的服务总线消息是基于文本的,通常 json 我们已经开始在我们的一些消息中看到有关文本中无效字符的错误。

这不会影响队列中的所有消息,我已经能够追溯到使用服务总线资源管理器重新提交正文类型为“字符串”的死信队列消息

在服务总线资源管理器中,消息显示完全正常:

然而,当从代码中读取消息时,正文是:

@06string083http://schemas.microsoft.com/2003/10/Serialization/�15嗨伙计,你好吗?

我希望能够处理以这种方式提交的消息,但是 none ReceivedMessage Class 上的消息有效。我在 Linqpad

中尝试了多种使用 C# 的方法
var client = new ServiceBusClient(connectionString);


var receiver = client.CreateReceiver(queueName, new ServiceBusReceiverOptions { ReceiveMode = ServiceBusReceiveMode.PeekLock});

string txtBody;
"Peek Messages".Dump();
var message = await receiver.PeekMessageAsync();
while (message != null)
{

    Stream stream = message.Body.ToStream();
    StreamReader reader = new StreamReader(stream,Encoding.UTF8);
    txtBody = reader.ReadToEnd();
    txtBody.Dump("Read with stream");
    
    txtBody = Encoding.UTF8.GetString(message.Body.ToArray());
    txtBody.Dump("Read with Byte[]");
    
    message.Body.ToString().Dump("Read with toString");
    
    message = await receiver.PeekMessageAsync();
}

只有当消息作为字符串重新提交时才会发生这种情况 - 作为流重新提交按预期工作。

在我看来,应该有一种检测此类消息的方法以及一种阅读它的替代方法。服务总线资源管理器显然正在以某种方式处理它。

Service Bus Explorer 基于旧版 SDK,它使用 DataContractSerializer 对消息负载进行编码。此方法已被弃用,并且未沿用到较新的 SDK 中。

Azure.Messaging.ServiceBus 不假设您的消息负载是如何序列化或编码的,仅返回原始字节。要与 Service Bus Explorer 中的负载交互,您需要使用等效的序列化程序来转换负载。

可以在 Service Bus Interop sample.

中找到这样做的示例

我正在添加自己的答案以帮助他人。

Jesse Squire 向我指出了服务总线互操作示例的正确方向,但该方法仅适用于消息已序列化并包含“序列化垃圾”的情况。

通过我的队列的绝大多数消息都是用新库生成的,并且是“干净的”。使用服务总线资源管理器或其他基于旧库的工具从 DQL“修复并重新提交”的消息中只有一小部分会导致问题。

我通过检查文本中的序列化标记解决了这个问题,如下所示。

string ReadMessageText(ServiceBusReceivedMessage message)
{
    string msgText = message.Body.ToString();

    if (msgText.StartsWith("@") && msgText.Contains(@"http://schemas.microsoft.com/2003/10/Serialization"))
    {
        var deserializer = new DataContractSerializer(typeof(string));
        XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(message.Body.ToStream(), XmlDictionaryReaderQuotas.Max);

        // deserialize the XML envelope into a string
        msgText = (string)deserializer.ReadObject(reader);
    }
    return msgText.Trim();
}

DataContractSerializer 需要 System.Runtime.Serialization,reader 需要 System.Xml。