c# - 如何从 .NET Core 上的 WCF SOAP 客户端记录 http 级流?

标签 c# wcf soap .net-core .net-standard-2.0

背景:我正在维护一个从各种不可靠的 API 中提取数据的集成平台。其中一些操作会产生潜在的高成本,因此出于诊断目的,每条传出和传入的消息都会记录到磁盘的单独文件中。对于类似 REST 的 API,我在网络流上使用了一个简单的包装器,它也将数据保存到一个文件中。对于 .NET Classic SOAP 客户端,我有一个帮助程序动态包装 SoapHttpClientProtocol 以使用相同的网络流日志记录机制。

.NET Standard 2.0.NET Core 中,唯一支持的编写 SOAP 客户端的方法是 WCF。如何以编程方式配置 WCF SOAP 客户端以将 HTTP 传入/传出流记录到单独的文件,最好使用可配置的名称?

我当前的示例客户端代码:

public abstract class ServiceCommunicatorBase<T>
    where T : IClientChannel
{
    private const int Timeout = 20000;

    private static readonly ChannelFactory<T> ChannelFactory = new ChannelFactory<T>(
        new BasicHttpBinding(),
        new EndpointAddress(new Uri("http://target/endpoint")));

    protected T1 ExecuteWithTimeoutBudget<T1>(
        Func<T, Task<T1>> serviceCall,
        [CallerMemberName] string callerName = "")
    {
        // TODO: fixme, setup logging
        Console.WriteLine(callerName);

        using (var service = this.CreateService(Timeout))
        {
            // this uses 2 threads and is less than ideal, but legacy app can't handle async yet
            return Task.Run(() => serviceCall(service)).GetAwaiter().GetResult();
        }
    }

    private T CreateService(int timeout)
    {
        var clientChannel = ChannelFactory.CreateChannel();
        clientChannel.OperationTimeout = TimeSpan.FromMilliseconds(timeout);
        return clientChannel;
    }
}

public class ConcreteCommunicator
    : ServiceCommunicatorBase<IWCFRemoteInterface>
{
    public Response SomeRemoteAction(Request request)
    {
        return this.ExecuteWithTimeoutBudget(
            s => s.SomeRemoteAction(request));
    }
}

最佳答案

我已经设法使用 IClientMessageInspector 记录消息通过可配置的行为附加。 Message Inspectors on MSDN一些文档但它仍然含糊不清(并且有些过时,netstandard-2.0 API 表面略有不同。

我不得不停止使用 ChannelFactory<T>使用实际生成的代理类。工作代码(为简洁起见删减):

var clientChannel = new GeneratedProxyClient(
  new BasicHttpBinding { SendTimeout = TimeSpan.FromMilliseconds(timeout) },
  new EndpointAddress(new Uri("http://actual-service-address"));

clientChannel.Endpoint.EndpointBehaviors.Add(new LoggingBehaviour());

服务类别:

// needed to bind the inspector to the client channel
// other methods are empty
internal class LoggingBehaviour : IEndpointBehavior
{
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(new LoggingClientMessageInspector());
    }
}

internal class LoggingClientMessageInspector : IClientMessageInspector
{
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        var correlationId = Guid.NewGuid();
        this.SaveLog(ref request, correlationId, "RQ");

        return correlationId;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        var correlationId = (Guid)correlationState;
        this.SaveLog(ref reply, correlationId, "RS");
    }

    private void SaveLog(ref Message request, Guid correlationId, string suffix)
    {
        var outputPath = GetSavePath(suffix, correlationId, someOtherData);
        using (var buffer = request.CreateBufferedCopy(int.MaxValue))
        {
            var directoryName = Path.GetDirectoryName(outputPath);
            if (directoryName != null)
            {
                Directory.CreateDirectory(directoryName);
            }

            using (var stream = File.OpenWrite(outputPath))
            {
                using (var message = buffer.CreateMessage())
                {
                    using (var writer = XmlWriter.Create(stream))
                    {
                        message.WriteMessage(writer);
                    }
                }
            }

            request = buffer.CreateMessage();
        }
    }
}

关于c# - 如何从 .NET Core 上的 WCF SOAP 客户端记录 http 级流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53341566/

相关文章:

c# - Nhibernate Queryover Case Insensitive IsIn

c# - 试写策略建议

c# - 如何以编程方式发现我的 C# 应用程序的当前端点?

ios - 如何编辑标签

java - 处理畸形 SOAP 故障

c# - 原始 SQL 方法中的字符串插值,这怎么可能?

c# - 将 VLC 媒体播放器添加到 Visual Studio 2015

.net - 有没有官方的 WCF 标志?

c# - 在 WCF 的其他契约(Contract)中将 MessageContract 作为 MessageBodyMember

wcf - 如何在 node.js 中使用 WCF soap web 服务