Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async method support in IInterceptionBehaviour #16

Open
wilversings opened this issue Jun 21, 2018 · 10 comments
Open

Async method support in IInterceptionBehaviour #16

wilversings opened this issue Jun 21, 2018 · 10 comments
Labels
Enhancement 🔨 Improvement of existing features
Milestone

Comments

@wilversings
Copy link

My usecase is that I'm trying to implement entry/exit/exception logging on an async method.
I an IInterceptionBehavoiur implementation, the call to getNext()(...) is performed asynchronously and I don't get to log the exit of the funciton.

@ENikS
Copy link
Contributor

ENikS commented Jun 21, 2018

Unity as of now does not do anything asynchronously. Can you provide more info?

@wilversings
Copy link
Author

In case of an awaitable target of the interception, I should be able to await the result in the IInterceptionBehavior.Invoke. Should I provide a more elaborate example?

@ENikS
Copy link
Contributor

ENikS commented Jun 21, 2018

Please do

@wilversings
Copy link
Author

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Unity;
using Unity.Interception.ContainerIntegration;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.Interceptors.InstanceInterceptors.InterfaceInterception;
using Unity.Interception.PolicyInjection.Pipeline;

namespace Program
{
    public class Program
    {
        public static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer().AddNewExtension<Interception>();
            container.RegisterType<IInterface, ConcreteClass>(
                new Interceptor<InterfaceInterceptor>(),
                new InterceptionBehavior<InterceptBehavior>());
            var myInterface = container.Resolve<IInterface>();
            myInterface.Method().Wait();
        }
    }

    public interface IInterface
    {
        Task Method();
    }

    public class ConcreteClass : IInterface
    {
        public async Task Method()
        {
            await Task.Delay(1000);
            Console.WriteLine("Method Called");
            await Task.Delay(1000);
        }
    }

    public class InterceptBehavior : IInterceptionBehavior
    {
        public bool WillExecute => true;

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("Before the call");
            var result = getNext()(input, getNext);

            Console.WriteLine("After the call");

            return result;
        }
    }
}

The output of this will be

Before the call
After the call
Method called

Because ConcreteClass's Method is async, and currently there is no way to await the result in the InterceptBehavior's Invoke method.

Even though I can work around that, with:

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("Before the call");
            var result = getNext()(input, getNext);

            if (result.ReturnValue is Task res)
            {
                result.ReturnValue = res.ContinueWith(_ => Console.WriteLine("After the call"));
            }
            else
            {
                Console.WriteLine("After the call");
            }
            return result;
        }

it still feels like the async targets could be supported by the library.

@ENikS
Copy link
Contributor

ENikS commented Jun 21, 2018

You are not alone in this thought.
The support for async is in preliminary stages of development

@ArnaudB88
Copy link

ArnaudB88 commented Jun 27, 2018

More information on how it can be handled at the moment:
https://msdn.microsoft.com/en-us/magazine/dn574805.aspx

Code download:
https://msdn.microsoft.com/magazine/msdnmag0214

  • One option to implement default support for async interception is a separate interceptor for sync and async method calls. The existing code can remain, and a new 'IAsyncInterceptionBehaviour' oid can be added. Core unity logic should choose the correct interceptor based on the method's type.
    Minor disadvantage: registering an interface with both async and sync methods would then have two interceptionBehaviours.
    An example of this can be found in the structureMap library:
    http://structuremap.github.io/dynamic-interception/

  • Other option is expanding the current InterceptionBehaviour with an extra InvokeAsync() method. Minor disadvantage: that will force the users to change their existing implementations (adding impl. for the async method).
    Advantage: registering an interface with both async and sync method will not change.

Edit:
Note on the code download: remove the 'configureAwait(false)' from the code, because that will lose the httpContext. If some logging is done afterwards which uses the DI container for eg. logging the username of the current user, and the DI container uses the HttpContext, an error occurs.

@ENikS ENikS added the Enhancement 🔨 Improvement of existing features label Sep 1, 2018
@ENikS ENikS added this to the 6.0.0 milestone Sep 1, 2018
@ArnaudB88
Copy link

Hi, what's the progress of this feature?
Thx!

@ENikS
Copy link
Contributor

ENikS commented Oct 23, 2018

Still in development

@kajbonfils
Copy link

Can you provide a new status? Still in dev? Any ideas on when to expect this to be ready?

@ENikS
Copy link
Contributor

ENikS commented Aug 21, 2019

The optimistic prognosis would be sometime in September

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement 🔨 Improvement of existing features
Projects
None yet
Development

No branches or pull requests

4 participants