Azure 服务总线简介
Azure 服务总线是一个完全托管的企业级消息代理,可促进云环境和混合环境中应用程序与服务之间的可靠通信。它支持消息队列(点对点通信)和发布-订阅主题(向多个消费者广播),非常适合解耦分布式系统。通过 Paramore.Brighter.MessagingGateway.AzureServiceBus 包,Brighter 提供了与 Azure 服务总线的一流集成,使 .NET 应用程序中的命令/事件路由更加无缝。
要求
- .NET 8 或更高版本
- 包含以下 NuGet 包的 .NET 项目:
- Paramore.Brighter.MessagingGateway.AzureServiceBus:启用 Azure 服务总线集成。
- Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection:将 Brighter 与 Azure 消息服务桥接。
- Paramore.Brighter.ServiceActivator.Extensions.Hosting:作为后台服务托管 Brighter。
- Serilog.AspNetCore:结构化日志记录(可选但推荐)。
Brighter 回顾
在继续 Azure 服务总线配置之前,先回顾一下我们已知的 Brighter 知识。
请求(命令/事件)
使用 IRequest 定义消息:
public class Greeting() : Event(Guid.NewGuid())
{
public string Name { get; set; } = string.Empty;
}
- 命令:单接收者操作(例如 SendEmail)。
- 事件:广播通知(例如 OrderShipped)。
消息映射器
在 Brighter 消息与应用程序对象之间转换:
public class GreetingMapper : IAmAMessageMapper<Greeting>
{
public Message MapToMessage(Greeting request)
{
var header = new MessageHeader();
header.Id = request.Id;
header.TimeStamp = DateTime.UtcNow;
header.Topic = "greeting.topic"; // 目标主题
header.MessageType = MessageType.MT_EVENT;
var body = new MessageBody(JsonSerializer.Serialize(request));
return new Message(header, body);
}
public Greeting MapToRequest(Message message)
{
return JsonSerializer.Deserialize<Greeting>(message.Body.Bytes)!;
}
}
请求处理器
处理传入消息:
public class GreetingHandler(ILogger<GreetingHandler> logger) : RequestHandler<Greeting>
{
public override Greeting Handle(Greeting command)
{
logger.LogInformation("你好 {Name}", command.Name);
return base.Handle(command);
}
}
使用 Azure 服务总线配置 Brighter
1. 连接设置
使用 Azure 凭据提供程序进行安全认证:
var connection = new ServiceBusVisualStudioCredentialClientProvider(".servicebus.windows.net");
或使用连接字符串:
var connection = new ServiceBusConnectionStringClientProvider("<Your-Connection-String>");
2. Azure 服务总线订阅
订阅队列/主题:
.AddServiceActivator(opt =>
{
opt.Subscriptions = [
new AzureServiceBusSubscription<Greeting>(
new SubscriptionName("greeting-subscription"), // 可选
new ChannelName("greeting-queue"), // 队列名称
new RoutingKey("greeting-topic"), // 主题名称
bufferSize: 2)
];
opt.ChannelFactory = new AzureServiceBusChannelFactory(new AzureServiceBusConsumerFactory(connection, false));
})
3. Azure 服务总线生产者配置
发布事件到主题:
.UseExternalBus(new AzureServiceBusProducerRegistryFactory(connection, new[]
{
new AzureServiceBusPublication
{
Topic = new RoutingKey("greeting-topic"),
MakeChannels = OnMissingChannel.Create
}
}).Create());
4. 死信队列(DLQ)
启用 DLQ 处理有毒消息:
opt.Subscriptions = [
new AzureServiceBusSubscription<Greeting>(
subscriptionName: new SubscriptionName("greeting-subscription"),
channelName: new ChannelName("greeting-queue"),
routingKey: new RoutingKey("greeting-topic"),
subscriptionConfiguration: new AzureServiceBusSubscriptionConfiguration
{
DeadLetteringOnMessageExpiration = true // 启用 DLQ
},
bufferSize: 2
)
];
Azure 服务总线会自动将过期或失败的消息移动到 DLQ 以供检查。
结论
将 Brighter 与 Azure 服务总线集成可在 .NET 应用程序中实现稳健、可扩展的消息传递。通过利用 Azure 的托管基础设施和 Brighter 的抽象层,您可以:
- 通过发布-订阅模式解耦服务。
- 确保消息顺序和可靠性。
- 通过 DLQ 简化错误处理。
在生产环境中使用时,始终根据 Brighter 的最新文档验证 Azure 服务总线配置。
参考
// See https://aka.ms/new-console-template for more information
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Paramore.Brighter;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.MessagingGateway.AzureServiceBus;
using Paramore.Brighter.MessagingGateway.AzureServiceBus.ClientProvider;
using Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection;
using Paramore.Brighter.ServiceActivator.Extensions.Hosting;
using Serilog;
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();
var host = new HostBuilder()
.UseSerilog()
.ConfigureServices((_, services) =>
{
var connection = new ServiceBusVisualStudioCredentialClientProvider(".servicebus.windows.net");
services
.AddHostedService<ServiceActivatorHostedService>()
.AddServiceActivator(opt =>
{
opt.Subscriptions = [
new AzureServiceBusSubscription<Greeting>(
new SubscriptionName("greeting-subscription"), // Optional
new ChannelName("greeting-queue"), // Queue name
new RoutingKey("greeting-topic"), // Topic Name
subscriptionConfiguration: new AzureServiceBusSubscriptionConfiguration{
DeadLetteringOnMessageExpiration = true // Enablin DLQ
},
bufferSize: 2)
];
opt.ChannelFactory = new AzureServiceBusChannelFactory(new AzureServiceBusConsumerFactory(connection, false));
})
.AutoFromAssemblies()
.UseExternalBus(new AzureServiceBusProducerRegistryFactory(connection, new[]
{
new AzureServiceBusPublication
{
Topic = new RoutingKey("greeting-topic"),
MakeChannels = OnMissingChannel.Create
}
}).Create());
})
.Build();
_ = host.RunAsync();
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(10));
Console.Write("Say your name (or q to quit): ");
var name = Console.ReadLine();
if (string.IsNullOrEmpty(name))
{
continue;
}
if (name == "q")
{
break;
}
var process = host.Services.GetRequiredService<IAmACommandProcessor>();
process.Post(new Greeting { Name = name });
}
await host.StopAsync();
public class Greeting() : Event(Guid.NewGuid())
{
public string Name { get; set; } = string.Empty;
}
public class GreetingMapper : IAmAMessageMapper<Greeting>
{
public Message MapToMessage(Greeting request)
{
var header = new MessageHeader();
header.Id = request.Id;
header.TimeStamp = DateTime.UtcNow;
header.Topic = "greeting.topic";
header.MessageType = MessageType.MT_EVENT;
var body = new MessageBody(JsonSerializer.Serialize(request));
return new Message(header, body);
}
public Greeting MapToRequest(Message message)
{
return JsonSerializer.Deserialize<Greeting>(message.Body.Bytes)!;
}
}
public class GreetingHandler(ILogger<GreetingHandler> logger) : RequestHandler<Greeting>
{
public override Greeting Handle(Greeting command)
{
logger.LogInformation("Hello {Name}", command.Name);
return base.Handle(command);
}
}
663

被折叠的 条评论
为什么被折叠?



