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):
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();
}
}
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;
}
}
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:
Autofac.Core.DependencyResolutionException: "An exception was thrown while activating MyProject.ViewModel.MainWindowViewModel."
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action
1 next) at Autofac.Core.Resolving.Middleware.SharingMiddleware.<>c__DisplayClass5_0.<Execute>b__0() at Autofac.Core.Lifetime.LifetimeScope.CreateSharedInstance(Guid id, Func
1 creator) at Autofac.Core.Lifetime.LifetimeScope.CreateSharedInstance(Guid primaryId, Nullable1 qualifyingId, Func
1 creator) at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action1 next) at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action
1 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, IEnumerable
1 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)
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)'."
at Autofac.Core.Activators.Reflection.ReflectionActivator.<>c__DisplayClass12_0.b__0(ResolveRequestContext ctxt, Action
1 next) at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action
1 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.
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);
}