c# - Create an exception-converting dynamic proxy that works with tasks -


problem

i'm somehow running in circles... try create interface proxy target using castle dynamic proxy. proxy should

  • return return value of invocation if no exception thrown (i.e. nothing).
  • throw new interceptedexception if invocation throws invalidoperationexception.
  • throw e if invocation throws exception e.

in other words, interceptor should catch , convert specific exception type, , not intercept in other cases.

i got working synchronous methods. however, need same behavior async methods return task.

what tried

i tried adding continuation returned task , inspect isfaulted , exception (similar this answer. works methods return task, not methods return task<t> since continuation of type task (and don't know t in interceptor).

tests covers 3 cases described above async methods (xunit.net)

public class convertnotfoundinterceptortest {     [fact]     public void non_throwing_func_returns_a_result()     {         assert.equal(43, runtest(i => + 1));     }      [fact]     public void invalidoperationexceptions_are_converted_to_indexoutofrangeexceptions()     {         var exception = assert.throws<aggregateexception>(() => runtest(i => { throw new invalidoperationexception("ugh"); }));         assert.true(exception.innerexception indexoutofrangeexception);     }      [fact]     public void other_exceptions_are_preserved()     {         var exception = assert.throws<aggregateexception>(() => runtest(i => { throw new argumentexception("ugh"); }));         assert.true(exception.innerexception argumentexception);     }      private static int runtest(func<int, int> func)     {         var generator = new proxygenerator();          var proxiedsubject = generator.createinterfaceproxywithtarget<isubject>(new subject(func), new convertnotfoundinterceptor());          return proxiedsubject.doasync(42).result;     }      public interface isubject     {         task<int> doasync(int input);     }      public class subject : isubject     {         private readonly func<int, int> _func;          public subject(func<int, int> func)         {             _func = func;         }          public async task<int> doasync(int input)         {             return await task.run(() => _func(input));         }     } } 

interceptor

public class convertnotfoundinterceptor : iinterceptor {     public void intercept(iinvocation invocation)     {         invocation.proceed();          var task = invocation.returnvalue task;         if (task != null)         {             var continuation = task.continuewith(                 t =>                 {                     if (t.exception != null && t.exception.innerexception invalidoperationexception)                     {                         throw new indexoutofrangeexception();                     }                 }, taskcontinuationoptions.onlyonfaulted);              // following line fails (invalidcastexception: unable cast object              // of type 'system.threading.tasks.continuationtaskfromtask'              // type 'system.threading.tasks.task`1[system.int32]'.)             invocation.returnvalue = continuation;         }     } } 

note implementation shown here not consider synchronous cases. left part out intentionally.

question

what correct way add above interception logic asynchronous methods?

ok, doesn't work task<dynamic> because castle dynamic proxy requires returnvalue exact matching type. however, can accomplish elegantly using dynamic dispatch:

public class convertnotfoundinterceptor : iinterceptor {     public void intercept(iinvocation invocation)     {         invocation.proceed();          var task = invocation.returnvalue task;         if (task != null)             invocation.returnvalue = convertnotfoundasync((dynamic)task);     }      private static async task convertnotfoundasync(task source)     {         try         {             await source.configureawait(false);         }         catch (invalidoperationexception)         {             throw new indexoutofrangeexception();         }     }      private static async task<t> convertnotfoundasync<t>(task<t> source)     {         try         {             return await source.configureawait(false);         }         catch (invalidoperationexception)         {             throw new indexoutofrangeexception();         }     } } 

i prefer async/await syntax because handle edge cases tricky using continuewith.


Comments

Popular posts from this blog

javascript - Google App Script ContentService downloadAsFile not working -

javascript - Function overwritting -

php - Find a regex to take part of Email -