Search code examples
c#autofacautofac-configuration

Autofac.Core.DependencyResolutionException: Expression of type '' cannot be used for return type 'System.Object' in Autofac 6.2


I have the code here, that used to work in Autofac 2.6, but now no longer works in Autofac 6.2:

class Program
{
    static void Main(string[] args)
    {
        Holder holder = null;

        Build(c =>
        {
            holder = new Holder() { Verifiers = c.Resolve<Verifiers>() };
        });
        var res = holder.Verifiers;
        Console.WriteLine("Success");
    }

    private static void Build(Action<IContainer> container)
    {
        var builder = new ContainerBuilder();
        builder.RegisterAssemblyTypes(typeof(Verifiers).Assembly).AsSelf().AsImplementedInterfaces();

        builder.RegisterType<ConsoleOutput>().As<IOutput>();
        builder.RegisterGeneric(typeof(EntityDisplay<>.Params));
        builder.RegisterGeneric(typeof(EntityDisplayFactory<,>));
        builder.Register<Func<DisplayFactories>>(c => () => new DisplayFactories() { Instances = c.Resolve<IEntityDisplayFactory<object>>() });
        container(builder.Build());
    }

}

public interface IOutput
{
    void Write(string content);
}

public class ConsoleOutput : IOutput
{
    public ConsoleOutput()
    {
    }
    public void Write(string content)
    {
        Console.WriteLine(content);
    }
}

public interface IEntityDisplay
{
    void Display(object parameter);
}

public class EntityDisplay<T> : IEntityDisplay
{
    public struct Params
    {
        private readonly IOutput _output;
        public Params(IOutput output)
        {
            _output = output;
        }
    }

    private readonly T _entity;
    public EntityDisplay(T entity)
    {
        _entity = entity;
    }
    public void Display(object parameter)
    {
    }
}

public interface IEntityDisplayFactory<in T>
{
    IEntityDisplay Create(T entity);
}

public class InstanceEntityDisplayFactory : EntityDisplayFactory<object, object>
{
    public InstanceEntityDisplayFactory(EntityDisplay<object>.Params parameters) : base(parameters)
    {
    }
}

public class EntityDisplayFactory<T, I> : IEntityDisplayFactory<T>
{
    private readonly EntityDisplay<T>.Params _param;
    public EntityDisplayFactory(EntityDisplay<T>.Params parameters)
    {
        _param = parameters;
    }
    public IEntityDisplay Create(T entity)
    {
        return new EntityDisplay<T>(entity);
    }
}

public class DisplayFactories
{
    public IEntityDisplayFactory<object> Instances { get; set; }
}

public class Verifiers
{
    private readonly DisplayFactories _displayFunc;
    public Verifiers(Func<DisplayFactories> displayFunc)
    {
        _displayFunc = displayFunc();
    }

    public void Show()
    {
        DisplayFactories res = _displayFunc;
        res.Instances.Create(null);
    }
}

public class Holder
{
    public Verifiers Verifiers { get; set; }
}

The exception that throws in Autofac 6.2 is

> Autofac.Core.DependencyResolutionException   HResult=0x80131500  
> Message=An exception was thrown while activating
> AutofacTest46.InstanceEntityDisplayFactory.   Source=Autofac  
> StackTrace:    at
> Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext
> context, Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.Middleware.RegistrationPipelineInvokeMiddleware.Execute(ResolveRequestContext
> context, Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext
> context, Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.Middleware.ScopeSelectionMiddleware.Execute(ResolveRequestContext
> context, Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext
> context, Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope
> currentOperationScope, ResolveRequest request)    at
> Autofac.Core.Resolving.Pipeline.DefaultResolveRequestContext.ResolveComponent(ResolveRequest
> request)    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
> AutofacTest46.Program.<>c__DisplayClass1_0.<Build>b__1() in D:\.net
> Samples project\May 2021\AutofacTest46\Program.cs:line 34    at
> AutofacTest46.Verifiers..ctor(Func`1 displayFunc) in D:\.net Samples
> project\May 2021\AutofacTest46\Outputs.cs:line 94    at
> Autofac.Core.Activators.Reflection.BoundConstructor.Instantiate()
> 
>   This exception was originally thrown at this call stack:
>     [External Code]
> 
> Inner Exception 1: ArgumentException: Expression of type
> 'AutofacTest46.EntityDisplay`1+Params[System.Object]' cannot be used
> for return type 'System.Object'
  1. Why is this happening in Autofac 6.2?
  2. How to solve this error?

Solution

  • The problem is that EntityDisplay<>.Params is a value type - a struct. Change it to a class and you'll be fine.

    Due to the way DI and reflection and whatnot all currently come together, we have to be able to cast the output of a reflection-based operation to an object. You can see the current wire-up code here. Unfortunately, the constructor invoker for a value type doesn't return an object so we can't resolve it and everything falls apart.

    We'd likely accept a pull request with fix-up code for that, however DI into value types isn't usually something folks do.

    Anyway, switch to class and it works.

    As an aside, this was sort of difficult to walk through - in future questions it might help to reduce the repro a bit (e.g., you don't need the Holder class at all, it's just noise; you don't need the Verifiers, etc. Getting a cleaner format on the exception message in the question would also help, and be sure all the inner exceptions are included. The big key was the inner exception pointing at the constructor invoker. I was only able to see it by copy/pasting this code in and debugging, which, unfortunately, I normally don't have time to do. I'd have had to pass on answering this one otherwise.