2013-09-01 2 views
0

клиент вызывает метод «Foo()» моя службу веб-WCF - и получает большой массив байт в ответ:Как я могу отслеживать продолжительность ответа программно?

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

очевидно, когда клиент считывает все данные, соединение HTTP закрывается - и если я знаю когда это произошло, я мог отслеживать общую продолжительность «передачи». Я знаю о трассировке и т. Д., Но мне нужно иметь эти данные программно, поэтому я могу отобразить его пользователю. Как я могу отслеживать это?

+0

Вы можете объявить переменную 'класса Stopwatch' и запустите его перед вызовом и отобразите 'секундомер.Elapsed' после возврата вызова. Если вы используете потоки или задачи, немного сложно получить доступ к главному окну, чтобы отображать статистику для пользователя, но идея остается прежней. –

+0

уверен - но не могли бы вы указать, где именно я должен назвать секундомер.Избран? – avs099

+0

Выполняет [по умолчанию счетчик производительности WCF] (http://msdn.microsoft.com/en-us/library/vstudio/ms731055 (v = vs.100) .aspx) доставляет то, что вам нужно? – rene

ответ

-1

Вы можете использовать класс 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; 
+0

'stopWatch.Elapsed' - это свойство TimeSpan, которое намного легче манипулировать, чем простые миллисекунды. –

+0

мой метод Foo() вызывается из КЛИЕНТА, я не вызываю его изнутри своего кода. – avs099

+0

@ avs099 да, Foo() будет вызываться клиентом, но с помощью секундомера вы можете рассчитать общую продолжительность вашей службы wcf для выполнения ваших функций, а затем вы можете отправить эту продолжительность клиенту или отобразить его, однако вы хотите, я имею в виду внутри вашего кода SERVICE. –

0

У меня есть два решения, счетчики Peformance и в пользовательское поведение, но я не уверен, что если они точно отвечают на ваш вопрос, потому что я не учитываю сетевую задержку.

Счетчики производительности
Первый soltuion использует встроенный в performance counters, которая приближается к вашему требованию. В основном вы хотите включить PerformanceCounters для своего сервиса, а затем в своем сервисе получить один из них. Точная продолжительность недоступна, но Calls per second входит в число других счетчиков.

Убедитесь, что это будет добавлено в конфигурацию службы:

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

В вашей службе есть статический класс, который держит ваш PerformanceCounter. В моем примере я добавил статический экземпляр в службу, и в реальности я бы переместил его в другой класс.

public class Service1 : IService1 
{ 
    // in an ideal world thisd how instancename would look like 
    //[email protected] 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 = "[email protected]:||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); 
} 
Смежные вопросы