目前我正在使用单例类,它在我使用它的每个地方都可以正常工作。但是我想为此使用Unity IoC容器。如下注册它不会按照我希望的方式工作:
container.RegisterInstance(new SomeNiceClass(), new ContainerControlledLifetimeManager());
意思是如果我这样做:
container.Resolve<SomeNiceClass>();
在除了首次注册之外的程序集中的类中,我将获得一个新实例。
答案 0 :(得分:3)
正如您自己注意到的那样,您需要使用相同的容器实例。
您可以通过Unity的IModule
界面执行此操作。
[Module(ModuleName="MyExternalModule", OnDemand=false)]
public class MyExternalModule : IModule
{
private readonly IUnityContainer container;
public MyExternalModule(IUnityContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
this.container = container;
}
public void Initialize()
{
container.RegisterInstance(new MyService());
}
}
在您的应用程序中,您注册了模块:
public class ApplicationBootstrapper : UnityBootstrapper
{
protected override IModuleCatalog CreateModuleCatalog()
{
var moduleCatalog = new ModuleCatalog();
moduleCatalog.AddModule(typeof(YourCompany.MyModule.MyExternalModule), InitializationMode.WhenAvailable);
return moduleCatalog;
}
...
}
修改强> 另外请注意,您的模块不应实例化自己的容器。只需在主应用程序中实例化容器。这些模块只进行注册,仅此而已!
如果您需要模块中的容器实例(IModule
实现之外),则只需在构造函数中声明它。
public class MyModuleResolver
{
private readonly IUnityContainer container;
public MyModuleResolver(IUnityContainer container)
{
if(container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
}
但请注意,在您的域/业务层内直接引用您的容器并不是一个好习惯。你应该自己使用IUnityContainer
只有两个原因:
其他所有东西都应该通过注射从容器中自动完成。
答案 1 :(得分:1)
只要您将引用传递给同一个容器,程序集边界就不重要了。
您可以尝试命名它:
container.RegisterInstance<SomeNiceClass>("MySingleton", new SomeNiceClass(), new ContainerControlledLifetimeManager());
container.Resolve<SomeNiceClass>("MySingleton");
还值得注意的是,文档说容器生命周期是RegisterInstance
的默认值,所以你可以像这样注册:
container.RegisterInstance<SomeNiceClass>(new SomeNiceClass());
在此处阅读MSDN评论:https://msdn.microsoft.com/en-ca/library/ff647854.aspx
如果您仍有问题,则需要再次了解如何处理容器。
答案 2 :(得分:1)
我遇到了完全相同的问题(不确定为什么每个人都在评论复制它是如此困难或不可能 - 从我看来它非常简单。
仅供参考,以下是重现的步骤:
一旦所有这一切都到位,我再现了同样的问题 - assembly1中的模块(与主模块相同)以某种方式获得了我的“singleton”的实例1,而assembly2中的模块(仅稍后加载,动态得到了我的单身实例2。我确认他们正在使用相同的容器实例。
我在我的情况下修复了问题,将这些单例的注册完全移出模块,并在任何模块加载之前进入我的引导程序(再次在ConfigureContainer中)。
另请注意 - 当我使用assembly2中的模块显式调用ModuleCatalog.AddModule时(不更改任何其余代码),多实例问题就消失了。但是当我删除该调用以显式加载它(在ConfigureModuleCatalog中)而只是允许我的动态模块目录动态加载它时,就会出现问题。我想这就是在引导程序中以正确的事件顺序获取事物 - 但在这种情况下它肯定不会像你期望的那样工作。
很抱歉,如果这不是一个非常简洁的解决方案 - 需要进行大量的反复试验才能完成所有这些工作。但我希望能帮到别人。
**更新**
在所有这些写作之后,再多思考一下......我终于意识到导致这种情况的原因。本质上,因为我正在预加载主模块,这也恰好注册了一些单例,然后Unity在引导程序模块初始化阶段重新加载同一模块和所有其他模块,同样的模块是有效的重新注册那些单例类,我猜这会产生一个重复的定义,最终会创建另一个实例。我错误地认为Unity非常聪明,知道它已经加载了模块,而不是重新加载它。
我已经为我的模块添加了一些功能(使用基本模块),只允许每个模块加载一次,并忽略对相同模块类型(静态)的任何后续调用Initialize。然后我将所有单例定义移回模块中。现在似乎工作正常。所以 - 这就是我的具体情况。
回到发布此问题的原始人 - 以及寻找答案的其他人 - 如果您在Unity中看到您的单身人士不止一次实例化,也许请仔细检查您是否未加载模块或注册类型不止一次。