C# Azure Service Bus发送消息方法 C#如何使用Service Bus队列和主题

1次阅读

ServiceBusClient 发送消息前必须确认连接字符串具有 Send 权限,否则会因 UnauthorizedaccessException 或 401 错误失败;发送需通过 ServiceBusSender(由 client.CreateSender() 创建)调用 SendMessageAsync,且消息须封装为 ServiceBusMessage。

C# Azure Service Bus发送消息方法 C#如何使用Service Bus队列和主题

ServiceBusClient 发送消息前必须确认连接字符串权限

ServiceBusClient 发送消息失败,十有八九是连接字符串没开“Send”权限。azure 门户里生成的连接字符串默认只含“Listen”,哪怕你只是发消息,也得手动进“Shared access policies”新建一个带 Send(或 Manage)权限的策略,再拿它的连接字符串。

常见错误现象:UnauthorizedAccessException401 Unauthorized,但里不直接提权限——它藏在底层 http 响应里。

  • 队列场景:连接字符串只需 Send 权限
  • 主题场景:同样只需 Send,不用 Manage(除非你要动态创建订阅)
  • 本地开发调试时,别用 RootManageSharedAccessKey 的完整连接字符串,容易误提交到代码库

发送到队列用 ServiceBusSender.SendMessageAsync,不是 SendAsync

ServiceBusSender 是发送入口,不是 ServiceBusClient 直接发。调用链必须是:ServiceBusClientCreateSender("queue-name")SendMessageAsync。写成 client.SendAsync(...) 会编译不过——这个方法根本不存在。

示例关键片段:

var client = new ServiceBusClient(connectionString); var sender = client.CreateSender("myqueue"); await sender.SendMessageAsync(new ServiceBusMessage("hello"));
  • 每条消息封装为 ServiceBusMessage,不能直接传 string 或 byte[]
  • 若需设置 TTL、sessionId、CorrelationId 等,都在 ServiceBusMessage 构造后赋值属性
  • 同一个 ServiceBusSender 实例可复用,但别跨线程共用未加锁的实例(SDK 内部已做线程安全处理,但高并发下仍建议按作用域创建)

发到主题要指定主题名,订阅名由接收方控制

主题(Topic)和队列(Queue)的发送 API 完全一致,区别只在 CreateSender 的参数:传主题名,不是订阅名。订阅(Subscription)是接收端概念,发送方完全感知不到。

例如发到主题 orders-topic

var sender = client.CreateSender("orders-topic"); // 不是 "orders-topic/subscriptions/new-orders" await sender.SendMessageAsync(new ServiceBusMessage(jsonSerializer.Serialize(order)));
  • 主题支持通配符订阅(如 orders-*),但发送方无需、也不能指定匹配逻辑
  • 若消息需要路由到特定订阅,得靠 Rule + Message.UserPropertiesapplicationProperties 配合筛选器,不是靠发送路径
  • 主题本身不存消息,消息进入主题后立刻分发到所有匹配的订阅;所以发送成功 ≠ 订阅端收到,得单独查订阅的活跃消息数

生产环境必须处理 MessageException 和 ServiceBusException

网络抖动、配额超限、消息体超 256KB(标准层)都会抛 ServiceBusException,而 MessageException 多见于序列化失败(比如传了不可序列化的对象)。不捕获这些异常,会导致消息静默丢失或应用崩溃。

  • 推荐用 try/catch (ServiceBusException ex) when (ex.Reason == ServiceBusFailureReason.ServiceTimeout) 做重试
  • MessageSizeExceeded 类异常,必须提前校验 ServiceBusMessage.Body 长度,SDK 不会在发送前主动检查
  • 不要依赖 sender.DisposeAsync() 清理连接——它只释放本地资源;连接池由 ServiceBusClient 统一管理,应优先复用 client 实例

实际用起来最易忽略的是:主题发送和队列发送代码一模一样,差别全在 Azure 资源命名和后台配置上。很多人卡在“发了但收不到”,结果发现是订阅没建、或筛选器写错了条件、或订阅被手动禁用了。

text=ZqhQzanResources