"Couldn't find an IPlatformOperations. This should never happen, your dependency resolver is broken" 在 WPF 上
"Couldn't find an IPlatformOperations. This should never happen, your dependency resolver is broken" on WPF
我正在编写一个程序,它是其他较小程序的容器。它通过 Assembly.Load 加载它的模块,找到实现 IModule 的类型并创建它们的实例。
在 WPF MainWindow 中,我有一个 RoutedViewHost,它将显示所有内容。
在我的 AppBoostrapper 中,我有以下内容:
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);
}
然后,在我的示例模块中:
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");
}
此外,每个模块都有自己的 MainViewModel,在选择模块时由 RoutedViewHost 显示。
不幸的是,这不起作用。我收到以下错误:
ReactiveUI.RoutedViewHost ERROR Couldn't find an IPlatformOperations.
This should never happen, your dependency resolver is broken
ModuleLoader.Load 是这样的:
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;
}
如果我只是创建实例而不是加载程序集,则没有错误。如果这很重要,SampleModule 也使用 ReactiveUI。
我尝试在不同的地方添加 Locator.CurrentMutable.InitializeReactiveUI();
(MainWindow 构造函数、App 构造函数、模块静态构造函数),但没有任何帮助。有什么想法吗?
编辑:如果这很重要,MainWindow 是来自 mahapps.metro
的 MetroWindow
编辑 2:
我尝试注册 PlatformOperations,正如@Wouter 建议的那样:
` var iPlatformOperations = Type.GetType("ReactiveUI.IPlatformOperations, ReactiveUI, Version=7.4.0.0, Culture=neutral, PublicKeyToken=null");
resolver.Register(() => new PlatformOperations(), iPlatformOperations);`
加载模块之前和之后,但没有任何变化。
嗯,事实证明,简单地调用 Assembly.Load("ReactiveUI");
会破坏整个事情,所以我只是添加了过滤 do loaded DLLs 以仅加载名称中带有 "Module" 的 DLL。
然后我遇到了新问题:视图位置不适用于动态加载的程序集,因此我使用以下 ResolveView 实现创建了自己的 ViewLocator:
public IViewFor ResolveView<T>(T viewModel, string contract = null)
where T : class
{
var typeToFind = ViewModelToViewFunc(viewModel.GetType().AssemblyQualifiedName);
var ret = attemptToResolveView(Reflection.ReallyFindType(typeToFind, false), contract);
if (ret != null) return ret;
// IViewFor<FooBarViewModel> (the original behavior in RxUI 3.1)
var viewType = typeof(IViewFor<>);
ret = attemptToResolveView(viewType.MakeGenericType(viewModel.GetType()), contract);
if (ret != null) return ret;
// check ViewModel's assembly
var typeAssembly = viewModel.GetType().Assembly;
var types = typeAssembly.GetExportedTypes()
.SelectMany(x => x.GetInterfaces()
.Where(i => i.Name.Contains("IViewFor")))
.ToArray(); // all IViewFor from assembly
types = types.Where(x => x.FullName.Contains(viewModel.GetType().Name.Replace("ViewModel", "View"))).ToArray(); // only IViewFor<ViewModel>
foreach (var type in types) // in case there is more than one registration - contracts
{
ret = attemptToResolveView(type, contract);
if (ret != null) return ret;
}
return null;
}
我正在编写一个程序,它是其他较小程序的容器。它通过 Assembly.Load 加载它的模块,找到实现 IModule 的类型并创建它们的实例。
在 WPF MainWindow 中,我有一个 RoutedViewHost,它将显示所有内容。
在我的 AppBoostrapper 中,我有以下内容:
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);
}
然后,在我的示例模块中:
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");
}
此外,每个模块都有自己的 MainViewModel,在选择模块时由 RoutedViewHost 显示。
不幸的是,这不起作用。我收到以下错误:
ReactiveUI.RoutedViewHost ERROR Couldn't find an IPlatformOperations. This should never happen, your dependency resolver is broken
ModuleLoader.Load 是这样的:
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;
}
如果我只是创建实例而不是加载程序集,则没有错误。如果这很重要,SampleModule 也使用 ReactiveUI。
我尝试在不同的地方添加 Locator.CurrentMutable.InitializeReactiveUI();
(MainWindow 构造函数、App 构造函数、模块静态构造函数),但没有任何帮助。有什么想法吗?
编辑:如果这很重要,MainWindow 是来自 mahapps.metro
的 MetroWindow编辑 2:
我尝试注册 PlatformOperations,正如@Wouter 建议的那样:
` var iPlatformOperations = Type.GetType("ReactiveUI.IPlatformOperations, ReactiveUI, Version=7.4.0.0, Culture=neutral, PublicKeyToken=null");
resolver.Register(() => new PlatformOperations(), iPlatformOperations);`
加载模块之前和之后,但没有任何变化。
嗯,事实证明,简单地调用 Assembly.Load("ReactiveUI");
会破坏整个事情,所以我只是添加了过滤 do loaded DLLs 以仅加载名称中带有 "Module" 的 DLL。
然后我遇到了新问题:视图位置不适用于动态加载的程序集,因此我使用以下 ResolveView 实现创建了自己的 ViewLocator:
public IViewFor ResolveView<T>(T viewModel, string contract = null)
where T : class
{
var typeToFind = ViewModelToViewFunc(viewModel.GetType().AssemblyQualifiedName);
var ret = attemptToResolveView(Reflection.ReallyFindType(typeToFind, false), contract);
if (ret != null) return ret;
// IViewFor<FooBarViewModel> (the original behavior in RxUI 3.1)
var viewType = typeof(IViewFor<>);
ret = attemptToResolveView(viewType.MakeGenericType(viewModel.GetType()), contract);
if (ret != null) return ret;
// check ViewModel's assembly
var typeAssembly = viewModel.GetType().Assembly;
var types = typeAssembly.GetExportedTypes()
.SelectMany(x => x.GetInterfaces()
.Where(i => i.Name.Contains("IViewFor")))
.ToArray(); // all IViewFor from assembly
types = types.Where(x => x.FullName.Contains(viewModel.GetType().Name.Replace("ViewModel", "View"))).ToArray(); // only IViewFor<ViewModel>
foreach (var type in types) // in case there is more than one registration - contracts
{
ret = attemptToResolveView(type, contract);
if (ret != null) return ret;
}
return null;
}