带有Async / Await的ContextBoundObject

时间:2013-11-28 01:08:27

标签: c# .net asynchronous aop async-await

我有一个使用AOP和ContextBoundObject的系统。

这用于拦截方法调用并在函数之前和之后执行某些操作。一切正常,直到我将'截获函数'设为异步。

据我所知,C#编译器将异步方法重写为状态机,一旦达到“等待”,就会将控制权返回到接收器 因此它继续进行拦截并执行仅在Method之后执行的代码。

我可以看到IMessageSink中有一个“AsyncProcessMessage”,但我找不到调用它的方法,我不确定它是否可以在async / await场景中工作。

有没有办法让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);
    }
}

1 个答案:

答案 0 :(得分:0)

我对ContextBoundObject一无所知,但我认为AsyncProcessMessage()async - await无关,并且以下内容应该可以正常使用SyncProcessMessage()

  1. 执行预处理步骤。
  2. 调用异步方法。
  3. 使用TaskContinueWith()将后处理步骤添加为返回的await的续篇。
  4. 将延续Task返回给来电者。
  5. 如果您对在线程池上执行的后处理没有问题,那么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(), …);