autofac / Autofac.Extras.DynamicProxy

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

Attempting to resolve intercepted types using class interceptors does not throw exception when a dependency is unmet #14

Closed jamesbascle closed 4 years ago

jamesbascle commented 7 years ago

I have a set of tests in place to ensure that all of my composition roots are able to be resolved. This has been working fine. I recently added a couple interceptors for logging and exception handling on my composition roots.

It would seem that even if a dependency is unmet, AutoFac will resolve the DynamicProxy and set null for any unmet dependencies, without throwing the standard Autofac.Core.Registration.ComponentNotRegisteredException. This causes the test to erroneously pass.

I commented out the interceptor registration, and the tests fail as expected.

jamesbascle commented 7 years ago

@alexmg @tillig I would like to submit a PR for this, but I'm having some trouble figuring out exactly where the exception should be thrown, and where to determine whether or not all parameters are satisfied.

I've looked into both the OnPreparing hooks and the ActivatingHandlers lists, but was unable to figure out how to access the constructor that Autofac/DynamicProxy intends to use in order to match that up with the parameters that are intended to be provided.

Could I get some guidance?

tillig commented 7 years ago

The real key will be figuring out two things:

  1. Under which interception circumstances does this issue occur?
  2. When does the component being intercepted actually get created?

To solve the first item, I added some unit tests. It looks like the interface interceptors actually do throw when there's a missing parameter, but class interceptors silently swallow it as you describe. That means you can focus attention on how class interceptors work rather than on every kind of interceptor.

Now to figure out the second part - when the actual component being intercepted is created/resolved. I haven't figured that out yet. This OnPreparing handler is where the actual proxy class gets created and a set of parameters get passed along to the class being intercepted, but from there I'm not entirely sure where it's happening. I see that interface interceptors use an ActivatingHandler instead of an OnPreparing handler and it may be that difference that is important - that maybe the class interception is happening too soon in the pipeline. I haven't dug into why that difference exists.

So that's where I'd start - figure out if changing the OnPreparing to an Activating handler will still allow tests to pass but also throw if there are missing parameters. I'd also start stepping into the code to figure out when exactly the component being intercepted gets created and how.

RaymondHuy commented 4 years ago

@alistairjevans This bug has already been fixed. We can close it now ;)

alistairjevans commented 4 years ago

Thanks @RaymondHuy. 🎉