基于WCF中间件/拦截器提前返回自定义响应的实现方案
问题描述
我想管控所有WCF方法的调用,统一添加验证逻辑。当验证失败时,要让方法提前返回和该方法返回类型一致的自定义响应,而且不想在每个方法里都加验证检查,怎么在集中位置实现这个需求?
附上我的WCF服务伪代码:
using System; using System.Collections.Generic; using System.ServiceModel; using System.Text; using System.Threading; namespace Microsoft.WCF.Documentation { [ServiceContractAttribute(Namespace="http://microsoft.wcf.documentation")] public interface ISampleService { [OperationContractAttribute(AsyncPattern=true)] IAsyncResult BeginGetCustomerInfo(GetCustomerInfoRequest request, AsyncCallback callback, object asyncState); GetCustomerInfoResponse EndGetCustomerInfo(IAsyncResult result); [OperationContractAttribute(AsyncPattern=true)] IAsyncResult BeginGetProductDetails(GetProductDetailsRequest request, AsyncCallback callback, object asyncState); GetProductDetailsResponse EndGetProductDetails(IAsyncResult result); } public class SampleService : ISampleService { public IAsyncResult BeginGetCustomerInfo(GetCustomerInfoRequest request, AsyncCallback callback, object asyncState) { Console.WriteLine("BeginGetCustomerInfo called with: \"{0}\"", request); // 业务逻辑 } public GetCustomerInfoResponse EndGetCustomerInfo(IAsyncResult r) { // 业务逻辑 return new GetCustomerInfoResponse(); } public IAsyncResult BeginGetProductDetails(GetProductDetailsRequest request, AsyncCallback callback, object asyncState) { Console.WriteLine("BeginGetProductDetails called with: \"{0}\"", request); // 业务逻辑 } public GetProductDetailsResponse EndGetProductDetails(IAsyncResult r) { // 业务逻辑 return new GetProductDetailsResponse(); } } }
解决方案:用WCF消息检查器+服务行为实现集中验证
WCF提供的IDispatchMessageInspector接口可在服务端接收请求后、调用业务方法前拦截消息,支持验证失败时直接构造自定义响应返回,无需进入业务方法。配合IServiceBehavior可将检查器应用到整个服务的所有方法,实现集中管控。
步骤1:实现IDispatchMessageInspector
通过AfterReceiveRequest方法执行验证逻辑,失败时构造对应响应并终止后续流程:
using System; using System.Reflection; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; public class ValidationMessageInspector : IDispatchMessageInspector { public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { // 获取当前调用的操作信息 var operationContext = OperationContext.Current; var operationDescription = operationContext.EndpointDispatcher.DispatchRuntime.Operations.Find(operationContext.IncomingMessageHeaders.Action); if (operationDescription == null) return null; // 解析请求参数(适配异步Begin方法) object requestParam = null; if (operationDescription.SyncMethod != null && operationDescription.SyncMethod.Name.StartsWith("Begin")) { var requestType = operationDescription.SyncMethod.GetParameters()[0].ParameterType; requestParam = request.GetBody(requestType); } // 执行验证逻辑 bool isValid = ValidateRequest(requestParam, operationDescription); if (isValid) return null; // 构造自定义失败响应 var responseType = GetResponseType(operationDescription); var customResponse = CreateCustomFailedResponse(responseType); // 返回响应并终止流程 Message reply = Message.CreateMessage(request.Version, operationDescription.Messages[1].Action, customResponse); operationContext.Reply(reply); return null; } public void BeforeSendReply(ref Message reply, object correlationState) { } // 获取对应操作的响应类型 private Type GetResponseType(OperationDescription operation) { if (operation.IsAsync) { return operation.EndMethod.ReturnType; } return operation.Messages[1].Body.ReturnValue.Type; } // 自定义验证逻辑 private bool ValidateRequest(object requestParam, OperationDescription operation) { // 示例:验证GetCustomerInfoRequest的CustomerId非空 if (requestParam is GetCustomerInfoRequest customerRequest) { return !string.IsNullOrEmpty(customerRequest.CustomerId); } // 示例:验证GetProductDetailsRequest的ProductId大于0 if (requestParam is GetProductDetailsRequest productRequest) { return productRequest.ProductId > 0; } return true; } // 创建验证失败的响应对象 private object CreateCustomFailedResponse(Type responseType) { var response = Activator.CreateInstance(responseType); // 假设所有响应都有IsSuccess和ErrorMessage属性 var isSuccessProp = responseType.GetProperty("IsSuccess"); var errorMsgProp = responseType.GetProperty("ErrorMessage"); isSuccessProp?.SetValue(response, false); errorMsgProp?.SetValue(response, "请求验证失败,请检查参数或权限"); return response; } }
步骤2:实现IServiceBehavior,全局应用检查器
public class ValidationServiceBehavior : IServiceBehavior { public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers) { foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints) { endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new ValidationMessageInspector()); } } } public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } }
步骤3:注册服务行为
方式1:配置文件注册(推荐)
在WCF配置文件中添加行为扩展:
<system.serviceModel> <extensions> <behaviorExtensions> <add name="validationBehavior" type="你的命名空间.ValidationServiceBehavior, 你的程序集名称" /> </behaviorExtensions> </extensions> <behaviors> <serviceBehaviors> <behavior name="SampleServiceBehavior"> <validationBehavior /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="Microsoft.WCF.Documentation.SampleService" behaviorConfiguration="SampleServiceBehavior"> <endpoint address="" binding="basicHttpBinding" contract="Microsoft.WCF.Documentation.ISampleService" /> </service> </services> </system.serviceModel>
方式2:代码注册
在服务宿主启动时添加行为:
using System.ServiceModel; class Program { static void Main() { using (ServiceHost host = new ServiceHost(typeof(SampleService))) { host.Description.Behaviors.Add(new ValidationServiceBehavior()); host.Open(); Console.WriteLine("Service is running..."); Console.ReadLine(); host.Close(); } } }
关键说明
- 异步方法兼容:代码已适配
AsyncPattern=true的异步方法,自动解析Begin方法参数和End方法返回类型。 - 响应适配:通过反射创建对应返回类型的响应对象,只要所有响应类型有统一的错误属性(如
IsSuccess、ErrorMessage)即可自动设置失败信息。 - 无侵入性:所有验证逻辑集中在检查器中,业务方法无需修改。
内容的提问来源于stack exchange,提问作者csharpdeveloper1
相关产品推荐
相关产品推荐

