如何以编程方式跟踪响应持续时间

本文关键字:跟踪 响应 持续时间 方式 编程 | 更新日期: 2023-09-27 18:29:51

客户端调用我的web WCF服务的方法"Foo()",并接收大字节数组作为响应:

public byte[] Foo()
{
    return new byte[10000000];
}

显然,当客户端读取所有数据时,HTTP连接就会关闭——如果我知道这是什么时候发生的,我就可以跟踪"传输"的总持续时间。我知道Tracing等,但我需要以编程方式获得这些数据,以便向用户显示。我该如何追踪?

如何以编程方式跟踪响应持续时间

我有两个解决方案,性能计数器和自定义行为,但我不确定它们是否能准确回答您的问题,因为我没有考虑网络延迟。

性能计数器
第一个解决方案使用了内置的性能计数器,可以满足您的需求。基本上,您希望为服务启用performanceCounters,然后在服务中获取其中一个。确切的持续时间不可用,但Calls per second在其他计数器中。

请确保将其添加到您的服务配置中:

<system.serviceModel>
    <diagnostics performanceCounters="All" />
</system.serviceModel>

在您的服务中有一个静态类,它保存您的性能计数器。在我的示例中,我将静态实例添加到服务中,实际上我会将其移动到另一个类中。

public class Service1 : IService1
{
     // in an ideal world thisd how instancename would look like
    //ServiceName.ContractName.OperationName@first endpoint listener address
    private static PerformanceCounter pc = new PerformanceCounter();
     // our static constructor
    static Service1()
    {
        // naming of the instance is garbeld due to length restrictions...
        var cat = new PerformanceCounterCategory("ServiceModelOperation 4.0.0.0");
        foreach (var instance in cat.GetInstanceNames())
        {
            Trace.WriteLine(instance); // determine the instancename and copy over :-)
        }
        pc.CategoryName = "ServiceModelOperation 4.0.0.0";
        pc.CounterName = "Calls Per Second";
        pc.InstanceName = "Service1.IServ84.GetDataUsingD31@00:||LOCALHOST:2806|SERVICE1.SVC";
    }
    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        // do interesting stuff here
        // here I have the value (in the service call but you can call this from anywhere, 
        // even from another thread. 
        // or use perfmon.exe to obtain or make a graph of the value over time...
        Trace.WriteLine(pc.NextValue().ToString()); 
        return composite;
    }
}

自定义行为
这种自定义行为拦截了对servicemethod的调用,从而可以启动和停止计时器并存储结果。

添加以下类:

// custom self timing for any wcf operation
    public class Timing :Attribute, IOperationBehavior,  IOperationInvoker 
    { 
        IOperationInvoker innerOperationInvoker;
        private string operName = "";
        public Timing()
        {
        }
        public Timing(IOperationInvoker innerOperationInvoker, string name)
        {
            this.innerOperationInvoker = innerOperationInvoker;
            operName = name;
        }
        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            dispatchOperation.Invoker = new Timing(dispatchOperation.Invoker, operationDescription.Name);
        }
        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            object value;
            var sw = new Stopwatch();
            sw.Start();
            value = innerOperationInvoker.Invoke( instance, inputs, out outputs);
            sw.Stop();
            // do what you need with the value...
            Trace.WriteLine(String.Format("{0}: {1} ms", operName,  sw.ElapsedMilliseconds));
            return value;
        }

        // boring required interface stuff
        public object[] AllocateInputs()
        {
            return innerOperationInvoker.AllocateInputs();
        }
        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            return innerOperationInvoker.InvokeBegin(instance, inputs, callback, state);
        }
        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            return innerOperationInvoker.InvokeEnd(instance, out outputs, result);
        }
        public bool IsSynchronous
        {
            get { return innerOperationInvoker.IsSynchronous; }
        }
        public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            // throw new NotImplementedException();
        }
        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {
            // throw new NotImplementedException();
        }
        public void Validate(OperationDescription operationDescription)
        {
            // throw new NotImplementedException();
        }
    }

现在,在您的界面中用Timing属性装饰要存储其计时的操作:

[ServiceContract]
public interface IService1
{
    [OperationContract]
    [Timing]   // Timing for this Operation!
    CompositeType GetDataUsingDataContract(CompositeType composite);
}

您可以使用StopWatch类来查找持续时间,请参阅此msdn链接:

http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.elapsed.aspx

        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        // your wcf functionalities
        stopWatch.Stop();
        long duration = stopWatch.ElapsedMilliseconds;