我有一个使用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);
}
}
答案 0 :(得分:0)
我对ContextBoundObject
一无所知,但我认为AsyncProcessMessage()
与async
- await
无关,并且以下内容应该可以正常使用SyncProcessMessage()
:
Task
或ContinueWith()
将后处理步骤添加为返回的await
的续篇。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(), …);