5

I'm using Ninject Interceptor in order do some tasks before and after the actual method gets called but I need these operations to be asynchronous. I have take a look at the following article making-ninject-interceptors-work-with-async-methods and implement that async part, but now I'm missing one last piece and that is waiting / non-blocking wait for task to complete in Intercept method.

  • I can't use wait because I want this to be asynchronous non-blocking operation

    /// <summary>
    /// Intercepts the specified invocation.
    /// </summary>
    /// <param name="invocation">The invocation to intercept.</param>
    public void Intercept(IInvocation invocation)
    {
        Task<bool> resultTask = InterceptAsync(invocation);
        if (resultTask.Exception != null)
            throw new Exception("Exception.", resultTask.Exception.InnerException);
    }
    
    
    /// <summary>
    /// Intercepts the specified invocation.
    /// </summary>
    /// <param name="invocation">The invocation to intercept.</param>
    protected async Task<bool> InterceptAsync(IMyInvocation invocation)
    {
        await BeforeInvokeAsync(invocation);
        if (!invocation.Cancel)
        {
            invocation.Proceed();
            await AfterInvokeAsync(invocation);
        }
        return true;
     }
    
  • I have even tried to put the async on this method and I still have problems, probably with the fact this is a void method

    /// <summary>
    /// Intercepts the specified invocation.
    /// </summary>
    /// <param name="invocation">The invocation to intercept.</param>
    public async void Intercept(IInvocation invocation)
    {
        Task<bool> resultTask = InterceptAsync(invocation);
        await resultTask;
        if (resultTask.Exception != null)
            throw new Exception("Exception.", resultTask.Exception.InnerException);
    }
    

Is there a way to make this real async all the way method ?

Community
  • 1
  • 1
khorvat
  • 1,630
  • 2
  • 20
  • 31
  • I'm pretty sure NInject's current design just doesn't allow for asynchronous pre-execution, because `Proceed` *must* be called synchronously. I recommend you raise this issue with NInject support. – Stephen Cleary Jul 15 '13 at 21:19
  • To clarify, I mean `Proceed` must be called synchronously from `Intercept`. – Stephen Cleary Jul 15 '13 at 21:27
  • I'm not sure if I understand what you are saying, _Proceed must be called synchronously from Intercept_ do you mean this has to be called synchronously because Intercept is not designed (and the rest of interception) asynchronously ? BTW I have raised the question on Ninject Interception GitHub issues section yesterday so we will see what happens. – khorvat Jul 16 '13 at 07:27
  • 1
    Right. If you `await` before you call `Proceed`, then your method actually returns, and when you return, Intercept assumes that the call is done (pulls out `ReturnValue` etc). When your method resumes later, it will try to call `Proceed` long after Intercept has completed that call. So it can't work with the current design; Intercept would have to change to have a more WebAPI-like architecture to fully support asynchronous interception. – Stephen Cleary Jul 16 '13 at 12:04
  • Yup I thought so, thanks for insights. – khorvat Jul 16 '13 at 15:19
  • For Googlers, the GitHub issue is [here](https://github.com/ninject/ninject.extensions.interception/issues/17). – Stephen Cleary Jul 16 '13 at 16:13
  • One question regarding the [link](http://stackoverflow.com/questions/13630548/making-ninject-interceptors-work-with-async-methods) I'm trying to wait synchronously for _BeforeInvokeAsync_ & _AfterInvokeAsync_ without getting a deadlock, any ideas how to achieve that ? – khorvat Jul 16 '13 at 16:47
  • It's not possible in the general case. You can play tricks with `Task.Run` or whatnot, but there's no general solution short of rewriting NInject Intercept. – Stephen Cleary Jul 16 '13 at 16:56
  • Yes, I have been playing with Task.Run, Wait etc. I'll post a dirty fix if I find it. One other side note is that changing Ninject Intercept isn't enough as you need to change the dependent proxy library _LinFu_ or _Castle.Core DynamicProxy_. – khorvat Jul 16 '13 at 20:49

1 Answers1

2

I have been forced to hack my way out of this issue and I have changed few bits of code inside Ninject.Extensions.Interception to allow async/await.

I have just started testing the code and so far it seems that awaiting before Proceed is called is working. I'm not 100% sure that everything is working as expected because I need more time to play with this, so feel free to check out the implementation and get back to me if you find bugs or have suggestions.

https://github.com/khorvat/ninject.extensions.interception

IMPORTANT - this solution works only with LinFu DynamicProxy as LinFu generates proxy classes in way that can be used to allow asynchronous waiting.

Note: Again this solution is a "hack" and not the full asynchronous interception implementation.

Regards

khorvat
  • 1,630
  • 2
  • 20
  • 31