Search code examples
c#exceptiondependency-injectionautofac

Autofac.Core.Registration.ComponentNotRegisteredException even the interface seems to be registered


I try to implement a WPF application using dependency injection and the MVVM pattern using the frameworks "CommunityFramework.MVVM" and "Autofac".

What I have so far is the the following(shows only the required parts):

  • in Main Project. Namespace: .UI.WPF
public class App : Application
{
    private IContainer _container;

    public App()
    {
        _builder = new ContainerBuilder();
        var assembly = Assembly.GetAssembly(typeof(Installer));
        string fullPath = assembly!.Location;
        string dir = Path.GetDirectoryName(fullPath)!;

        _builder.RegisterAssemblyModules(assembly);

        var assemblyPath = Path.Combine(dir, "ViewModel.dll");
        Debug.Assert(File.Exists(assemblyPath));
        assembly = Assembly.LoadFile(assemblyPath);
        _builder.RegisterAssemblyModules(assembly);

         assemblyPath = Path.Combine(dir, "Model.dll");
         Debug.Assert(File.Exists(assemblyPath));
         assembly = Assembly.LoadFile(assemblyPath);
         builder.RegisterAssemblyModules(assembly);

         _container = _builder.Build();
    }
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var start = _container?.Resolve<IShell<IMainWindow>>();
        // HERE the Exception occcures !!!
        var workSpace = _container?.Resolve<IMainWindowViewModel>();

        ....
    }
}

public interface IShell<T> where T:class
{
    // some defines here
}

public class Shell : IShell<IMainWindow>
{
    public Shell()
    {
        // some initialization here
    }
}
public class Installer : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        // Shell
        object ret = builder.RegisterType<Shell>()
            .As<IShell<IMainWindow>>()
            .SingleInstance();

        // Messanger
        builder.Register(_ => MessageListener.Listen().Messenger)
            .As<IMessenger>()
            .SingleInstance();
    }
}
  • in Project ViewModel: Namespace: .ViewModel
public class Installer : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        // MainWindowViewModel
        builder.RegisterType<MainWindowViewModel>()
            .As<IMainWindowViewModel>()
        .    SingleInstance();
    }
}

public interface IMainWindowViewModel
{
    // some entries here
}

public class MainWindowViewModel : ObservableRecipient, IMainWindowViewModel
{
    private IMessenger _messenger;
    private IMyProjectData_data;

    public MainWindowViewModel(IMyProjectDatadata, IMessenger messenger)
        : base(messenger)
    {
        _data = data;
        _messenger = messenger;
    }
}

  • in Project Model: Namespace: .Models
public class Installer : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        // Foto-Renamer Data
        builder.RegisterType<MyProjectData>()
            .As<IMyProjectData>()
            .SingleInstance();

        // Setings
        builder.RegisterType<Settings>()
            .As<ISettings>().
            SingleInstance();
    }
}

public interface IMyProjectData
{
    // some entries here
}

public partial class MyProjectData : ObservableObject, IMyProjectData
{
    private ISettings _settings;

    public MyProjectData(ISettings settings)
    {
        _settings = settings;
        // more initialization here
    }
}

public interface ISettings
{
    // some entries here
}

public class Settings : ISettings
{
    private IShell<IWindow> _shell;

    public Settings(IShell<IMainWindow> shell)
    {
        _shell = shell;
        //more initializations here
    }
}

At the marked Point i get the following exeption:

EDIT:

Exception:

Autofac.Core.DependencyResolutionException: "An exception was thrown while activating MyProject.ViewModel.MainWindowViewModel."

Stack trace:

at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action1 next) at Autofac.Core.Resolving.Middleware.SharingMiddleware.<>c__DisplayClass5_0.<Execute>b__0() at Autofac.Core.Lifetime.LifetimeScope.CreateSharedInstance(Guid id, Func1 creator) at Autofac.Core.Lifetime.LifetimeScope.CreateSharedInstance(Guid primaryId, Nullable1 qualifyingId, Func1 creator) at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action1 next) at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action1 next) at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request) at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest request) at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable1 parameters, Object& instance) at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable1 parameters) at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters) at MyProject.UI.WPF.App.OnStartup(StartupEventArgs e) in F:\Projects\MyProject\UI\MyProject.UI.WPF\App.xaml.cs: Zeile64 at System.Windows.Application.<.ctor>b__1_0(Object unused) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.DispatcherOperation.InvokeImpl() at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state) at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

Inner exeption:

Autofac.Core.DependencyResolutionException: "None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyProject.ViewModel.MainWindowViewModel' can be invoked with the available services and parameters: Cannot resolve parameter 'MyProject.Model.Interfaces.IMyProjectData data' of constructor 'Void .ctor(MyProject.Model.Interfaces.IMyProjectData, CommunityToolkit.Mvvm.Messaging.IMessenger)'."

Stack trace inner exception:

at Autofac.Core.Activators.Reflection.ReflectionActivator.<>c__DisplayClass12_0.b__0(ResolveRequestContext ctxt, Action1 next) at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action1 next) at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)

I checked that all three "Installer"-classes are reached and the registration is executed properly. At the point of the exception I tryed the container: All servicec can be resolved, expected:

_container.Resolve<IMyProjectData>() and

_container.Resolve<ISettings>() (this is required as parameter for IMyProjectData.ctor)

Can anybody see why the exception raises? It seems I'm blind for the moment! Thank you in advance for your response.


Solution

  • The problem is that you have 2 instances of FotoRenamer.Model.dll loaded.

    If you set a breakpoint on the faulting line and then open Debug->Windows->Modules you will see it. It's caused by loading the assemblies with Assembly.LoadFile(). The assemblies loaded this way are loaded into different load context (see https://learn.microsoft.com/en-us/dotnet/framework/deployment/best-practices-for-assembly-loading?source=recommendations for details about load contexts).

    Since all assemblies are referenced by the main project you don't need to load them. The fix is simple:

        public static void InstallAutofac(ContainerBuilder builder)
        {
            var assembly = Assembly.GetAssembly(typeof(Installer));
            builder.RegisterAssemblyModules(assembly);
    
            assembly = Assembly.GetAssembly(typeof(ViewModel.Installer));
            builder.RegisterAssemblyModules(assembly);
    
            assembly = Assembly.GetAssembly(typeof(Model.Installer));
            builder.RegisterAssemblyModules(assembly);
        }