【问题标题】:WCF Tracing in ASP.NET CoreASP.NET Core 中的 WCF 跟踪
【发布时间】:2019-02-05 00:08:05
【问题描述】:

我们曾经使用 WCF over ASP.NET,最近切换到 WCF over ASP.NET Core。这很难实现,因为 ASP.Net Core 不支持开箱即用的 WCF。一方面,整个 web.config XML 配置模型已转储到 ASP.NET Core 中,因此我们无法在那里配置 WCF 跟踪。

即这个文件没用: https://docs.microsoft.com/en-us/dotnet/framework/wcf/diagnostics/tracing/configuring-tracing

我们不得不通过在 WCF 和端口 80 之间放置一个 http 代理来破解 ASP.NET Core。WCF 实际上是在另一个端口上运行的。

问题是,如果 ASP.NET Core 不关注 web.config,我们如何启用 WCF 跟踪?

【问题讨论】:

  • 通过使用 webhttp 绑定,WCF 可以像 RestFul 服务一样使用。所以可以代替webApi项目使用
  • WCF 太复杂了,这就是为什么需要跟踪。为什么需要在 ASP.NET Core 中进行跟踪?请把两者分开,不要用别人没有的方法来困扰自己。
  • 你以为我想支持一个死技术?如果可以选择摆脱它,我会的。不要用无用的 cmets 来困扰自己。

标签: c# asp.net .net wcf asp.net-core


【解决方案1】:

在客户端跟踪的情况下,我使用自定义端点行为 (IEndpointBehavior) 和自定义消息日志检查器 (IClientMessageInspector) 来获取输入和输出消息。

客户端初始化:

_serviceClient = new MyCustomServiceClient();
_serviceClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(_configParams.ServiceUri);
_serviceClient.Endpoint.EndpointBehaviors.Add(new EndpointLoggingBehavior("MyCustomService"));

EndpointLoggingBehavior的实现:

public class EndpointLoggingBehavior : IEndpointBehavior
    {
        public EndpointLoggingBehavior(string serviceName)
        {
            _serviceName = serviceName;
        }

        private readonly string _serviceName;

        public void AddBindingParameters(ServiceEndpoint endpoint,
            System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.ClientMessageInspectors.Add(new MessageLoggingInspector(_serviceName));
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }
    }

MessageLoggingInspector的实现:

public class MessageLoggingInspector : IClientMessageInspector
    {
        private readonly string _serviceName;
        public MessageLoggingInspector(string serviceName)
        {
            _serviceName = serviceName;
        }
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            // copying message to buffer to avoid accidental corruption
            var buffer = reply.CreateBufferedCopy(int.MaxValue);
            reply = buffer.CreateMessage();
            // creating copy
            var copy = buffer.CreateMessage();
            //getting full input message
            var fullInputMessage = copy.ToString();

        }
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            // copying message to buffer to avoid accidental corruption
            var buffer = request.CreateBufferedCopy(int.MaxValue);
            request = buffer.CreateMessage();
            // creating copy
            var copy = buffer.CreateMessage();
            //getting full output message
            var fullOutputMessage = copy.ToString();
            return null;
        }
    }

然后,当然,您需要将这些消息写入任何存储。

【讨论】:

  • Petr,谢谢你的提示,我从my Q&A 引用了这个。一个建议:在“copy.ToString();”之后添加一条评论,如“那么,当然......”在代码中,例如"// 将消息写入存储或记录器"。 WCF 太难学了——从我的角度来看太难了,它与金锤反模式相反——所以该代码中的任何技巧都可以节省时间。在我的例子中,我在 MessageLoggingInspector 的构造函数中注入了一个记录器。
【解决方案2】:

您将在 .NET Core 上为 WCF 使用 ETW 跟踪

https://github.com/dotnet/wcf/blob/master/Documentation/HowToUseETW.md

根据我的经验,您有一些限制

  1. 对所有 WCF 应用启用跟踪,而不是通过配置文件为单个应用配置
  2. 您无法输出带有 ETW 跟踪的消息
  3. SvcTraceViewer.exe 不能很好地用于跟踪审查,您需要转到 PerfView.exe,这可能会出现学习曲线

ETW 的好处

  1. 您可以避免传统形式的跟踪对性能造成的影响
  2. 不再需要更改配置来启动/停止跟踪

【讨论】:

    【解决方案3】:

    以 Petr Pokrovskiy 的出色 answer 为基础,您可以通过以下方式将跟踪重定向到标准 .NET Core 日志:

    客户端初始化:

    ILogger<MyCustomService> = ...; // use dependency injection to get instance
    _serviceClient = new MyCustomServiceClient();
    _serviceClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(_configParams.ServiceUri);
    _serviceClient.Endpoint.SetTraceLogging(logger);
    

    SetTraceLogging 的实现:

    using Microsoft.Extensions.Logging;
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    
    namespace Common.ServiceModel.Logging
    {
        public static class ServiceEndpointExtensions
        {
            public static void SetTraceLogging(this ServiceEndpoint serviceEndpoint, ILogger logger)
            {
                if (logger == null)
                    throw new ArgumentNullException(nameof(logger));
                if (logger.IsEnabled(LogLevel.Trace))
                    serviceEndpoint.EndpointBehaviors.Add(new ClientMessageLoggingBehavior(logger));
            }
        }
    
        internal sealed class ClientMessageLoggingBehavior :
            IEndpointBehavior
        {
            private readonly ILogger _logger;
    
            public ClientMessageLoggingBehavior(ILogger logger)
            {
                _logger = logger;
            }
    
            public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
            {
            }
    
            public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
            {
                clientRuntime.ClientMessageInspectors.Add(new ClientMessageLogger(_logger));
            }
    
            public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
            {
            }
    
            public void Validate(ServiceEndpoint endpoint)
            {
            }
        }
    
        internal sealed class ClientMessageLogger :
            IClientMessageInspector
        {
            private readonly ILogger _logger;
    
            public ClientMessageLogger(ILogger logger)
            {
                this._logger = logger;
            }
    
            public void AfterReceiveReply(ref Message reply, object correlationState)
            {
                // copying message to buffer to avoid accidental corruption
                reply = Clone(reply);
                this._logger.LogTrace("Received SOAP reply:\r\n{0}", reply.ToString());
    
            }
    
            public object BeforeSendRequest(ref Message request, IClientChannel channel)
            {
                // copying message to buffer to avoid accidental corruption
                request = Clone(request);
                this._logger.LogTrace("Sending SOAP request:\r\n{0}", request.ToString());
                return null;
            }
    
            private static Message Clone(Message message)
            {
                return message.CreateBufferedCopy(int.MaxValue).CreateMessage();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      • 2019-04-04
      • 1970-01-01
      • 2019-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多