Skip to content

Latest commit

 

History

History
111 lines (90 loc) · 4.36 KB

MethodInterceptors.md

File metadata and controls

111 lines (90 loc) · 4.36 KB

Method Interceptors

Someta supports method interceptors. What this means is that when you decorate your method with an implementation of one or both of IMethodInterceptor and IAsyncMethodInterceptor you can have your own code called instead. Both kinds allow you to call the original implementation via a provided delegate.

The reason we have two types of interfaces is that for async interceptors, there's a good chance you'll want to use await. Since await requires the return type of the interceptor method to return a Task, you have to have a separate implementation for async methods if you actually want to make use of await in your interceptor.

However, you are allowed to only implement IMethodInterceptor. If you don't also implement IAsyncMethodInterceptor then the Invoke method defined in IMethodInterceptor will be called for all methods, both async and non-async.

This interface has one method:

object Invoke(MethodInfo methodInfo, object instance, Type[] typeArguments, object[] arguments, Func<object[], object> invoker);

snippet source | anchor

Example

public void MethodExample()
{
    var testClass = new MethodTestClass();
    testClass.Method();
    Console.WriteLine(testClass.InvocationCount);     // Prints 1
}

class MethodTestClass
{
    [MethodInterceptor]
    public void Method()
    {
    }

    public int InvocationCount { get; set; }
}

[AttributeUsage(AttributeTargets.Method)]
class MethodInterceptor : Attribute, IMethodInterceptor
{
    public object Invoke(MethodInfo methodInfo, object instance, Type[] typeArguments, object[] arguments, Func<object[], object> invoker)
    {
        ((MethodTestClass)instance).InvocationCount++;
        return invoker(arguments);
    }
}

snippet source | anchor

This interface has one method:

Task<object> InvokeAsync(MethodInfo methodInfo, object instance, Type[] typeArguments, object[] arguments, Func<object[], Task<object>> invoker);

snippet source | anchor

Example

public async Task AsyncMethodExample()
{
    var testClass = new AsyncMethodTestClass();
    await testClass.AsyncMethod();
    testClass.InvocationCount.ShouldBe(1);
}

class AsyncMethodTestClass
{
    [AsyncMethodInterceptor]
    public async Task AsyncMethod()
    {
        await Task.Delay(0);        // Just to force await semantics
    }

    public int InvocationCount { get; set; }
}

[AttributeUsage(AttributeTargets.Method)]
class AsyncMethodInterceptor : Attribute, IAsyncMethodInterceptor
{
    public async Task<object> InvokeAsync(MethodInfo methodInfo, object instance, Type[] typeArguments, object[] arguments, Func<object[], Task<object>> invoker)
    {
        await Task.Delay(0);        // Just to demonstrate await semantics
        ((AsyncMethodTestClass)instance).InvocationCount++;
        return await invoker(arguments);
    }
}

snippet source | anchor