Search code examples
c#autofaccastle-dynamicproxy

Autofac method level interception with Castle DynamicProxy in .NET Core 2


I currently wrote an Interceptor which code is below

public class TransactionalInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        using (var transaction = ...)
        {
            try
            {
                invocation.Proceed();
                transaction.Commit();

            }
            catch
            {
                transaction.Rollback();
            }
            finally
            {
                transaction.Dispose();
            }
        }

    }
}

but when register this interceptor it will apply to all methods. I have a service class with a repository injected having CRUD methods. I don't want a transaction to be opened for query methods.

I read this link but I cannot figure out how to apply it to my code http://docs.autofac.org/en/latest/advanced/adapters-decorators.html#decorators

I don't know who to refactor my TransactionalInterceptor (and register it) to use it in a class like this code

[Intercept(typeof(LoggerInterceptor))] //logger
public class SomeService : ISomeService
{
    private readonly ISomeRepository someRepository;

    public SomeService(SomeRepository someRepository)
    {
        this.someRepository = someRepository;
    }

    public IEnumerable<SomeDto> GetAll()
    {
        // code
    }

    public SomeDto GetById()
    {
        // code
    }

    [Transactional]
    public int Create(SomeDto someDto)
    {
        // code to insert
    }
}

Solution

  • The invocation parameter of the Intercept method contains a Method property which is a MethodInfo of the method currently intercepted.

    You can use this property to do what you want.

    For example by using the method name :

    public void Intercept(IInvocation invocation)
    {
        if (invocation.MethodInvocationTarget.Name != nameof(ISomeService.Create))
        {
            invocation.Proceed();
            return;
        }
        using (var transaction = ...)
        {
            try
            {
                invocation.Proceed();
                transaction.Commit();
            }
            catch
            {
                transaction.Rollback();
            }
            finally
            {
                transaction.Dispose();
            }
        }
    }
    

    or based on an attribute from the target method :

    if (!invocation.MethodInvocationTarget
                   .CustomAttributes
                   .Any(a => a.AttributeType == typeof(TransactionalAttribute)))
    

    You can also use the IInterceptorSelector type but it requires more work to register it with Autofac