如何在 Prism 应用程序的各个模块中从 Unity 容器获取相同的对象实例
本文关键字:获取 Unity 实例 对象 Prism 应用程序 模块 | 更新日期: 2023-09-27 18:30:53
我有一个 Prism 应用程序,其中有三个模块:
- 共享服务模块
- (我正在使用共享服务在模块之间进行通信)
- 模块A
- 模块B
共享服务模块只有接口及其实现CommonService:
public interface ICommonService
{
string SomeStorage { get; set; }
}
public class CommonService : ICommonService
{
string fooStorage;
public string FooStorage
{
get
{
return fooStorage;
}
set
{
fooStorage = value;
OnPropertyChanged("FooStorage");
}
}
}
我想要的是使用共享服务在模块之间创建通信。所以我在模块A的ViewModelA上分配«ModuleAValue»,然后我想在模块B的ViewModelB中读取这个值。让我们看看细节。
我在模块 A 的 ViewModelA 中创建单个ICommonService
实例,并将值"ModuleAValue"分配给FooStorage
:
查看模型A的方法:
unityContainer = new UnityContainer();
unityContainer.RegisterType<ICommonService, CommonService>(new ContainerControlledLifetimeManager());
IMyService someFoo = unityContainer.Resolve<ICommonService>();
someFoo.FooStorage = "ModuleAValue";//value is "ModuleAValue" in FooStorage
然后我想在模块 B 的视图模型 B 中读取这些数据。但是FooStorage
的值不是"模块 A",而只是空值:
视图模型B的方法:
IUnityContainer unityContainer=new UnityContainer//creation of UnityContainer in ModuleB
ICommonService someFoo = unityContainer.Resolve<CommonService>();
string str=someFoo.FooStorage;//value is empty in
FooStorage, but it should be "ModuleAValue"
我的引导程序是:
public class Bootstrapper:UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<Shell>();
}
protected override void InitializeShell()
{
base.InitializeShell();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType<IShellViewModel, ShellViewModel>();
RegisterTypeIfMissing(typeof(IMyService), typeof(MyService), true);
}
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();
mappings.RegisterMapping(typeof(StackPanel), Container.Resolve<StackPanelRegionAdapter>());
return mappings;
}
protected override IModuleCatalog CreateModuleCatalog()
{
ModuleCatalog catalog = new ModuleCatalog();
catalog.AddModule(typeof(ModuleAModule));
catalog.AddModule(typeof(ModuleBModule));
return catalog;
}
}
我做错了什么?在我看来,Unity 总是创建新的CommonService
实例。从 Unity 容器获取相同的实例时我做错了什么?
任何帮助将不胜感激!
引导程序会为你创建一个UnityContainer
,请参阅UnityBootstrapper.cs
:
protected virtual IUnityContainer CreateContainer()
{
return new UnityContainer();
}
引导程序还应将容器注册为 viewmodel 工厂:
protected override void ConfigureContainer()
{
base.ConfigureContainer();
ViewModelLocationProvider.SetDefaultViewModelFactory( type => Container.Resolve( type ) );
}
在模块定义类中,可以将此"全局"容器作为依赖项注入:
public class ClientModule : IModule
{
private readonly IUnityContainer _unityContainer;
public ClientModule( IUnityContainer unityContainer )
{
_unityContainer = unityContainer;
}
}
在模块的初始化中,向以下容器注册类型或实例:
public void Initialize()
{
// Register services
_unityContainer.RegisterType<IGameClock, LocalGameClock>( new ContainerControlledLifetimeManager() );
_unityContainer.RegisterType<IWorldStateService, LocalWorldStateService>( new ContainerControlledLifetimeManager() );
}
在视图(在 xaml 中)中,现在可以使用 ViewModelLocator.AutoWireViewModel="True"
自动为视图创建视图模型。ViewModelLocationProvider
将使用"全局"容器来解析视图模型(如上所述),因此所有视图模型都将收到我们的相同实例,例如IGameClock
。
辅助建议:你不想自己直接打电话给Resolve
。以这种方式使用它首先违背了使用统一性的全部目的。最好将依赖项作为构造函数参数注入,并且仅在最高级别(即在模块初始化中)使用容器。而且你永远不需要创建多个容器,以免你确切地知道你在做什么。
不应创建新的容器实例。通常,应用程序中应该只有一个容器实例。如果您使用的是棱镜,则视图模型也应该从容器创建(如果棱镜负责视图模型的创建,而不是从容器创建)。在这种情况下,只需使用ICommonService类型的参数在视图模型中创建构造函数,如下所示:
public ViewModelA(ICommonService service) { ... }
然后在创建视图模型期间,服务的相同实例将被注入到该视图模型。
通常,公共服务在应用程序启动期间在命令行管理程序中注册。但是,如果需要,也可以在模块中注册服务,只需使用在应用程序启动期间创建的相同unity容器即可。在视图模型中,使用带有 IUnityContainer 类型的参数的构造函数。