WCF:如何手动记录原始 xml 消息内容?

Posted

技术标签:

【中文标题】WCF:如何手动记录原始 xml 消息内容?【英文标题】:WCF: How to log raw xml message contents manually? 【发布时间】:2020-04-15 00:10:49 【问题描述】:

我有一个简单的经典 ASP 网站,它使用 WCF 调用 SOAP API。 为了调试,我需要手动将 XML 消息内容记录到单独的日志文件中。

例如,12/23/18_34.txt 文件包含在 12/23 18:34 发送的 XML 请求。 我已经阅读了许多记录 WCF XML 消息的文章并找到了这两种方法。

    使用消息记录功能。 使用 IClientMessageInspector。

我可以使用第一种方法进行日志记录,但这样做我无法将消息内容保存到具有特定名称的单独文件中。 所以我尝试了第二种方法,但它不起作用,我找不到问题所在。

由于当前项目是一个经典的 ASP 网站,没有命名空间,我不知道如何设置 web.config 文件中 type 属性的值。 我设法通过创建一个具有BehaviorExtensionElement 的单独dll 文件来添加它,并将其复制到当前项目的Bin 文件夹中。

<add name="logXmlBehavior" type="MessageLogger.MessageLoggerBehaviorExtensionElement, MessageLogger, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
public class MessageLogger : IClientMessageInspector
    
        public void AfterReceiveReply(ref Message reply, object correlationState)
        
            MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
            reply = buffer.CreateMessage();

            var fileName = DateTime.Now.ToString("dd_HHmm");
            System.IO.File.WriteAllText($"C:/Logs/Symmetry/fileName_response.txt", buffer.CreateMessage().ToString());
        

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        
            MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
            request = buffer.CreateMessage();

            var fileName = DateTime.Now.ToString("dd_HHmm");
            System.IO.File.WriteAllText($"C:/Logs/Symmetry/fileName_post.txt", buffer.CreateMessage().ToString());
            return null;
        
    

这是我的 MessageLogger 类,但它不记录任何内容。 ????

如何在没有单独 DLL 的情况下将 BehaviorExtensionElement 添加到经典 ASP 网站? 为什么我当前的记录器不工作?

PS:网站使用 IIS 托管。

【问题讨论】:

您在运行应用程序时是否遇到任何异常?你能分享你如何从经典的asp调用WCF服务吗?您的应用程序池在哪个身份下运行?尝试将应用程序池标识设置为网络服务或本地系统。还可以在 iis 中为经典 asp link 启用详细的错误消息。 【参考方案1】:

你的代码sn-ps好像没有问题。请参考我的示例。MessageLogger 类。

    public class ClientMessageLogger : IClientMessageInspector
    
        public void AfterReceiveReply(ref Message reply, object correlationState)
        
            string displayText = $"the client has received the reply:\nreply\n";
            Console.Write(displayText);
        

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        
            string displayText = $"the client send request message:\nrequest\n";
            Console.WriteLine(displayText);
            return null;
        

应用于客户端服务端点的端点行为。

public class AuthBehavior : BehaviorExtensionElement, IEndpointBehavior
    
        public override Type BehaviorType => typeof(AuthBehavior);
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        
        
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        
            ClientMessageLogger inspector = new ClientMessageLogger();
            clientRuntime.ClientMessageInspectors.Add(inspector);
        
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        
        
        public void Validate(ServiceEndpoint endpoint)
        
        
        protected override object CreateBehavior()
        
            return new AuthBehavior();
        
    

然后我在扩展部分注册端点行为并将其应用于自动生成的客户端服务端点。

    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IService" />
            </basicHttpBinding>
        </bindings>
        <client>
          <!--apply it on the endpoint-->
            <endpoint address="http://localhost:1300/" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference1.IService"
                name="BasicHttpBinding_IService" behaviorConfiguration="authBehavior" />
        </client>
      <behaviors>
        <endpointBehaviors>
          <behavior name="authBehavior">
            <authbehavior />
          </behavior>
        </endpointBehaviors>
      </behaviors>
      <extensions>
        <behaviorExtensions>
          <!--like yours, namespace.class,assembly-->
          <add name="authbehavior" type="Client3.AuthBehavior,Client3,Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
        </behaviorExtensions>
      </extensions>
</system.serviceModel>

最终,控制台应用程序在向服务器发送请求时会正确记录消息。

ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
        //client.Endpoint.EndpointBehaviors.Add(new AuthBehavior());
        try
        
            Console.WriteLine(client.SayHello());
        
        catch (Exception ex)
        
            Console.WriteLine(ex.ToString());
        

结果。 此外,我认为 WCF 跟踪也可以完成记录通信消息的任务。只需添加以下配置,检查 bin 文件夹中的mylogs.svclog 文件。

  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel.MessageLogging">
        <listeners>
          <add type="System.Diagnostics.XmlWriterTraceListener" name="xmlLog" initializeData="myLogs.svclog"/>
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IService" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://10.157.13.70:1300/" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference1.IService"
        name="BasicHttpBinding_IService" />
    </client>
    <diagnostics>
      <messageLogging logEntireMessage="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="false"/>
    </diagnostics>
  </system.serviceModel>

如果有什么我可以帮忙的,请随时告诉我。

【讨论】:

以上是关于WCF:如何手动记录原始 xml 消息内容?的主要内容,如果未能解决你的问题,请参考以下文章

WCF 自定义行为的依赖注入

如何从 SOAP 响应 XML 创建 WCF 消息对象

如何将参数(id)传递给 WCF 中的消息检查器?

响应消息的内容类型application/xml;charset=utf-8 与绑定的内容类型(text/xml;charset=utf-8)不匹配,WCF

如何从 WCF 服务返回 xml 响应

快速入门系列--WCF--02消息会话与服务寄宿