简体   繁体   English

在Unity中的程序集之间共享实例

[英]Sharing instance between assemblies in Unity

Currently I'm using a singleton class and it works ok in every place I use it. 目前,我正在使用单例类,并且在我使用它的每个地方都可以。 However I'd like to make use of Unity IoC container for that. 但是,我想为此使用Unity IoC容器。 Registering it as below doesn't work the way I would like it to: 按以下方式注册它不符合我希望的方式:

container.RegisterInstance(new SomeNiceClass(), new ContainerControlledLifetimeManager());

Meaning that if I do this: 意思是如果我这样做:

container.Resolve<SomeNiceClass>();

In a class in assembly other than that it was first registered, I will get a new instance. 在除了第一次注册的汇编类中,我将获得一个新实例。

As you noticed yourself, you need to use the same instance of the container. 如您所知,您需要使用相同的容器实例。

You can do this via Unity's IModule interface. 您可以通过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());
    }
}

In your application, you register the module: 在您的应用程序中,您注册模块:

public class ApplicationBootstrapper : UnityBootstrapper
{
    protected override IModuleCatalog CreateModuleCatalog()
    {
        var moduleCatalog = new ModuleCatalog();
        moduleCatalog.AddModule(typeof(YourCompany.MyModule.MyExternalModule), InitializationMode.WhenAvailable);
        return moduleCatalog;
    }
    ...
}

edit: As an additional note, your modules should not instantiate their own containers. 编辑:作为附加说明,您的模块不应实例化其自己的容器。 The container only has to be instantiated in the main application . 容器只需要在主应用程序中实例化即可。 The modules only do registrations, nothing more! 这些模块仅进行注册,仅此而已!

If you need an instance of the container in your modules (outside of the IModule implementation), you just have to declare it in constructor. 如果您需要模块中容器的实例(在IModule实现之外),则只需在构造函数中声明它即可。

public class MyModuleResolver 
{
    private readonly IUnityContainer container;

    public MyModuleResolver(IUnityContainer container)
    {
        if(container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.container = container;
    }
}

However, please note that it's not a good practice to directly reference your container inside of your domain/business layer. 但是,请注意,直接引用您的域/业务层内部的容器不是一个好习惯。 There are only two reasons you should ever have to use the IUnityContainer yourself: 您必须自己亲自使用IUnityContainer原因只有两个:

  1. Inside your bootstrapper 在您的引导程序中
  2. Inside your application types, ie certain factory classes that need to resolve a certain type manually depending on a runtime parameter 在您的应用程序类型内部,即某些工厂类需要根据运行时参数手动解析某种类型

Everything else should be done automatically from your container via injection. 其他一切都应通过注射从您的容器中自动完成。

The assembly boundary shouldn't matter as long as you're passing a reference to the same container. 只要您将引用传递给同一容器,程序集边界就无关紧要。

You could try naming it: 您可以尝试命名:

container.RegisterInstance<SomeNiceClass>("MySingleton", new SomeNiceClass(), new ContainerControlledLifetimeManager());
container.Resolve<SomeNiceClass>("MySingleton");

Its also worth noting that the documentation says that container lifetime is the default for RegisterInstance so you could just register like so: 还值得注意的是,文档说容器生存期是RegisterInstance的默认值,因此您可以像这样进行RegisterInstance

container.RegisterInstance<SomeNiceClass>(new SomeNiceClass());

Read the MSDN comments on this here: https://msdn.microsoft.com/en-ca/library/ff647854.aspx 在此处阅读有关此的MSDN注释: https : //msdn.microsoft.com/zh-cn/library/ff647854.aspx

If you still have an issue, you need to take another look at how you deal with the container. 如果仍然有问题,则需要再次查看如何处理容器。

I had exactly the same problem (not sure why everyone is commenting that it's so difficult or impossible to reproduce - from what I can see it's quite simple. 我遇到了完全相同的问题(不确定为什么每个人都评论说很难或不可能重现-从我所看到的情况来看很简单。

FYI here are steps to reproduce: 仅供参考,以下是重现步骤:

  1. Create a solution with 2 or more assemblies. 创建具有2个或更多程序集的解决方案。
  2. Put one or more modules in each assembly. 在每个装配件中放置一个或多个模块。
  3. Rather than having the bootstrapper hardcode loading of each assembly, use some approach that dynamically discovers and loads them. 与其加载每个程序集的引导程序硬代码,不如使用一种动态发现并加载它们的方法。 I used a simplified version of this: http://brianlagunas.com/prism-dynamically-discover-and-load-modules-at-runtime/ 我使用了一个简化的版本: http : //brianlagunas.com/prism-dynamically-discover-and-load-modules-at-runtime/
  4. Try to register some singleton (ContainerControlledLifetime) type or instance in one module. 尝试在一个模块中注册某些单例(ContainerControlledLifetime)类型或实例。
  5. Also try to reference this singleton in the other modules. 还要尝试在其他模块中引用此单例。
  6. In my case, I also pre-loaded the first "main" module out of order, within the ConfigureContainer part of the bootstrapper - maybe this is part of what caused my problem. 就我而言,我还按顺序在引导程序的ConfigureContainer部分内无序地预加载了第一个“主”模块-也许这是导致我的问题的一部分。

Once all of this is in place, I reproduced the same problem - modules in assembly1 (the same as the main module) somehow got instance 1 of my "singleton", whereas modules in assembly2 (which is only loaded later, dynamically) got instance 2 of my singleton. 所有这些就绪后,我重现了相同的问题-Assembly1中的模块(与主模块相同)以某种方式获得了“单人”的实例1,而Assembly2中的模块(仅稍后以动态方式加载)得到了实例我单身的2。 I verified that they are using the same container instance. 我确认他们正在使用相同的容器实例。

I fixed the problem in my case, by moving registration of these singletons out of the modules entirely, and into my bootstrapper (again in ConfigureContainer) before any of the modules ever get loaded. 在我的情况下,我通过将这些单例的注册完全移出模块,并在加载任何模块之前将其移入引导程序(再次在ConfigureContainer中)来解决了这个问题。

Also note - when I explicitly call ModuleCatalog.AddModule with the module in assembly2 (without changing any of the rest of the code) the multiple instances problem went away. 还要注意-当我使用Assembly2中的模块显式调用ModuleCatalog.AddModule时(无需更改其余代码),多实例问题就消失了。 But when I removed that call to explicitly load it (in ConfigureModuleCatalog) and instead just allowed my dynamic module catalog to load it dynamically, the problem occurs. 但是,当我删除该调用以显式加载它(在ConfigureModuleCatalog中),而只允许我的动态模块目录动态加载它时,就会出现此问题。 I guess this is all about just getting things in the right order of events within the bootstrapper - but it certainly doesn't work as you would expect, in this scenario. 我猜想这一切都是为了在引导程序中按正确的事件顺序进行操作-但在这种情况下,它当然无法按您期望的那样工作。

Sorry if that's not a very succinct solution - it took quite a lot of trial and error to work all of this out. 很抱歉,如果这不是一个非常简洁的解决方案,那么花了很多时间反复试验才能解决所有问题。 But I hope that helps somebody. 但我希望这可以对某人有所帮助。

** update ** **更新**

After all of that writeup, and thinking through things a bit more... i finally realized what had been causing this. 经过所有这些写稿,再仔细考虑……我终于意识到了造成这种情况的原因。 Essentially, because I am pre-loading the main module which also happens to register some of the singletons, and then later on Unity is re-loading this same module along with all other modules during the bootstrapper module init phase, the same module is effectively re-registering those singleton classes, which I guess results in a duplicate definition and ultimately another instance being created. 本质上,因为我正在预加载主模块,该模块也恰好注册了一些单例,然后稍后在Bootstrapper模块初始化阶段,Unity随同其他模块一起重新加载了该模块,因此该模块有效重新注册这些单例类,我猜这会导致重复的定义,并最终创建另一个实例。 I had incorrectly assumed Unity was somehow smart enough to know it had already loaded the module, and not to reload it. 我错误地认为Unity足够聪明,以至于知道它已经加载了模块,而不是重新加载它。

I've added some functionality to my modules (with a base module) to only allow each module to be loaded once, and ignore any subsequent calls to Initialize on that same module type (statically). 我在模块(带有基本模块)中添加了一些功能,以仅允许每个模块加载一次,而忽略了对同一模块类型(静态)的任何后续对Initialize的调用。 I've then moved all of my singleton definitions back into the module. 然后,我将所有单例定义移回了模块。 Things seem to be working fine now. 现在一切似乎都很好。 So - that's what it was in my particular case. 所以-这就是我的特殊情况。

So back to the original person who posted this question - and to anyone else looking for answers - if you are seeing your singletons instantiated more than once in Unity, perhaps double check that you aren't loading the modules or registering the types more than once. 因此,请回到最初发布此问题的人员-以及其他任何寻求答案的人-如果您在Unity中多次看到单例实例化,则可能要仔细检查一下您是否要多次加载模块或注册类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM