2016-03-03 153 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都能保证延续。 –