Return wait Method.Invoke ()

I am a big fan of DRY coding and I like to avoid boiler plate code as much as possible. So I reworked my entire WCF channel into an AOP class that focuses on the WCF channel life cycle.

I am also a big fan of async waiting, especially with WCF, as it theoretically frees up a thread that will usually wait for a response.

So I created an interceptor in the 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; } } 

However, after thinking a little about the solution, I noticed that in the case of a WCF contract, the forms

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

GetInt will have unexpected results. First, catch FaultException will do nothing. Secondly, I would close the channel before the request returns. Theoretically, I could switch to a different code path if the return type has Task. But I cannot figure out how to wait for the results of Task <>, and then return the expected one.

This, of course, is especially difficult, since during the execution of AOP I would not have access to using generics of the return type (without a whole reflection).

Any ideas on how to implement this function as expected, which closes the channel on termination and catch / marshals exceptions for the calling thread?

+4
source share
1 answer

To complete the async injection, you will have to replace the returned task. To read the code, I recommend replacing it with the async method instead of using ContinueWith .

I am not familiar with fluentAOP, but I injected async using Castle DynamicProxy.

If you want to use reflection, then you must first determine if this is an async call (i.e. if the return type is a subclass or equal to typeof(Task) . If it is a async , then you will need to use reflection to pull T from Task<T> and apply it to your own async method:

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

An alternative is to use 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; } 
+6
source

All Articles