如何在收发两端通用拦截Azure Service Bus消息并无侵入式处理属性?
当然有办法实现这个需求!针对Azure Service Bus结合WCF的场景,IClientMessageInspector和IDispatchMessageInspector确实是完美的拦截器方案,不用修改原有收发业务代码就能实现通用的消息属性注入与读取。下面给你一个完整可运行的示例,涵盖从拦截器实现到配置启用的全流程:
一、实现客户端拦截器(发送时自动添加属性)
这个拦截器会在消息发送前,自动向消息中添加通用属性,比如发送时间、客户端标识之类的:
using System; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; public class ServiceBusClientInspector : IClientMessageInspector { // 发送消息前拦截,添加自定义属性 public object BeforeSendRequest(ref Message request, IClientChannel channel) { // 添加自定义属性到消息Properties集合 request.Properties["X-Client-Send-Time"] = DateTime.UtcNow.ToString("o"); request.Properties["X-Client-Id"] = Environment.MachineName; return null; } // 接收响应后处理(这里我们不需要,留空即可) public void AfterReceiveReply(ref Message reply, object correlationState) { } } // 行为扩展类,用于将拦截器添加到客户端行为中 public class ServiceBusClientBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { // 将自定义拦截器添加到客户端运行时 clientRuntime.ClientMessageInspectors.Add(new ServiceBusClientInspector()); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } }
二、实现服务端拦截器(接收时自动读取属性)
服务端拦截器会在消息接收后,自动读取并处理这些通用属性,比如记录日志或者做业务校验:
using System; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; public class ServiceBusDispatchInspector : IDispatchMessageInspector { // 接收消息后拦截,读取自定义属性 public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { if (request.Properties.ContainsKey("X-Client-Send-Time")) { var sendTime = request.Properties["X-Client-Send-Time"].ToString(); Console.WriteLine($"收到来自客户端的消息,发送时间:{sendTime}"); } if (request.Properties.ContainsKey("X-Client-Id")) { var clientId = request.Properties["X-Client-Id"].ToString(); Console.WriteLine($"客户端标识:{clientId}"); } return null; } // 发送响应前处理(这里我们不需要,留空即可) public void BeforeSendReply(ref Message reply, object correlationState) { } } // 行为扩展类,用于将拦截器添加到服务端行为中 public class ServiceBusDispatchBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { // 将自定义拦截器添加到服务端调度运行时 endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new ServiceBusDispatchInspector()); } public void Validate(ServiceEndpoint endpoint) { } }
三、配置WCF端点启用拦截器
你可以通过配置文件或者代码配置两种方式启用这些拦截器:
方式1:通过App.config/Web.config配置
首先要注册行为扩展,然后在端点行为中引用:
<system.serviceModel> <extensions> <behaviorExtensions> <!-- 注册客户端行为扩展 --> <add name="serviceBusClientBehavior" type="YourNamespace.ServiceBusClientBehavior, YourAssemblyName"/> <!-- 注册服务端行为扩展 --> <add name="serviceBusDispatchBehavior" type="YourNamespace.ServiceBusDispatchBehavior, YourAssemblyName"/> </behaviorExtensions> </extensions> <behaviors> <endpointBehaviors> <behavior name="ClientWithInterceptor"> <serviceBusClientBehavior /> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior name="ServiceWithInterceptor"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> <!-- 客户端端点配置 --> <client> <endpoint address="sb://your-servicebus-namespace.servicebus.windows.net/your-queue" binding="netMessagingBinding" bindingConfiguration="NetMessagingBinding" contract="YourNamespace.IYourServiceContract" behaviorConfiguration="ClientWithInterceptor"/> </client> <!-- 服务端端点配置 --> <services> <service name="YourNamespace.YourServiceImplementation" behaviorConfiguration="ServiceWithInterceptor"> <endpoint address="sb://your-servicebus-namespace.servicebus.windows.net/your-queue" binding="netMessagingBinding" bindingConfiguration="NetMessagingBinding" contract="YourNamespace.IYourServiceContract" behaviorConfiguration="ServiceWithInterceptorEndpoint"/> </service> </services> <bindings> <netMessagingBinding> <binding name="NetMessagingBinding"> <transportSettings batchFlushInterval="00:00:01"/> </binding> </netMessagingBinding> </bindings> </system.serviceModel>
方式2:通过代码动态配置
如果你的WCF客户端/服务是通过代码创建的,可以直接添加行为:
客户端代码配置示例:
var endpointAddress = new EndpointAddress("sb://your-servicebus-namespace.servicebus.windows.net/your-queue"); var binding = new NetMessagingBinding(); var factory = new ChannelFactory<IYourServiceContract>(binding, endpointAddress); // 添加客户端拦截器行为 factory.Endpoint.Behaviors.Add(new ServiceBusClientBehavior()); var client = factory.CreateChannel(); // 此时调用服务方法,消息会自动带上自定义属性 client.YourServiceMethod();
服务端代码配置示例:
var serviceHost = new ServiceHost(typeof(YourServiceImplementation)); var endpoint = serviceHost.AddServiceEndpoint( typeof(IYourServiceContract), new NetMessagingBinding(), "sb://your-servicebus-namespace.servicebus.windows.net/your-queue"); // 添加服务端拦截器行为 endpoint.Behaviors.Add(new ServiceBusDispatchBehavior()); serviceHost.Open();
四、验证效果
当你运行客户端发送消息时,客户端拦截器会自动添加X-Client-Send-Time和X-Client-Id属性;服务端接收到消息后,拦截器会读取这些属性并打印到控制台(或者你可以改成记录到日志系统)。整个过程完全不需要修改原有业务的收发代码,实现了通用的属性处理逻辑。
内容的提问来源于stack exchange,提问作者Jörgen Sigvardsson
相关产品推荐
相关产品推荐

