autofac / Autofac.Extras.DynamicProxy

Interceptor and decorator support for Autofac IoC via Castle DynamicProxy
MIT License
106 stars 33 forks source link

Provided example with typed interceptor is not working #22

Closed JackGrinningCat closed 6 years ago

JackGrinningCat commented 6 years ago

Hi,

I tried to intercept an interface and parts of the the example provided here (create-interceptors)

I tried this yesterday and was confused as it seems widely used, documented but not working in my code. I already doubt my code until I tried to use the provided code in the example to make an test. I even tried to clone this repository to find an appropriate test, which would had helped me, to find out how to do it, but I could not build the solution directly from visual studio 2017. As I did recently installed my PC, it lacks some build tools.

So I made an test project. EnableInterfaceInterceptor.zip

It includes the packages.config and the code but which is not more than following.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Autofac" version="4.6.2" targetFramework="net461" />
  <package id="Autofac.Extras.DynamicProxy" version="4.2.1" targetFramework="net461" />
  <package id="Castle.Core" version="4.0.0" targetFramework="net461" />
  <package id="NUnit" version="3.9.0" targetFramework="net461" />
  <package id="NUnit3TestAdapter" version="3.9.0" targetFramework="net461" />
</packages>
tillig commented 6 years ago

You missed the rest of the instructions, where it says you have to tie interceptors to the things being intercepted. You can...

Name the CallLogger interceptor and tie the interface to it using a name:

builder.Register(c => new CallLogger(Console.Out))
       .Named<IInterceptor>("log-calls");

[Intercept("log-calls")]
public class SomeType

Or you can use typed interceptors:

builder.Register(c => new CallLogger(Console.Out));

[Intercept(typeof(CallLogger)]
public class SomeType

Or you can do it all through Autofac registration:

builder.RegisterType<SomeType>()
       .EnableInterfaceInterceptors()
       .InterceptedBy(typeof(CallLogger));
builder.Register(c => new CallLogger(Console.Out));
Darkbish commented 6 years ago

Hi, Interface intercept worked, but class intercept does not work.

    public class UserService
    {
        public int Add()
        {
            Console.WriteLine("AddUser");
            return 1;
        }
    }
    public class RedisInterceptor : IInterceptor
    {
        private TextWriter writer;

        public RedisInterceptor(TextWriter writer)
        {
            this.writer = writer;
        }

        public void Intercept(IInvocation invocation)
        {
            writer.WriteLine("Before Proceed");
            invocation.Proceed();
            invocation.ReturnValue = 3;
            writer.WriteLine("After Proceed");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<UserService>()
                .EnableClassInterceptors()
                .InterceptedBy(typeof(RedisInterceptor));
            builder.Register(d => new RedisInterceptor(Console.Out));
            var container = builder.Build();
            var service = container.Resolve<UserService>();
            var ret = service.Add();
            System.Console.WriteLine(ret);
        }
    }

The output is:

AddUser 1

tillig commented 6 years ago

You might want to run through the docs again:

... EnableClassInterceptors() dynamically subclasses the target component to perform interception of virtual methods.

Make Add virtual.

Darkbish commented 6 years ago

got it. thx

JackGrinningCat commented 6 years ago

Thanks @tillig, as i saw your answer it just came over me. Maybe those following three sentences lead me to in the wrong direction, that specializing the type or give it a name is just for the more complex cases. But I have to agree such behavior would maybe lead to very magic-linking behavior.


> // Typed registration
> builder.Register(c => new CallLogger(Console.Out));
> ```
> Enable Interception on Types
> -
> When you register a type being intercepted, you have to mark the type at registration time so Autofac knows to wire up that interception.