You need to enable JavaScript to run this app. .NET 5.0中原WCF的Endpoint.Behaviors等组件位置及SOAP日志实现
优惠活动
大模型
产品
解决方案
定价
更多

.NET 5.0中原WCF的Endpoint.Behaviors等组件位置及SOAP日志实现

.NET 5 及以上版本实现WCF客户端SOAP流量日志的适配方案

你通过NuGet安装的面向.NET 5+的System.ServiceModel系列包,其实并没有移除IClientMessageInspector、IEndpointBehavior、ClientRuntime.MessageInspectors这些核心接口和属性,之前找不到对应入口,本质是混淆了WCF客户端和服务端的扩展逻辑,整套实现的适配改动量非常小,具体步骤如下:

1. 调整原有消息检查器的实现

你之前写的入站、出站消息捕获逻辑可以完全保留,只需要补充消息缓冲的适配——.NET Framework下默认会帮你做消息流的内存缓冲,.NET 5+的WCF客户端默认是流式读取的,直接读取Message内容会把流耗尽,导致下游SOAP调用失败:

public class SoapLogClientMessageInspector : IClientMessageInspector
{
    private readonly ILogger _logger;
    public SoapLogClientMessageInspector(ILogger logger)
    {
        _logger = logger;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        var bufferedReply = BufferMessage(reply);
        _logger.Debug("Reply received: {NewLine}{MessageContent}", 
            Environment.NewLine, bufferedReply.ToString());
        // 把缓冲后的消息实例回写,保证下游能正常读取
        reply = bufferedReply;
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        var bufferedRequest = BufferMessage(request);
        _logger.Debug("Sending request: {NewLine}{MessageContent}", 
            Environment.NewLine, bufferedRequest.ToString());
        request = bufferedRequest;
        return null;
    }

    // 消息缓冲辅助方法,避免流读取耗尽的问题
    private Message BufferMessage(Message original)
    {
        if (original == null) return null;
        var messageBuffer = original.CreateBuffer(int.MaxValue);
        return messageBuffer.CreateMessage();
    }
}

注意:.NET Framework下WCF默认会自动对消息流做内存缓冲,因此可以直接调用ToString()读取内容;.NET 5+的跨平台WCF客户端默认采用流式传输,不会自动缓冲,直接读取Message会消耗底层流,导致下游SOAP调用直接报错。

2. 实现自定义端点行为

很多人适配时找不到MessageInspectors属性,本质是找错了对象:这个集合是客户端侧ClientRuntime的专属成员,在自定义IEndpointBehavior的ApplyClientBehavior方法参数中就能拿到,跨平台WCF客户端包里完整保留了这个属性,和.NET Framework的行为完全一致:

public class SoapLogEndpointBehavior : IEndpointBehavior
{
    private readonly IClientMessageInspector _inspector;
    public SoapLogEndpointBehavior(IClientMessageInspector inspector)
    {
        _inspector = inspector;
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        // 无额外绑定参数需求,留空即可
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        // 直接把消息检查器加入客户端运行时的检查器集合
        clientRuntime.MessageInspectors.Add(_inspector);
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        // 客户端场景不需要实现服务端分发逻辑,留空即可
    }

    public void Validate(ServiceEndpoint endpoint)
    {
        // 可按需添加端点合法性校验逻辑
    }
}

3. 挂载行为到客户端端点

这套注册逻辑和.NET Framework的使用方式几乎没有区别:拿到生成的WCF代理客户端实例后,直接把自定义的端点行为加入Endpoint的行为集合即可:

// 初始化WCF客户端代理
var soapClient = new YourServiceClient(binding, endpointAddress);
// 初始化日志检查器,注入项目内的ILogger实例
var logInspector = new SoapLogClientMessageInspector(_logger);
// 挂载端点行为
soapClient.Endpoint.Behaviors.Add(new SoapLogEndpointBehavior(logInspector));

常见场景适配

  • 如果是通过依赖注入集成WCF客户端,不需要手动实例化客户端,可以在添加客户端的链式配置中直接挂载行为:
    services.AddServiceClient<IYourService>(config =>
    {
        // 配置绑定、服务地址的原有逻辑
    }).AddEndpointBehavior<SoapLogEndpointBehavior>();
    
  • 若运行时抛出"消息主体已被读取,无法重复读取"的异常,就是没有执行消息缓冲导致的,必须通过CreateBuffer把消息内容加载到内存,再读取内容做日志,最后把缓冲生成的Message实例回写到ref参数中。

内容的提问来源于stack exchange,提问作者AFract

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 16:36:03