如何从 Prism 应用程序的各个模块中的 Unity 容器中获取相同的对象实例?
How to get the same instance of object from Unity container in various modules of Prism application?
我有一个 Prism 应用程序,其中包含三个模块:
- SharedServiceModule(我正在使用SharedServices在模块之间进行通信)
- 模块A
- 模块 B
SharedServiceModule 只有接口及其实现 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");
}
}
}
我想要的是使用 Shared Services 在模块之间创建通信。所以我在 ModuleA 的 ViewModelA 分配了 «ModuleAValue»,然后我想在 ViewModelB 中读取这个值模块 B。来看看详情吧。
我在 ModuleA 的 ViewModelA 中创建了一个 ICommonService
的实例,并将值 "ModuleAValue" 分配给FooStorage
:
ViewModelA的方法:
unityContainer = new UnityContainer();
unityContainer.RegisterType<ICommonService, CommonService>(new ContainerControlledLifetimeManager());
IMyService someFoo = unityContainer.Resolve<ICommonService>();
someFoo.FooStorage = "ModuleAValue";//value is "ModuleAValue" in FooStorage
然后我想在ModuleB的viewModelB中读取这个数据。但是 FooStorage
的值不是 'Module A',而是空值:
ViewModelB的方法:
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 容器获取同一个实例时我做错了什么?
任何帮助将不胜感激!
您不应该创建新的容器实例。通常您的应用程序中应该只有一个容器实例。
如果您使用的是棱镜,您的视图模型也应该从容器中创建(如果棱镜负责视图模型的创建而不是从容器中创建的)。在这种情况下,只需在视图模型中使用 ICommonService 类型的参数创建构造函数,如下所示:
public ViewModelA(ICommonService service) { ... }
然后在创建 ViewModel 期间,相同的服务实例将被注入到该 ViewModel。
并且通常在应用程序启动时在Shell中注册常用服务。但是如果你愿意,你也可以在模块中注册一个服务,只需使用在应用程序启动期间创建的相同的统一容器。在视图模型中使用带有 IUnityContainer 类型参数的构造函数。
您应用的引导程序会为您创建一个 UnityContainer
,请参阅 UnityBootstrapper.cs
:
protected virtual IUnityContainer CreateContainer()
{
return new UnityContainer();
}
引导程序还应将容器注册为视图模型工厂:
protected override void ConfigureContainer()
{
base.ConfigureContainer();
ViewModelLocationProvider.SetDefaultViewModelFactory( type => Container.Resolve( type ) );
}
在您的模块定义 class 中,您可以将此 'global' 容器作为依赖项注入:
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
将使用 'global' 容器来解析视图模型(如上定义),因此所有视图模型都将收到我们的相同实例,例如 IGameClock
.
辅助建议:您不想自己直接调用 Resolve
。以这种方式使用它首先会破坏使用统一性的全部目的。最好将依赖项作为构造函数参数注入,并且只在最高级别使用容器,即在模块初始化中。而且您永远不需要创建多个容器,以免您确切地知道自己在做什么。
我有一个 Prism 应用程序,其中包含三个模块:
- SharedServiceModule(我正在使用SharedServices在模块之间进行通信)
- 模块A
- 模块 B
SharedServiceModule 只有接口及其实现 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");
}
}
}
我想要的是使用 Shared Services 在模块之间创建通信。所以我在 ModuleA 的 ViewModelA 分配了 «ModuleAValue»,然后我想在 ViewModelB 中读取这个值模块 B。来看看详情吧。
我在 ModuleA 的 ViewModelA 中创建了一个 ICommonService
的实例,并将值 "ModuleAValue" 分配给FooStorage
:
ViewModelA的方法:
unityContainer = new UnityContainer();
unityContainer.RegisterType<ICommonService, CommonService>(new ContainerControlledLifetimeManager());
IMyService someFoo = unityContainer.Resolve<ICommonService>();
someFoo.FooStorage = "ModuleAValue";//value is "ModuleAValue" in FooStorage
然后我想在ModuleB的viewModelB中读取这个数据。但是 FooStorage
的值不是 'Module A',而是空值:
ViewModelB的方法:
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 容器获取同一个实例时我做错了什么?
任何帮助将不胜感激!
您不应该创建新的容器实例。通常您的应用程序中应该只有一个容器实例。 如果您使用的是棱镜,您的视图模型也应该从容器中创建(如果棱镜负责视图模型的创建而不是从容器中创建的)。在这种情况下,只需在视图模型中使用 ICommonService 类型的参数创建构造函数,如下所示:
public ViewModelA(ICommonService service) { ... }
然后在创建 ViewModel 期间,相同的服务实例将被注入到该 ViewModel。
并且通常在应用程序启动时在Shell中注册常用服务。但是如果你愿意,你也可以在模块中注册一个服务,只需使用在应用程序启动期间创建的相同的统一容器。在视图模型中使用带有 IUnityContainer 类型参数的构造函数。
您应用的引导程序会为您创建一个 UnityContainer
,请参阅 UnityBootstrapper.cs
:
protected virtual IUnityContainer CreateContainer()
{
return new UnityContainer();
}
引导程序还应将容器注册为视图模型工厂:
protected override void ConfigureContainer()
{
base.ConfigureContainer();
ViewModelLocationProvider.SetDefaultViewModelFactory( type => Container.Resolve( type ) );
}
在您的模块定义 class 中,您可以将此 'global' 容器作为依赖项注入:
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
将使用 'global' 容器来解析视图模型(如上定义),因此所有视图模型都将收到我们的相同实例,例如 IGameClock
.
辅助建议:您不想自己直接调用 Resolve
。以这种方式使用它首先会破坏使用统一性的全部目的。最好将依赖项作为构造函数参数注入,并且只在最高级别使用容器,即在模块初始化中。而且您永远不需要创建多个容器,以免您确切地知道自己在做什么。