rabbitmq c#开发必须引用rabbitmq.client,显式配置连接参数,启用发布确认和qos,正确设置durable/autodelete,优先用basicconsume而非basicget,并注意消息顺序不保证。

直接上手 RabbitMQ 的 C# 项目,RabbitMQ.Client 是唯一必须引用的 NuGet 包,其他封装库(如 EasyNetQ)会掩盖底层行为,新手容易在连接异常、消息丢失、确认机制失效时完全抓瞎。
安装 RabbitMQ.Client 并验证基础连接
不要跳过本地服务验证这一步。很多“连不上”的问题其实出在 RabbitMQ 本身没跑起来,而不是代码写错了。
- 确保 RabbitMQ 服务已启动:
sudo service rabbitmq-server status(Linux)或 Windows 服务管理器中检查RabbitMQ服务状态 - NuGet 安装命令:
Install-Package RabbitMQ.Client(Package Manager Console) - 最简连接测试代码里必须包含
ConnectionFactory的HostName、Port、UserName、Password—— 即使是本地默认配置,也建议显式写出,避免依赖隐式值 - 连接失败时常见错误信息是:
System.IO.IOException: Unable to read data from the transport connection,大概率是端口不通(5672 被防火墙拦截)或用户权限不足(guest用户默认只允许 localhost 登录)
声明 Queue 和 Exchange 时必须设对 durable 和 autoDelete
这两个布尔参数决定消息和队列的生命周期,新手常设反导致消息一断电就丢,或者重启后队列自动消失。
-
durable = true:队列本身会持久化到磁盘,但不等于消息自动持久化——消息还要单独设IBasicProperties.DeliveryMode = 2 -
autoDelete = false:即使没有消费者连接,队列也不会被自动删除;设为true会导致你发完消息后没人消费,队列立刻被删,消息永久丢失 - Exchange 声明也要配
durable = true,否则重启 RabbitMQ 后 Exchange 消失,生产者发消息直接报错404 NOT_FOUND - no exchange 'xxx' - 推荐组合:
QueueDeclare("log_queue", durable: true, exclusive: false, autoDelete: false, arguments: null)
发送消息必须用 channel.ConfirmSelect() + channel.WaitForConfirmsOrDie()
默认情况下,C# 客户端发消息是“发完即忘”,网络中断、Broker 崩溃、磁盘满都不会通知你。不加发布确认,等于裸奔。
-
channel.ConfirmSelect()必须在channel.BasicPublish()之前调用,否则WaitForConfirmsOrDie()会一直阻塞或抛异常 -
WaitForConfirmsOrDie()是同步等待,适合低频关键消息;高频场景应改用异步回调channel.BasicAcks += (sender, ea) => { ... } - 如果没收到确认,
WaitForConfirmsOrDie()抛出OperationInterruptedException,此时必须重试或记录失败消息,不能忽略 - 注意:
ConfirmSelect只对当前 channel 生效,每个新 channel 都要重新启用
BasicGet 拉模式 vs BasicConsume 推模式选错会卡死线程
新手容易以为 channel.BasicGet() 是“主动取一条”,结果在循环里狂调它,CPU 拉满却收不到消息——因为它是无消息时立即返回 null,不是阻塞等待。
-
BasicGet适合偶发、低频、控制权必须在自己手里的场景(比如定时轮询检查);但它不会触发QoS限流,容易把大量消息一次性拉进内存撑爆 -
BasicConsume才是标准做法:注册一个EventingBasicConsumer,消息来时由 Broker 主动推给你的HandleDelivery回调;记得设置channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false)控制并发消费数 - 漏掉
consumer.Shutdown += (s, e) => { ... }处理,进程退出时 channel 可能没正常关闭,Broker 端残留 unack 消息 - 不要在
HandleDelivery里做耗时操作(如 HTTP 请求、DB 写入),否则会堵住整个 consumer 线程,应转交 Task 或后台队列处理
最易被忽略的一点:RabbitMQ 默认不保证消息顺序,哪怕单个 producer + 单个 consumer + 单 queue,只要开了多线程 publish 或 consumer 用了 prefetch > 1,就可能乱序。需要严格顺序,得靠业务层加序列号或用单线程 consumer + prefetchCount = 1 死守。










