question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

OnActivated() not working together with EnableInterfaceInterceptors()

See original GitHub issue

I 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:closed
  • Created 6 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
tilligcommented, Oct 7, 2020

Verified this works in v6.

I tried it with this quick C# script using the same code as in the original post:

#!/usr/bin/env dotnet-script
#r "nuget:Autofac, 6.0.0"
#r "nuget:Autofac.Extras.DynamicProxy, 6.0.0"

using System;
using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;

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();
    }
}

var builder = new ContainerBuilder();

builder.Register(a => new DummyInterceptor());

var r = builder.RegisterType<A>()
    .As<IA>()
                          // Changed to a.Instance to get better info.
    .OnActivated(a => Console.WriteLine(a.Instance.GetType().ToString()))
    .EnableInterfaceInterceptors()
    .InterceptedBy(typeof(DummyInterceptor));

var c = builder.Build();

var ia = c.Resolve<IA>();

Console.WriteLine(ia.Hello());

The console output for this is:

Submission#0+A
before hello world!

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.

1reaction
bcmedeiroscommented, Jul 11, 2017

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:

 r.OnActivated(a =>
	{
		if (ProxyUtil.IsProxy(a.Instance))
			{
				init((Impl) ProxyUtil.GetUnproxiedInstance(a.Instance));
			}
			else
			{
				init(a.Instance);
			} 
	});

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?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Autofac Interception Not Working
Build() from the Interceptor.Configure() method. That will actually throw an exception on trying to build the container a second time.
Read more >
[Solved]-Autofac global interface interceptor with Autofac ...
The idea is to override the Autofac Activating event and create the DynamicProxy manually. Most of the work here is making sure we...
Read more >
Autofac Documentation
This TodayWriter is where it all comes together. // Notice it takes a constructor parameter of type. // IOutput - that lets the...
Read more >
Release 3.3 Autofac Contributors
Autofac is an addictive IoC container for Microsoft .NET 4.5, Silverlight 5, Windows Store apps, and Windows Phone.
Read more >
Release 4.0 Autofac Contributors
The basic pattern for integrating Autofac into your application is: • Structure your app with inversion of control (IoC) in mind.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found