return await Method.Invoke()

时间:2013-03-04 10:30:58

标签: c# aop async-await methodinfo

我是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;
        }
    }

但是,在考虑解决方案时,我注意到在表格的WCF合同的情况下

[ServiceContract]
public interface IFoo
{
    [OperationContract]
    Task<int> GetInt();
}

GetInt会有意想不到的结果。首先,catchException将无效。其次,我会在请求返回之前关闭通道。如果返回类型是Task,我理论上可以切换到另一个代码路径。但我无法弄清楚如何等待任务的结果&lt;&gt;然后返回一个等待的。

这当然特别困难,因为运行时AOP我无法访问能够使用返回类型的泛型(没有完整的反射)。

任何想法如何实现这个函数作为一个等待,它关闭完成的通道和捕获/编组调用线程的异常?

1 个答案:

答案 0 :(得分:7)

要进行async注射,您必须更换已退回的任务。为了代码可读性,我建议使用async方法替换它,而不是使用ContinueWith

我不熟悉fluentAOP,但我已经使用Castle DynamicProxy注入了async

如果你想使用反射,你要做的是首先确定它是否是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; } } 方法:

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; }

{{1}}