OnActivated() not working together with EnableInterfaceInterceptors()
See original GitHub issueI was struggling with some weird InvalidCastException nested inside a Autofac.Core.DependencyResolutionException in my application and after a few hours I could narrow the problem down to the following code:
using System;
using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
namespace AutofacTest
{
public interface IA
{
string Hello();
}
public class A : IA
{
public string Hello()
{
return "hello world!";
}
}
public class DummyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.Write("before ");
invocation.Proceed();
}
}
public class Program
{
static void Main(string[] args)
{
// Create your builder.
var builder = new ContainerBuilder();
builder.Register(a => new DummyInterceptor());
var r = builder.RegisterType<A>()
.As<IA>()
.OnActivated(a => Console.WriteLine( a.GetType().ToString() ))
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(DummyInterceptor));
var c = builder.Build();
var ia = c.Resolve<IA>();
Console.WriteLine(ia.Hello());
Console.ReadKey();
}
}
}
Autofac.Core.DependencyResolutionException occurred
HResult=0x80131500
Message=An exception was thrown while executing a resolve operation. See the InnerException for details.
Source=Autofac
StackTrace:
at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
at AutofacTest.Program.Main(String[] args) in ....\Projects\ConsoleApp2\ConsoleApp2\Program.cs:line 47
Inner Exception 1:
InvalidCastException: Unable to cast object of type 'Castle.Proxies.IAProxy' to type 'A'.
In the original code, I got a little bit deeper in Autofac code:
> Autofac.dll!Autofac.Builder.RegistrationBuilder<CCC.Scheduling.BusinessLayer.Services.StockpileBusinessService, Autofac.Builder.ConcreteReflectionActivatorData, Autofac.Builder.SingleRegistrationStyle>.OnActivated.AnonymousMethod__0(object s, Autofac.Core.ActivatedEventArgs<object> e) Unknown
Autofac.dll!Autofac.Core.Resolving.InstanceLookup.Complete() Unknown
Autofac.dll!Autofac.Core.Resolving.ResolveOperation.CompleteActivations() Unknown
Autofac.dll!Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(Autofac.Core.ISharingLifetimeScope currentOperationScope, Autofac.Core.IComponentRegistration registration, System.Collections.Generic.IEnumerable<Autofac.Core.Parameter> parameters) Unknown
Autofac.dll!Autofac.Core.Resolving.ResolveOperation.Execute(Autofac.Core.IComponentRegistration registration, System.Collections.Generic.IEnumerable<Autofac.Core.Parameter> parameters) Unknown
Autofac.dll!Autofac.ResolutionExtensions.TryResolveService(Autofac.IComponentContext context, Autofac.Core.Service service, System.Collections.Generic.IEnumerable<Autofac.Core.Parameter> parameters, out object instance) Unknown
Autofac.dll!Autofac.ResolutionExtensions.ResolveService(Autofac.IComponentContext context, Autofac.Core.Service service, System.Collections.Generic.IEnumerable<Autofac.Core.Parameter> parameters) Unknown
Autofac.dll!Autofac.ResolutionExtensions.Resolve<CCC.Scheduling.BusinessLayer.Interface.IStockpileBusinessService>(Autofac.IComponentContext context, System.Collections.Generic.IEnumerable<Autofac.Core.Parameter> parameters) Unknown
This problem seems to be related to the https://github.com/autofac/Autofac/blob/develop/src/Autofac/Builder/RegistrationBuilder{TLimit%2CTActivatorData%2CTRegistrationStyle}.cs class, in the onActivated()
method, the handler is called with a cast, like (TLimit)e.Instance)
, which seems unlikely to work with a interface proxy.
Using:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Autofac" version="4.6.0" targetFramework="net452" />
<package id="Autofac.Extras.DynamicProxy" version="4.2.1" targetFramework="net452" />
<package id="Castle.Core" version="4.0.0" targetFramework="net452" />
</packages>
I’m reluctant to believe I just found a bug in a very likely feature combination like this, but I couldn’t find any other reasonable explanation. Please let me know what you think about this.
If you need any extra info, please let me know! 😃
Issue Analytics
- State:
- Created 6 years ago
- Comments:9 (5 by maintainers)
Verified this works in v6.
I tried it with this quick C# script using the same code as in the original post:
The console output for this is:
The
Submission#0
is an artifact of C# script, since there’s no main program or namespace, that’s a generated one. Point is, it appears this works as expected.Hi, tillig! Thanks for the fast reply 😃
About being blocked, what I did here is to avoid adding the
OnActivated
handler when we don’t need to (we used to add an empty one in most of the cases just by convenience). Thank’s for the extension, though, we’ll definitely try it 😃About the actual issue, at first sight I thought the cast issue was happening on my handler, not inside Autofac, so I tried this:
It didn’t fix the problem, but I don’t think it’s a bad idea. Actually, I think this is the proper way to fix it since the handler registered with
OnActivated
is meant to run directly on the real instance, not being intercepted by any proxy and consequently not being affected by any custom behavior.What do you think?