2013-11-28 119 views
5

我有一个使用AOP和ContextBoundObject的系统。ContextBoundObject与异步/等待

这是用来拦截方法调用,并在函数前后执行某些操作。这一切工作正常,直到我让'拦截功能'异步。

我知道C#编译器将异步方法重写为一个状态机,一旦达到'await'就会将控制权返回到接收器 因此,它继续截取并执行仅用于执行的代码方法之后。

我可以看到IMessageSink中有一个“AsyncProcessMessage”,但我找不到调用它的方法,我不确定它是否可以在异步/等待方案中工作。

有没有办法使Async/Await与ContextBoundObject一起工作?在这里唯一的选择是使用另一个面向方面编程方法吗?

下面的代码示例具有用'Audit'属性装饰的方法,并放入AuditFacade(ContextBoundObject)中。 AuditSink中的SyncProcessMessage方法具有在方法之前和之后执行的逻辑。

[AuditBoundary] 
public class AuditFacade : ContextBoundObject 
{ 
    [Audit] 
    public ResponseObject DoSomthing() 
    { 
     //Do something 
     return new ResponseObject(); 
    } 

    /// <summary> 
    /// Async Method to be intercepted 
    /// </summary> 
    /// <returns></returns> 
    [Audit] 
    public async Task<ResponseObject> DoSomthingAysnc() 
    { 
     //Do something Async 
     await Task.Delay(10000); 
     return new ResponseObject(); 
    } 
} 

[AttributeUsage(AttributeTargets.Method)] 
public class AuditAttribute : Attribute 
{ 
} 

[AttributeUsage(AttributeTargets.Class)] 
public class AuditBoundaryAttribute : ContextAttribute 
{ 
    public AuditBoundaryAttribute() 
     : base("AuditBoundary" + Guid.NewGuid().ToString()) 
    { 
    } 
    public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg) 
    { 
     ctorMsg.ContextProperties.Add(new AuditProperty()); 
    } 
} 

public class AuditProperty : IContextProperty, IContributeObjectSink 
{ 
    public string Name 
    { 
     get { return "AuditProperty"; } 
    } 

    public bool IsNewContextOK(Context newCtx) 
    { 
     var p = newCtx.GetProperty("AuditProperty") as AuditProperty; 

     if (p == null) 
      return false; 

     return true; 
    } 

    public void Freeze(Context newContext) 
    { 
    } 

    public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink) 
    { 
     return new AuditSink(nextSink); 
    } 

} 

public class AuditSink : IMessageSink 
{ 
    private IMessageSink nextSink; 

    public AuditSink(IMessageSink nextSink) 
    { 
     this.nextSink = nextSink; 
    } 

    public IMessage SyncProcessMessage(IMessage msg) 
    { 
     var message = msg as IMethodCallMessage; 

     IMethodReturnMessage returnMessage = null; 
     ResponseObject response; 

     //Some Pre Processing happens here 
     var newMessage = new MethodCallMessageWrapper(message); 

     //Invoke the Method to be Audited 
     returnMessage = nextSink.SyncProcessMessage(newMessage) as IMethodReturnMessage; 
     response = returnMessage.ReturnValue as ResponseObject; 

     //Some Post Processing happens here with the "response" 
     return returnMessage; 
    } 

    public IMessageSink NextSink 
    { 
     get { return this.nextSink; } 
    } 
    public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) 
    { 
     return nextSink.AsyncProcessMessage(msg, replySink); 
    } 
} 

回答

0

我不知道ContextBoundObject什么,但我认为AsyncProcessMessage()无关与async - await和其后面的工作,应该用正常SyncProcessMessage()

  1. 做你的预处理步骤。
  2. 调用异步方法。
  3. 使用ContinueWith()await将您的后处理步骤作为对返回的Task的延续添加。
  4. 将返回Task返回给调用者。

如果你在线程池中执行的后处理没问题,那么ContinueWith()可能更简单。如果您需要在原始上下文中执行后处理,请使用await

await版本看起来是这样的:

var responseTask = (Task<ResponseObject>)returnMessage.ReturnValue; 

Func<Task<ResponseObject>> postProcessTaskFunc = async() => 
{ 
    var response = await responseTask; 
    // Some Post Processing happens here with the "response" 
    return response; 
} 

return new ReturnMessage(postProcessTaskFunc(), …);