2016-03-03 148 views
0
  1. 我創建了一個IDisposable對象,用於記錄Dispose上的執行時間。使用異步語句不等待內部任務

  2. 然後,我創建了一個使用這個對象來記錄我的業務類的任何方法調用

  3. 我的業務類使用異步方法,在任務完成前,然後離開using語句的時間RealProxy ,然後記錄錯誤的執行時間。

這裏是我的代碼:

/// <summary> 
/// Logging proxy with stopwatch 
/// </summary> 
/// <typeparam name="T"></typeparam> 
public sealed class LoggingProxy<T> : RealProxy// where T : MarshalByRefObject 
{ 
    private ILog _logger; 
    private readonly T _instance; 

    private LoggingProxy(T instance, ILog logger) 
     : base(typeof(T)) 
    { 
     _logger = logger; 
     _instance = instance; 
    } 

    /// <summary> 
    /// Create the Transparent proy for T 
    /// </summary> 
    /// <param name="type">An implementation type of T</param> 
    /// <returns>T instance</returns> 
    public static T Create(ILog logger) 
    { 
      logger.DebugFormat("[{0}] Instantiate {1}", "LoggingProxy", typeof(T).Name); 
      var instance = (T)Activator.CreateInstance(typeof(T), logger); 

      //return the proxy with execution timing if debug enable in logger 
      if (logger.IsDebugEnabled) 
       return (T)new LoggingProxy<T>(instance, logger).GetTransparentProxy(); 
      else 
       return instance; 
    } 


    /// <summary> 
    /// Invoke the logging method using Stopwatch to log execution time 
    /// </summary> 
    /// <param name="msg"></param> 
    /// <returns></returns> 
    public override IMessage Invoke(IMessage msg) 
    { 
     var methodCall = (IMethodCallMessage)msg; 
     var method = (MethodInfo)methodCall.MethodBase; 

     string methodName = method.Name; 
     string className = method.DeclaringType.Name; 

     //return directly methods inherited from Object 
     if (method.DeclaringType.Name.Equals("Object")) 
     { 
      var result = method.Invoke(_instance, methodCall.Args); 
      return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); 
     } 

     using (var logContext = _logger.DebugTiming("[{0}] Execution time for {1}", className, methodName)) 
     { 
      _logger.DebugFormat("[{0}] Call method {1}", className, methodName); 
      //execute the method 
      //var result = method.Invoke(_instance, methodCall.Args); 
      object[] arg = methodCall.Args.Clone() as object[]; 
      var result = method.Invoke(_instance, arg); 

      //wait the task ends before log the timing 
      if (result is Task) 
       (result as Task).Wait(); 

      return new ReturnMessage(result, arg, 0, methodCall.LogicalCallContext, methodCall); 
     } 

    } 

的_logger.DebugTiming方法啓動秒錶t和記錄它的處置。 我發現,使其與異步方法的工作的唯一辦法,就是用這條線:

  //wait the task ends before log the timing 
      if (result is Task) 
       (result as Task).Wait(); 

但我一直認爲我做的是打破異步方法的所有優點的感覺。

- >如果你有一個關於如何做一個正確實施

建議 - >任何的呼籲代理的wait()的真正影響的想法?

+0

您嘗試編寫的代碼可以在[使用Unity的異步攔截器]中找到(https://msdn.microsoft.com/en-us/magazine/dn574805.aspx) –

+0

但是,在我的上下文中不能使用Unity。 。有些經理將它看作科幻 –

回答

1

您可以使用Task.ContinueWith():

public override IMessage Invoke(IMessage msg) 
{ 
    var methodCall = (IMethodCallMessage)msg; 
    var method = (MethodInfo)methodCall.MethodBase; 

    string methodName = method.Name; 
    string className = method.DeclaringType.Name; 

    //return directly methods inherited from Object 
    if (method.DeclaringType.Name.Equals("Object")) 
    { 
     var result = method.Invoke(_instance, methodCall.Args); 
     return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); 
    } 

    var logContext = _logger.DebugTiming("[{0}] Execution time for {1}", className, methodName); 
    bool disposeLogContext = true; 
    try 
    { 
     _logger.DebugFormat("[{0}] Call method {1}", className, methodName); 
     //execute the method 
     //var result = method.Invoke(_instance, methodCall.Args); 
     object[] arg = methodCall.Args.Clone() as object[]; 
     var result = method.Invoke(_instance, arg); 

     //wait the task ends before log the timing 
     if (result is Task) { 
      disposeLogContext = false; 
      ((Task)result).ContinueWith(() => logContext.Dispose()); 
     } 

     return new ReturnMessage(result, arg, 0, methodCall.LogicalCallContext, methodCall); 
    } 
    finally 
    { 
     if (disposeLogContext) 
      logContext.Dispose(); 
    } 
} 

不要調用的任務等待() - 改變的行爲,並可能導致死鎖。

+0

謝謝,在我看來,這是一種優雅的方式來解決這個問題:) –

+0

出於好奇:如果變量中的任務發生異常,將調用logContext.Dispose() 'result'? – gogognome

+0

是的,無論如何,ContinueWith都能保證延續。 –