Aro*_*ron 5 c# aop methodinfo async-await
我是DRY编码的忠实粉丝,我喜欢尽可能避免使用锅炉板代码.因此,我将所有WCF频道faff重构为AOP类,该类处理WCF频道的生命周期.
我也是async-await的忠实粉丝,特别是对于WCF,因为它理论上可以释放一个通常在睡眠中等待响应的线程.
所以我在fluentAOP lib中创建了一个拦截器
private static object InvokeOnChannel(IMethodInvocation methodInvocation)
{
var proxy = _factory.CreateChannel();
var channel = (IChannel) proxy;
try
{
channel.Open();
var ret = methodInvocation.Method.Invoke(proxy, methodInvocation.Arguments);
channel.Close();
return ret;
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,在考虑解决方案时,我注意到在表格的WCF合同的情况下
[ServiceContract]
public interface IFoo
{
[OperationContract]
Task<int> GetInt();
}
Run Code Online (Sandbox Code Playgroud)
GetInt会有意想不到的结果.首先,catchException将无效.其次,我会在请求返回之前关闭通道.如果返回类型是Task,我理论上可以切换到另一个代码路径.但我无法弄清楚如何等待任务<>的结果然后返回等待.
这当然是特别困难的,因为运行时AOP我无法访问能够使用返回类型的泛型(没有整个反射).
任何想法如何实现这个功能作为一个等待,它关闭完整的通道和捕获/编组调用线程的异常?
要进行async注射,您必须更换返回的任务.为了代码可读性,我建议用async方法替换它而不是使用ContinueWith.
我不熟悉fluentAOP,但我已经完成async了Castle DynamicProxy的注入.
如果你想使用反射,你要做的是首先确定它是否是一个async调用(即,如果返回类型是一个子类或等于typeof(Task).如果它是一个async调用,那么你将需要使用反射拉T出来Task<T>,并把它应用到你自己的async方法:
private static MethodInfo handleAsync = ...; // point this to HandleAsync<T>
// Only called if the return type is Task/Task<T>
private static object InvokeAsyncOnChannel(IMethodInvocation methodInvocation)
{
var proxy = _factory.CreateChannel();
var channel = (IChannel) proxy;
try
{
channel.Open();
var task = methodInvocation.Method.Invoke(proxy, methodInvocation.Arguments) as Task;
object ret;
if (task.GetType() == typeof(Task))
ret = HandleAsync(task, channel);
else
ret = handleAsync.MakeGenericMethod(task.GetType().GetGenericParameters()).Invoke(this, task, channel);
return ret;
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task HandleAsync(Task task, IChannel channel)
{
try
{
await task;
channel.Close();
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task<T> HandleAsync<T>(Task task, IChannel channel)
{
try
{
var ret = await (Task<T>)task;
channel.Close();
return ret;
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用dynamic:
private static object InvokeOnChannel(IMethodInvocation methodInvocation)
{
var proxy = _factory.CreateChannel();
var channel = (IChannel) proxy;
try
{
channel.Open();
dynamic result = methodInvocation.Method.Invoke(proxy, methodInvocation.Arguments);
return Handle(result, channel);
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task Handle(Task task, IChannel channel)
{
try
{
await task;
channel.Close();
}
catch (FaultException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
throw;
}
catch(Exception)
{
channel.Abort();
throw;
}
}
private static async Task<T> Handle<T>(Task<T> task, IChannel channel)
{
await Handle((Task)task, channel);
return await task;
}
private static T Handle<T>(T result, IChannel channel)
{
channel.Close();
return result;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3676 次 |
| 最近记录: |