Search code examples
autofacnamed-instance

Autofac Named Services and Dynamic Instantiation not working


I have an object graph as,

Client -> Handler -> HandlerSettings

and my app has multiple Clients with different HandlerSettingss.

// instances
Client1 -> Handler1 -> HandlerSettings1
Client2 -> Handler2 -> HandlerSettings2
...

Autofac's dynamic instantiation for named services is not working. I can get it to work with just named services and skipping dynamic instantiation, but wanted to know why it fails and, what are my options?

For example, with,

    public class Depy1
    { }

    public class Class1
    {
        public Class1(Depy1 depy1)
        { }
    }

    public class Class2
    {
        public Class2(Func<Depy1> depy1) // dynamic instantiation
        { }
    }

and DI as,

    var named = "bork!";
    builder.RegisterType<Depy1>()
        .Named<Depy1>(named)
        .InstancePerDependency();

    builder.RegisterType<Class1>()
        .WithParameter(ResolvedParameter.ForNamed<Depy1>(named))
        .InstancePerDependency();

    builder.RegisterType<Class2>()
        .WithParameter(ResolvedParameter.ForNamed<Depy1>(named))
        .InstancePerDependency();

and resolution as,

    var class1 = container.Resolve<Class1>(); // works
    var class2 = container.Resolve<Class2>(); // throws!

the class2 resolution throws DependencyResolutionException as,

    Autofac.Core.DependencyResolutionException
      HResult=0x80131500
      Message=None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Example.Class2' can be invoked with the available services and parameters:
    Cannot resolve parameter 'System.Func`1[Example.Depy1] depy1' of constructor 'Void .ctor(System.Func`1[Example.Depy1])'.
      Source=Autofac
      StackTrace:
       at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
       at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
       at Autofac.Core.Resolving.InstanceLookup.Execute()
       at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
       at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
       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(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
       at Example.Program.<Showcase>d__2.MoveNext() in D:\work\client\samples\Example\Program.cs:line 175
       at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
       at Example.Program.<Main>d__0.MoveNext() in D:\work\client\samples\Example\Program.cs:line 34
       at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
       at Example.Program.<Main>(String[] args)

      This exception was originally thrown at this call stack:
        [External Code]
        Example.Program.Showcase(Autofac.IContainer, Microsoft.Extensions.Configuration.IConfigurationRoot) in Program.cs
        [External Code]
        Example.Program.Main(string[]) in Program.cs
        [External Code]        

Solution

  • When calling ResolvedParameter.ForNamed, you need to use the actual type in the constructor. That means that instead of ForNamed<Depy1>(...), you need to specify ForNamed<Func<Depy1>>(...), changing your registration of Class2 to:

      builder.RegisterType<Class2>()
            .WithParameter(ResolvedParameter.ForNamed<Func<Depy1>>(named))
            .InstancePerDependency();