发送含MessageData<byte[]>集合的消息时消费端遇MassTransit加载异常
嘿,我之前也碰到过这个MassTransit.MessageDataException: The message data was not loaded的问题,咱们一步步来排查解决:
1. 确保发送端与消费端的Enchilada存储配置完全一致
这是最常见的问题!发送端和消费端的MessageData存储配置必须完全匹配,包括存储类型(本地磁盘、S3、Azure Blob等)、路径/桶名称、权限配置。如果两端配置不一样,消费端根本找不到存储的MessageData文件,自然会抛出异常。
举个例子,发送端如果是这样配置本地磁盘存储:
services.AddMassTransit(x => { x.UsingRabbitMq((context, cfg) => { cfg.MessageDataRepository(context, r => { r.EnchiladaRepository(c => { c.UseFileSystem("/app/attachments"); }); }); }); });
那消费端必须用完全相同的路径(如果是本地存储,要确保消费进程有该路径的读写权限);如果是云存储,密钥、桶名、区域这些参数也必须完全一致。
2. 确认数组类型MessageData的发送处理
你用到了MessageData<byte[]>[]数组,发送时要确保每个数组元素都被正确上传到存储库,不能有遗漏。最好用Task.WhenAll等待所有附件上传完成后再发送消息,避免消息先被投递但部分附件还没写入存储的情况:
// 假设你有一组byte[]格式的附件内容 var attachmentContents = new List<byte[]> { ... }; // 逐个上传到MessageData存储 var messageDataAttachments = await Task.WhenAll( attachmentContents.Select(async content => await _messageDataRepository.PutBytes(content, CancellationToken.None) ) ); // 构造消息并发送 var sendMailMessage = new SendMail { Attachments = messageDataAttachments, AttachmentFileName = "example.pdf", // 其他属性... }; await _bus.Publish(sendMailMessage);
3. 消费端正确加载MessageData数组
消费时,要注意MessageData<T>的Value属性是异步的,必须用await加载,数组类型需要逐个处理每个元素:
public class SendMailConsumer : IConsumer<ISendMail> { private readonly IMessageDataRepository _messageDataRepository; public SendMailConsumer(IMessageDataRepository messageDataRepository) { _messageDataRepository = messageDataRepository; } public async Task Consume(ConsumeContext<ISendMail> context) { // 加载单个附件 var singleAttachmentBytes = await context.Message.Attachment.Value; // 加载数组中的所有附件 var allAttachmentBytes = await Task.WhenAll( context.Message.Attachments.Select(async md => await md.Value) ); // 这里做你的邮件发送逻辑... } }
如果跳过await直接访问Value,会因为加载未完成抛出异常。另外也要确保消费端正确注册了IMessageDataRepository,和发送端配置一致。
4. 检查MessageData的引用地址是否完整
有时候消息传输过程中,MessageData的存储地址(Address属性)可能被序列化/反序列化篡改。你可以在发送端打印每个MessageData的Address,然后在消费端对比:
发送端打印:
var attachment = await _messageDataRepository.PutBytes(content, CancellationToken.None); Console.WriteLine($"发送端附件地址: {attachment.Address}");
消费端打印:
foreach(var md in context.Message.Attachments) { Console.WriteLine($"消费端收到的附件地址: {md.Address}"); }
如果地址不一致,说明序列化配置有问题,比如自定义序列化器没有正确处理MessageData类型,建议检查MassTransit的序列化设置(默认Json序列化是支持MessageData的,如果你换了Protobuf等序列化器,需要确认是否兼容)。
5. 验证Enchilada存储的可用性
最后,确认消费端能访问到Enchilada的存储服务:
- 如果是本地存储:检查路径是否存在,消费进程是否有读写权限;
- 如果是云存储:确认密钥有效、网络连通、桶权限配置正确;
- 手动检查存储位置是否存在发送端上传的文件,消费端能否直接读取该文件。
内容的提问来源于stack exchange,提问作者Arjan Verrmunt

