I'm writing a program that is container for other, smaller programs. It loads it's modules via Assembly.Load, finds types implementing IModule and makes instances of them.
In WPF MainWindow I have a RoutedViewHost, which will display everything.
In my AppBoostrapper, I have the following:
private ReactiveList<IModule> LoadModules(IMutableDependencyResolver resolver)
{
var modules = ModuleLoader.Load(ModulesDirectory);
// var modules = new IModule[] { new SampleModuleClass(), }; // this works perftectly!
foreach (var module in modules)
{
try
{
module.RegisterDependencies(this, resolver);
}
catch (Exception e)
{
Log.Error(e, "Could not register dependecies for module " + module.Name);
}
}
Log.Debug("Modules loaded: " + string.Join(", ", modules.Select(x => x.Name)));
return new ReactiveList<IModule>(modules);
}
Then, in my sample module:
public void RegisterDependencies(IMainScreen screen, IMutableDependencyResolver resolver)
{
_screen = screen;
_resolver = resolver;
resolver.Register(() => new SampleView(), typeof(IViewFor<SampleViewModel>));
resolver.Register(() => new GetNameDialogView(), typeof(IViewFor<GetNameDialogViewModel>));
Log.Debug("Dependecies registered");
}
Also, each module has its MainViewModel, which is displayed by RoutedViewHost when module is chosen.
Unfortunately, this does not work. I get the following error:
ReactiveUI.RoutedViewHost ERROR Couldn't find an IPlatformOperations. This should never happen, your dependency resolver is broken
The ModuleLoader.Load goes like this:
public static IModule[] Load(string path)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
Log.Error("No modules directory found - creating");
return new IModule[0];
}
var moduleTypes = GetTypes(path);
return moduleTypes.Select(MakeInstance).Where(x => x != null).ToArray();
}
private static IModule MakeInstance(Type type)
{
try
{
var module = type.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as IModule;
if (module != null)
{
Log.Info("{0} module succesfully instatiated", module.Name);
return module;
}
Log.Error("Could not instantiate {0}", type.FullName);
return null;
}
catch (Exception exception)
{
Log.Error(exception, "Exception during instatiating {0}", type.FullName);
return null;
}
}
private static List<Type> GetTypes(string path)
{
var di = new DirectoryInfo(path);
var moduleTypes = new List<Type>();
foreach (var dir in di.GetDirectories())
{
FileInfo[] files = dir.GetFiles("*.dll");
foreach (var file in files)
{
Assembly newAssembly = Assembly.LoadFile(file.FullName);
Type[] types = newAssembly.GetExportedTypes();
foreach (var type in types)
{
if (type.IsClass && !type.IsAbstract && (type.GetInterface(typeof(IModule).FullName) != null))
{
moduleTypes.Add(type);
Log.Debug("Loaded {0} type", type.Name);
}
}
}
}
return moduleTypes;
}
There is no error if I just create the instance instead of loading the assembly. If this is important, SampleModule also uses ReactiveUI.
I've tried adding Locator.CurrentMutable.InitializeReactiveUI();
in various places (MainWindow constructor, App constructor, module static constructor), but nothing helped. Any ideas?
EDIT: if this is important, MainWindow is a MetroWindow from mahapps.metro
EDIT2:
I tried to register PlatformOperations, as @Wouter suggested with:
` var iPlatformOperations = Type.GetType("ReactiveUI.IPlatformOperations, ReactiveUI, Version=7.4.0.0, Culture=neutral, PublicKeyToken=null");
resolver.Register(() => new PlatformOperations(), iPlatformOperations);`
both before module loading and after, but nothing changes.
Assembly.LoadFile
method in appdomain which does not load dependencies automatically. Instead of it useAssembly.Load
method. – Nate