在C# .net中RabbitMQ的核心类型和属性,除了交换机,队列关键的类型 / 属性,影响其行为

前言:本文详细介绍了在C#.NET中使用RabbitMQ的核心组件与实现方法。主要内容包括:1) RabbitMQ四种交换机类型(Direct/Fanout/Topic/Headers)的实现原理及C#代码示例;2) 队列的关键属性配置(持久化、排他队列、自动删除等)及其应用场景;3) 高级队列特性如死信队列、消息TTL、优先级队列的实现方式。文章通过完整可运行的代码示例,展示了如何在.NET环境中利用RabbitMQ.Client库构建可靠的消息系统,并针对不同业务场景提供了最佳实践建议,如订单处理、广播通知等典型应用。

在C# .net中RabbitMQ 中不同的**交换机(Exchange)**类型,这是决定消息如何路由到队列的关键组件,除了交换机,队列也有一些关键的类型 / 属性,影响其行为,我会一并说明。

在 C# .NET 开发环境中,如何使用 RabbitMQ 的各种核心类型(主要是交换机类型),我会结合 .NET 生态下最常用的 RabbitMQ.Client 库,为你提供可直接运行的代码示例和清晰的解释。

在 .NET 中使用 RabbitMQ,核心依然是操作 四种交换机类型 (Direct、Fanout、Topic、Headers),API 调用方式与其他语言逻辑一致,但语法符合 C# 规范。以下是完整的实现示例,基于 RabbitMQ.Client NuGet 包(这是官方推荐的 .NET 客户端)。

前置准备

首先需要安装依赖包:

cs 复制代码
# 通过 NuGet 安装 RabbitMQ.Client
Install-Package RabbitMQ.Client
# 或使用 .NET CLI
dotnet add package RabbitMQ.Client

一、通用连接工具类

先封装一个通用的连接创建方法,避免重复代码:

cs 复制代码
using RabbitMQ.Client;
using System;

public static class RabbitMqHelper
{
    // 创建 RabbitMQ 连接
    public static IConnection CreateConnection()
    {
        var factory = new ConnectionFactory
        {
            HostName = "localhost", // RabbitMQ 服务器地址
            UserName = "guest",     // 默认用户名
            Password = "guest",     // 默认密码
            Port = 5672             // 默认端口
        };
        
        try
        {
            var connection = factory.CreateConnection();
            Console.WriteLine("RabbitMQ 连接成功!");
            return connection;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"连接失败:{ex.Message}");
            throw;
        }
    }
}

二、核心:各交换机(Exchange)类型实现示例

交换机是接收生产者消息并将其路由到队列的组件,它的类型决定了路由规则。

1. Direct Exchange(直连交换机)

  • 核心逻辑:RoutingKey 与 BindingKey 完全匹配时路由消息。

  • 适用场景:一对一的消息发送(比如任务分发、精准通知)。

  • 示例代码

    cs 复制代码
    public class DirectExchangeDemo
    {
        // 生产者:发送消息到直连交换机
        public static void SendDirectMessage(string routingKey, string message)
        {
            using (var connection = RabbitMqHelper.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                // 1. 声明直连交换机(durable: true 表示持久化)
                channel.ExchangeDeclare(
                    exchange: "direct_exchange_demo",
                    type: ExchangeType.Direct, // 直连类型
                    durable: true);
    
                // 2. 声明队列(持久化)
                channel.QueueDeclare(
                    queue: "direct_queue_demo",
                    durable: true,
                    exclusive: false,
                    autoDelete: false,
                    arguments: null);
    
                // 3. 绑定交换机和队列(指定 BindingKey)
                channel.QueueBind(
                    queue: "direct_queue_demo",
                    exchange: "direct_exchange_demo",
                    routingKey: routingKey);
    
                // 4. 发送消息(指定 RoutingKey)
                var body = System.Text.Encoding.UTF8.GetBytes(message);
                channel.BasicPublish(
                    exchange: "direct_exchange_demo",
                    routingKey: routingKey,
                    basicProperties: null,
                    body: body);
    
                Console.WriteLine($"已发送 Direct 消息:{message} (RoutingKey: {routingKey})");
            }
        }
    
        // 消费者:接收直连交换机的消息
        public static void ReceiveDirectMessage(string routingKey)
        {
            using (var connection = RabbitMqHelper.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                // 重复声明交换机/队列(幂等操作,不存在则创建)
                channel.ExchangeDeclare("direct_exchange_demo", ExchangeType.Direct, true);
                channel.QueueDeclare("direct_queue_demo", true, false, false, null);
                channel.QueueBind("direct_queue_demo", "direct_exchange_demo", routingKey);
    
                // 创建消费者
                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                    var body = ea.Body.ToArray();
                    var message = System.Text.Encoding.UTF8.GetString(body);
                    Console.WriteLine($"已接收 Direct 消息:{message} (RoutingKey: {ea.RoutingKey})");
                    
                    // 手动确认消息已处理
                    channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
                };
    
                // 开始消费
                channel.BasicConsume(
                    queue: "direct_queue_demo",
                    autoAck: false, // 关闭自动确认,手动 Ack
                    consumer: consumer);
    
                Console.WriteLine("Direct 消费者已启动,按任意键退出...");
                Console.ReadKey();
            }
        }
    }

2. Fanout Exchange(扇出 / 广播交换机)

  • 核心逻辑:无视 routing key 和 binding key,将消息广播到所有绑定到该交换机的队列。

  • 适用场景:一对多的消息广播(比如实时通知、状态同步)。

  • 特点:性能最高,因为无需匹配逻辑。

  • 示例代码

    cs 复制代码
    public class FanoutExchangeDemo
    {
        public static void SendFanoutMessage(string message)
        {
            using (var connection = RabbitMqHelper.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                // 声明扇出交换机
                channel.ExchangeDeclare(
                    exchange: "fanout_exchange_demo",
                    type: ExchangeType.Fanout, // 扇出类型
                    durable: true);
    
                // 声明两个队列并绑定到交换机(无需指定 RoutingKey)
                channel.QueueDeclare("fanout_queue_1", true, false, false, null);
                channel.QueueDeclare("fanout_queue_2", true, false, false, null);
                channel.QueueBind("fanout_queue_1", "fanout_exchange_demo", "");
                channel.QueueBind("fanout_queue_2", "fanout_exchange_demo", "");
    
                // 发送消息(RoutingKey 为空)
                var body = System.Text.Encoding.UTF8.GetBytes(message);
                channel.BasicPublish("fanout_exchange_demo", "", null, body);
                Console.WriteLine($"已发送 Fanout 广播消息:{message}");
            }
        }
    
        // 消费 fanout_queue_1 的消息
        public static void ReceiveFanoutMessage1()
        {
            using (var connection = RabbitMqHelper.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                channel.ExchangeDeclare("fanout_exchange_demo", ExchangeType.Fanout, true);
                channel.QueueDeclare("fanout_queue_1", true, false, false, null);
                channel.QueueBind("fanout_queue_1", "fanout_exchange_demo", "");
    
                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                    var message = System.Text.Encoding.UTF8.GetString(ea.Body.ToArray());
                    Console.WriteLine($"队列1 接收 Fanout 消息:{message}");
                    channel.BasicAck(ea.DeliveryTag, false);
                };
    
                channel.BasicConsume("fanout_queue_1", false, consumer);
                Console.WriteLine("Fanout 消费者1已启动...");
                Console.ReadKey();
            }
        }
    }

3. Topic Exchange(主题交换机)

  • 核心逻辑 :基于通配符匹配 routing key 和 binding key,支持模糊路由。

    • *:匹配一个 单词(比如 order.* 匹配 order.create,但不匹配 order.create.user)。
    • #:匹配零个或多个 单词(比如 order.# 匹配 order.createorder.create.user)。
  • 适用场景:多维度的消息路由(比如按业务模块 + 操作类型路由)。

  • 示例代码

    cs 复制代码
    public class TopicExchangeDemo
    {
        public static void SendTopicMessage(string routingKey, string message)
        {
            using (var connection = RabbitMqHelper.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                // 声明主题交换机
                channel.ExchangeDeclare(
                    exchange: "topic_exchange_demo",
                    type: ExchangeType.Topic, // 主题类型
                    durable: true);
    
                // 绑定规则:
                // queue_order 绑定 "order.*" → 匹配 order.create、order.pay 等
                // queue_error 绑定 "#.error" → 匹配 order.error、user.login.error 等
                channel.QueueDeclare("queue_order", true, false, false, null);
                channel.QueueDeclare("queue_error", true, false, false, null);
                channel.QueueBind("queue_order", "topic_exchange_demo", "order.*");
                channel.QueueBind("queue_error", "topic_exchange_demo", "#.error");
    
                // 发送消息(比如 routingKey = "order.create" 或 "user.login.error")
                var body = System.Text.Encoding.UTF8.GetBytes(message);
                channel.BasicPublish("topic_exchange_demo", routingKey, null, body);
                Console.WriteLine($"已发送 Topic 消息:{message} (RoutingKey: {routingKey})");
            }
        }
    }

4. Headers Exchange(头交换机)

  • 核心逻辑 :无视 routing key,通过消息的 header 属性(键值对)匹配路由规则。

  • 匹配规则 :通过消息头(Headers)而非 RoutingKey 匹配,支持 all/any 匹配规则。

  • 适用场景:复杂的多条件路由(较少用,因为不如 topic 灵活)。

  • 示例代码

    cs 复制代码
    public class HeadersExchangeDemo
    {
        public static void SendHeadersMessage(string message)
        {
            using (var connection = RabbitMqHelper.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                // 声明头交换机
                channel.ExchangeDeclare(
                    exchange: "headers_exchange_demo",
                    type: ExchangeType.Headers, // 头类型
                    durable: true);
    
                // 声明队列并绑定(匹配规则:type=payment 且 status=success)
                channel.QueueDeclare("headers_queue_demo", true, false, false, null);
                channel.QueueBind(
                    queue: "headers_queue_demo",
                    exchange: "headers_exchange_demo",
                    routingKey: "", // 头交换机忽略 RoutingKey
                    arguments: new Dictionary<string, object>
                    {
                        { "x-match", "all" }, // all=所有头匹配,any=任意一个匹配
                        { "type", "payment" },
                        { "status", "success" }
                    });
    
                // 构建消息头并发送
                var properties = channel.CreateBasicProperties();
                properties.Headers = new Dictionary<string, object>
                {
                    { "type", "payment" },
                    { "status", "success" }
                };
    
                var body = System.Text.Encoding.UTF8.GetBytes(message);
                channel.BasicPublish("headers_exchange_demo", "", properties, body);
                Console.WriteLine($"已发送 Headers 消息:{message}");
            }
        }
    }

三、调用示例

cs 复制代码
// 测试 Direct 交换机
DirectExchangeDemo.SendDirectMessage("error", "系统错误日志");
DirectExchangeDemo.ReceiveDirectMessage("error");

// 测试 Fanout 交换机
FanoutExchangeDemo.SendFanoutMessage("全站广播通知");
FanoutExchangeDemo.ReceiveFanoutMessage1();

// 测试 Topic 交换机
TopicExchangeDemo.SendTopicMessage("order.create", "新订单创建");

// 测试 Headers 交换机
HeadersExchangeDemo.SendHeadersMessage("支付成功通知");

总结

  1. 核心 API :.NET 中通过 ExchangeType 枚举指定交换机类型(Direct/Fanout/Topic/Headers),与 RabbitMQ 原生逻辑完全一致。
  2. 关键注意点
    • 声明交换机 / 队列是幂等操作(多次调用不会重复创建);
    • 生产 / 消费时需保证交换机、队列、绑定关系一致;
    • 建议开启手动 AckautoAck: false),避免消息丢失。
  3. 使用场景:Direct 用于精准路由,Fanout 用于广播,Topic 用于多维度模糊路由,Headers 极少使用(灵活性不如 Topic)。

四、队列的常见类型属性

除了交换机,队列也有一些关键的类型 / 属性,影响其行为:

  1. 持久化队列(Durable):队列在 RabbitMQ 重启后依然存在(需同时设置消息持久化)。
  2. 排他队列(Exclusive):仅对当前连接可见,连接关闭后自动删除(适合临时任务)。
  3. 自动删除队列(Auto-delete):最后一个消费者断开后自动删除。
  4. 死信队列(DLX):接收因过期、拒绝、队列满而无法投递的消息(属于特殊的普通队列,通过绑定死信交换机实现)。
  5. 延迟队列 :通过 x-delayed-message 交换机实现(需安装延迟插件),支持消息延迟投递。

队列的属性是在调用 QueueDeclare 方法时通过参数或 arguments 字典配置的,这些属性直接决定了队列的生命周期、消息可靠性、异常处理等核心行为。

前置说明

在 .NET 中,声明队列的核心方法是 IModel.QueueDeclare,基础签名如下:

cs 复制代码
QueueDeclareOk QueueDeclare(
    string queue,        // 队列名
    bool durable,        // 是否持久化
    bool exclusive,      // 是否排他
    bool autoDelete,     // 是否自动删除
    IDictionary<string, object> arguments); // 扩展属性(死信、延迟、最大长度等)

下面按「基础属性」和「高级扩展属性」分类讲解,每个属性都包含作用说明 + C# 代码示例 + 适用场景

一、队列基础属性(必配)

这是声明队列时的核心参数,决定队列的基础行为。

1. Durable(持久化)

  • 作用 :设置为 true 时,队列会被持久化到磁盘,RabbitMQ 重启后队列依然存在;false 则仅存于内存,重启后丢失。

  • 注意 :队列持久化 ≠ 消息持久化,需同时设置消息的 BasicProperties.Persistent = true 才能保证消息不丢。

  • 代码示例

    using (var channel = connection.CreateModel())
    {
    // 声明持久化队列(核心:durable = true)
    channel.QueueDeclare(
    queue: "durable_queue",
    durable: true, // 持久化
    exclusive: false,
    autoDelete: false,
    arguments: null);

    复制代码
      // 发送持久化消息(配合队列持久化)
      var properties = channel.CreateBasicProperties();
      properties.Persistent = true; // 消息持久化
      channel.BasicPublish("", "durable_queue", properties, Encoding.UTF8.GetBytes("持久化消息"));

    }

  • 适用场景:生产环境核心业务队列(如订单、支付),必须保证重启后不丢失。

2. Exclusive(排他队列)

  • 作用 :设置为 true 时,队列仅对创建它的连接可见:

    • 只有创建队列的连接能访问该队列;
    • 连接关闭(或断开)后,队列会被自动删除;
    • 同一连接的多个信道(Channel)可共享该队列。
  • 代码示例

    channel.QueueDeclare(
    queue: "exclusive_queue",
    durable: false, // 排他队列通常不持久化(因为生命周期和连接绑定)
    exclusive: true, // 排他
    autoDelete: false,
    arguments: null);

  • 适用场景:临时任务队列(如客户端专属的临时查询结果队列)、避免多客户端竞争的临时队列。

3. AutoDelete(自动删除)

  • 作用 :设置为 true 时,当最后一个消费者断开连接后,队列会被自动删除(无消费者时触发)。

  • 注意:仅「消费者断开」触发,无消费者时创建队列不会立即删除。

  • 代码示例

    channel.QueueDeclare(
    queue: "auto_delete_queue",
    durable: false,
    exclusive: false,
    autoDelete: true, // 自动删除
    arguments: null);

  • 适用场景:临时消费场景(如实时通知、一次性任务消费),避免无用队列堆积。

二、队列高级扩展属性(通过 arguments 配置)

这些属性通过 QueueDeclarearguments 字典配置,是实现特殊功能的核心。

1. 死信队列(DLX,Dead-Letter-Exchange)

  • 作用 :当消息满足以下条件时,会被路由到「死信交换机」,进而转发到死信队列:

    • 消息被消费者拒绝(BasicNack/BasicReject)且 requeue = false
    • 消息过期;
    • 队列达到最大长度,新消息挤掉旧消息。
  • 核心参数

    • x-dead-letter-exchange:死信交换机名称;
    • x-dead-letter-routing-key:死信消息的路由键(可选,默认用原消息的 routing key)。
  • 代码示例

    // 1. 声明死信交换机和死信队列(普通的直连交换机即可)
    channel.ExchangeDeclare("dlx_exchange", ExchangeType.Direct, true);
    channel.QueueDeclare("dlx_queue", true, false, false, null);
    channel.QueueBind("dlx_queue", "dlx_exchange", "dlx_routing_key");

    // 2. 声明业务队列,并绑定死信属性
    var arguments = new Dictionary<string, object>
    {
    { "x-dead-letter-exchange", "dlx_exchange" }, // 绑定死信交换机
    { "x-dead-letter-routing-key", "dlx_routing_key" }, // 死信路由键
    { "x-message-ttl", 60000 } // 消息过期时间(60秒)
    };

    channel.QueueDeclare(
    queue: "business_queue",
    durable: true,
    exclusive: false,
    autoDelete: false,
    arguments: arguments);

    // 3. 模拟消息被拒绝,进入死信队列
    channel.BasicReject(deliveryTag: 1, requeue: false); // requeue=false 才会进入死信

  • 适用场景:处理失败消息(如订单支付超时、接口调用失败),避免消息丢失或无限重试。

2. 消息过期时间(x-message-ttl)

  • 作用:设置队列中所有消息的默认过期时间(毫秒),超过时间未消费的消息会被丢弃或进入死信队列。

  • 注意 :也可给单个消息设置过期时间(BasicProperties.Expiration),优先级高于队列级别。

  • 代码示例

    var arguments = new Dictionary<string, object>
    {
    { "x-message-ttl", 30000 } // 队列中所有消息默认30秒过期
    };
    channel.QueueDeclare("ttl_queue", true, false, false, arguments);

    // 单个消息设置过期时间(优先级更高)
    var props = channel.CreateBasicProperties();
    props.Expiration = "10000"; // 该消息10秒过期
    channel.BasicPublish("", "ttl_queue", props, Encoding.UTF8.GetBytes("限时消息"));

  • 适用场景:限时有效消息(如验证码、临时通知)。

3. 队列最大长度(x-max-length)

  • 作用:限制队列最多存放的消息数量,超过后会删除旧消息(或发送到死信队列)。

  • 可选参数x-max-length-bytes(按字节数限制队列大小)。

  • 代码示例

    var arguments = new Dictionary<string, object>
    {
    { "x-max-length", 1000 }, // 队列最多存1000条消息
    { "x-dead-letter-exchange", "dlx_exchange" } // 超过数量的旧消息进入死信
    };
    channel.QueueDeclare("limit_queue", true, false, false, arguments);

  • 适用场景:防止队列无限堆积导致内存 / 磁盘溢出(如日志队列)。

4. 队列过期时间(x-expires)

  • 作用:设置队列的空闲过期时间(毫秒),当队列无消费者、无消息、无连接的时间超过该值,会被自动删除。

  • 代码示例

    var arguments = new Dictionary<string, object>
    {
    { "x-expires", 300000 } // 队列空闲5分钟后自动删除
    };
    channel.QueueDeclare("expire_queue", false, false, false, arguments);

  • 适用场景:临时队列(如客户端临时订阅的队列),避免无用队列残留。

5. 最大优先级(x-max-priority)

  • 作用:设置队列支持的消息优先级级别(0~ 指定值),优先级高的消息会先被消费。

  • 代码示例

    var arguments = new Dictionary<string, object>
    {
    { "x-max-priority", 10 } // 支持0-10级优先级(10最高)
    };
    channel.QueueDeclare("priority_queue", true, false, false, arguments);

    // 发送带优先级的消息
    var props = channel.CreateBasicProperties();
    props.Priority = 9; // 该消息优先级为9(高优先级)
    channel.BasicPublish("", "priority_queue", props, Encoding.UTF8.GetBytes("紧急消息"));

  • 适用场景:区分消息紧急程度(如订单队列中,VIP 订单优先消费)。

三、完整示例:配置多属性的业务队列

运行

复制代码
using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Text;

public class AdvancedQueueDemo
{
    public static void CreateAdvancedQueue()
    {
        var factory = new ConnectionFactory { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            // 1. 声明死信交换机和死信队列
            channel.ExchangeDeclare("order_dlx_exchange", ExchangeType.Direct, true);
            channel.QueueDeclare("order_dlx_queue", true, false, false, null);
            channel.QueueBind("order_dlx_queue", "order_dlx_exchange", "order_dlx");

            // 2. 声明订单队列,配置多属性
            var queueArgs = new Dictionary<string, object>
            {
                { "x-durable", true },                  // 持久化
                { "x-message-ttl", 180000 },            // 消息3分钟过期
                { "x-max-length", 5000 },               // 队列最多存5000条消息
                { "x-dead-letter-exchange", "order_dlx_exchange" }, // 死信交换机
                { "x-dead-letter-routing-key", "order_dlx" },       // 死信路由键
                { "x-max-priority", 5 }                 // 5级优先级
            };

            channel.QueueDeclare(
                queue: "order_business_queue",
                durable: true,
                exclusive: false,
                autoDelete: false,
                arguments: queueArgs);

            Console.WriteLine("高级队列创建成功!");
        }
    }
}

总结

  1. 基础属性核心
    • durable 保证队列重启不丢,需配合消息持久化;
    • exclusive 是连接级别的私有队列,autoDelete 是消费者断开后自动删除。
  2. 高级属性重点
    • 死信队列(DLX)是处理异常消息的核心方案;
    • 过期时间(TTL)、最大长度用于控制队列规模,避免堆积;
    • 优先级属性可实现消息的优先消费。
  3. 配置原则 :生产环境队列建议设置 durable=true,并根据业务配置死信、TTL 等属性,避免消息丢失或无限堆积。

其他

RabbitMQ 安装卸载

https://blog.csdn.net/cao919/article/details/115602240

【电商 】订单减少库存业务流程,分布式ID策略选型,C# .net雪花ID代码,下单功能实现 ,异步延时队列

https://blog.csdn.net/cao919/article/details/126413455

SAAS多租户套餐权限模块功能按钮 设置 关键代码实现 JAVA C#

https://blog.csdn.net/cao919/article/details/143254585

相关推荐
guygg882 小时前
C#实现的TCP/UDP网络调试助手
网络·tcp/ip·c#
jackletter12 小时前
3dsmax2026插件开发入门:使用.net8开发
.net·3dmax·入门·插件·.net8·3dsmax2026
1314lay_100714 小时前
C# 点击一次api,限流中间件但是X-Rate-Limit-Remaining剩余数量减少2
visualstudio·c#
“抚琴”的人14 小时前
C#上位机工厂模式
开发语言·c#
工程师00717 小时前
C#中的AutoUpdater自动更新类
开发语言·c#·自动更新开源库·autoupdate
曹牧19 小时前
C#:Obsolete
开发语言·c#
我是苏苏19 小时前
Web开发:使用C#的System.Drawing.Common将png图片转化为icon图片
开发语言·c#
阿蒙Amon19 小时前
C#每日面试题-is和as的区别
java·开发语言·c#
阿蒙Amon19 小时前
C#每日面试题-简述泛型约束
java·开发语言·c#