I have install IoC with Autofac and use AoP interceptors.
I usually use front-end interceptors registered as follows:
var builder = new ContainerBuilder(); builder.RegisterType<MyType>() .As<IMyType>() .UsingConstructor(new Type[0]) .EnableInterfaceInterceptors() .InterceptedBy(typeof(MyInterceptor));
And it works. But for certain reasons (not explicit in this minimal example) I need one class for registration and input as well as myself (not via the interface), so I try:
var builder = new ContainerBuilder(); builder.RegisterType<MyType>() .As<IMyType>() .AsSelf() .UsingConstructor(new Type[0]) .EnableClassInterceptors() .InterceptedBy(typeof(MyInterceptor));
In this setting, the interceptor never starts. When I test the injected dependency in debugging, it seems to be a subclass proxy (as it should be), but its private _interceptors property contains only one instance of Castle.DynamicProxy.StandardInterceptor , which is obviously not what I configured.
In fact, if I delete AsSelf() , it still doesn’t intercept, which leads me to the conclusion that either I am doing something wrong, or intercepting a class simply does not work ...?
UPDATE
MyType actually inherits from EF DbContext , and I'm trying to intercept SaveChanges() , which is virtual. Just for the test, I added public virtual void Foo() , which was also not intercepted.
UPDATE
I forgot about this before and simplified the important fact I missed: I specify UsingConstructor() in the registry. Now, I have empirically discovered that UsingConstructor() seems to prevent EnableClassInterceptors() from working.
Full registration I am currently using:
builder.RegisterType<FooClass>() .AsSelf() .InstancePerRequest() .EnableClassInterceptors() .UsingConstructor(new Type[0]) // commenting this out solves the issue .InterceptedBy(typeof(MyInterceptor)); public class FooClass { public virtual void Bar() { Debugger.Break(); } public FooClass() { } public FooClass(int i) { } }
Interceptor works for other injections; this is complex code, but I put a breakpoint at the beginning of the public void Intercept(IInvocation invocation) method.
Commenting on the choice of constructor, it works again.
I will award a reward to anyone who can give me a workaround, or at least a good explanation of why this does not work.
UPDATE
With your answers about the added constructor options, I explored this aspect and really:
Foo.GetType().GetConstructors() // Foo is injected, proxied instance of FooClass
really returns 3 constructors:
Void .ctor(Castle.DynamicProxy.IInterceptor[]) Void .ctor(Castle.DynamicProxy.IInterceptor[], Int32) Void .ctor()
This happens if I UseConstructor() or not. Coincidentally, the code did not drop for me; this would be if I specified a different constructor (and not without parameters).
Regardless, I tried the following registration:
builder.RegisterType<MyType>() .As<IMyType>() .AsSelf() .InstancePerRequest() .UsingConstructor(new[] { typeof(IInterceptor[]) }) .EnableClassInterceptors() .InterceptedBy(typeof(MyInterceptor));
... and, surprise, surprise! he fails with
No match constructor exists in type MyType
We dig further, changing the order of these freely used methods solves it ultimately, with full registration of work:
builder.RegisterType<MyType>() .As<IMyType>() .AsSelf() .InstancePerRequest() .EnableClassInterceptors() .UsingConstructor(new[] { typeof(IInterceptor[]) }) .InterceptedBy(typeof(MyInterceptor));
ESSENCE
I would consider that a bad API has what appears to be a free API, but at the same time it depends heavily on the order in which the fast methods are used. Even worse, he doesn’t actually quit, he just fails.
I would also think of poor design (leave only documentation) in order to require internal knowledge of proxy logic from users. Ideally, UseConstructor () should encapsulate the added fact of interceptors in the matching logic. However, I developed the API myself, and I know that it is easy to require, but it is difficult to deliver certain functions.
In any case, the case is closed, and I would like to hug you all. I believe that it was Jim Ball who gave the first exact answer, which led to a breakthrough, so that cookies go to him. Correct me if I am wrong.