GithubHelp home page GithubHelp logo

Comments (33)

ENikS avatar ENikS commented on September 2, 2024 1

The good news is, it passes all tests in v6.
Unity v5 fails few of these.

If you want to contribute a fix, the key is to use "Owner" property on the ImplicitRegistration to initialize a BuilderContext.Container if lifetime manager is ContainerControlledLifetimeManager.

from container.

ENikS avatar ENikS commented on September 2, 2024

@jarikp

Is it important for you to have dependencies Disposable? If they are not, you could just hold references to these from the singleton.

This is interesting situation though and presents certain challenges. Could you create a Unity Test I could play around with?

from container.

jarikp avatar jarikp commented on September 2, 2024

I will provide a test case illustrating this tomorrow. It will be easier to explain the problem that way, you are right. Thanks again!

Best regards
Jarik

from container.

jarikp avatar jarikp commented on September 2, 2024

Hi @ENikS

I made some unit tests to illustrate what exactly I mean by this topic.
I tried to make an extension to redirect the resolution for singletons, but it didn't work, I am afraid, I don't have enough info about how the internals of Unity work, here is what I did:

public sealed class SignletonBuilderStrategy : BuilderStrategy
        {
            private readonly SignletonBuildExtension _extension;

            public SignletonBuilderStrategy(SignletonBuildExtension extension)
            {
                _extension = extension;
            }
                 
            public override void PreBuildUp(ref BuilderContext context)
            {
                // this is just to illustrate, will use attributes to detect singletons here
                if (context.Type.Name.Contains("GlobalSingleton") && context.Container.Parent != null)
                {
                   context.Existing =  extension.ResolveInRootScope(context.Type);             
                   context.BuildComplete = true
                }

                base.PreBuildUp(ref context);
            }
        }

I hope, you can point in a direction or otherwise advise about a solution/workaround. Thanks!

Regards
/Jarik

from container.

ENikS avatar ENikS commented on September 2, 2024

Did you see this Singleton Lifeteime?

from container.

jarikp avatar jarikp commented on September 2, 2024

Yes, I have . As pr your request I made few unit tests, and the singleton type in the test target is registered as InstanceLifetime.Singleton:

image

Or maybe you mean something different?

from container.

jarikp avatar jarikp commented on September 2, 2024

Hi @ENikS , have you had any time to look at the test cases? I see that my branch is now failing, but I guess that is unrelated.
/Jarik

from container.

ENikS avatar ENikS commented on September 2, 2024

from container.

jarikp avatar jarikp commented on September 2, 2024

Ok, thanks! 👍

from container.

ENikS avatar ENikS commented on September 2, 2024

After looking into this long and hard I can conclude that this is a correct behavior. Every resolution runs in the context of the executing container. This is by design from the dawn of time and could not be changed.

from container.

jarikp avatar jarikp commented on September 2, 2024

Ok, I see, thank you for you time. But do you think there is a workaround to bypass/reconfigure this behavior? I am not talking about changing the default flow, but perhaps som extension mechanism to override it?

from container.

ENikS avatar ENikS commented on September 2, 2024

from container.

jarikp avatar jarikp commented on September 2, 2024

I can do that if I am resolving a singleton type directly, then it is possible to check. But if the singleton is somewhere down the chain of the dependencies, then it is out of my control. This is why I was trying to intercept a singleton in BuilderStrategy in my example above and redirect it to be resolved in the root, but this approach didn't work. Do you think it is possible at all (without modifying the unity code)?

from container.

ENikS avatar ENikS commented on September 2, 2024

What stops you from preemptively creating it right after you registered the singleton?

You could create a type factory, same as Unity's Func<> or Lazy<>. Each container has a pointer _root...

from container.

jarikp avatar jarikp commented on September 2, 2024

Hi @ENikS ,

I tried what you suggested and unfortunately, I was not able to find a satisfactory solution by re-wrapping the singletons into Lazy/Factory constructs, it is complicated and difficult to implement in the code base.

However, I managed to build this logic into Resolve-flows in the UnityContainer (only for 5.10.3) , and the proposed fix actually resolved the problems. Would you kindly review the pull request and let me know if this is a good solution or what should be re-written to achieve same behavior?

Thanks!

Best regards
Jarik

from container.

ENikS avatar ENikS commented on September 2, 2024

@jarikp
Your change significantly alters Unity's behavior. I am still not convinced it is broken to begin with.
Limiting resolution to the level of registration changes one of the main resolve specs and I don't think it is justified.

Now, if it is done for the singleton, it would have to apply to Container Controlled lifetime as well? Same issue...

from container.

jarikp avatar jarikp commented on September 2, 2024

Yes, I completely agree that this is potentially breaking change with serious impact.

The problem is that I don know how it should be implemented otherwise?.. The real need here is to create some kind of "super" singleton (or "global" singleton ?) which is never going to be corrupted if the container where it was resolved first time is disposed later, implying that the singleton itself and all its dependencies, sub-dependencies etc including factories (this is important!) have infinite lifetime or at least until the root is torn down.

So maybe to prevent any issues like breaking existing lifetime of Unity, it would be better idea to define a new manager option in Unity.TypeLifetime, like RootedSingleton or GlobalSingleton etc? And use that to enable the desired behavior? This will at least be more explicit for developers and the existing behavior will remain unchanged.

from container.

ENikS avatar ENikS commented on September 2, 2024

Why not register all relevant types in the root, resolve the singleton, and only then create child containers?

from container.

jarikp avatar jarikp commented on September 2, 2024

Well, some constraints preventing doing this workaround could be due to architecture limitations, app design, performance reasons (resolving can be expensive and only wanted on demand) or the cost of refactoring.

Here is an example of how this problem is translated into the real-life usage of Unity:

Imagine you have an app, and when you start the app, you can open different child windows for from app. The main window of the app will be representing the root container (if you close the main window, the app is terminated). Each new window will be created as a child container. With this design each window will have its own scope, where it can host its own "local" singletons (states).

However, some of the services in the app are globally shared, and only one instance of each is allowed to exist – let's call them "global" singletons. Due to start-up performance, memory consumption and sometimes licensing limitations they are not resolved when the app is launched, but only when needed during the lifetime of the running process. Anyway, there is a window, which will resolve such a global service when opened first time. Then when you open a different window using same service, it will get the very same instance of the service, etc….

The problem now is that if you close the first window, before you open the second one, the corresponding child container of that window is disposed. Which means all dependencies of the singleton service are potentially broken (since they were all resolved in that container and never promoted to the root). And when you open the second window, it will indeed get the same singleton service, but everything in its dependency chain will be corrupted, as the owning container was disposed, when you closed the first window.

So due to the application design it is not possible to pre-resolve those things during the startup. It needs to be managed by the unity container, when (and IF) a global singleton is resolved for the first time.

The registration of types is done in the root container already, this is not the problem .

from container.

ENikS avatar ENikS commented on September 2, 2024

Just because one application has certain design requirements it does not warrant change to basic container behavior. I already offered at least couple of different solutions to the problem. The behavior you describe could be easily achieved by implementing any of these.

from container.

jarikp avatar jarikp commented on September 2, 2024

Hi @ENikS

First, thank you for the time you are spending on this, it is really appreciated. I do understand, how this problem might look from your side, and it is hard for me to run this campaign :)

Your proposed solutions are valid in general, but they are very hard to implement in my case. In the system I am working on (consisting of multiple applications) there are almost 10000 types which are all registered in the containers, with very complicated dependency chains and different lifetime types. And the UnityContainer has been in its IoC core since the beginning.

This issue is preventing the upgrade to version 5.x of the container, it looks like version 4.0.1 which is used now, does not show this problem at runtime as often as version 5 - for whatever reason. But I suspect that version 5 is much faster with resolve/teardown, which unveils the problem with singletons in closed child containers.

I also think that the lifetime management as this is a responsibility of the IoC container / framework, not the application itself. Therefore, I keep looking for a solution in the Unity Container, instead of doing the manual bookkeeping in the application.

The good thing is that the UnityContainer is already able to help me with all of this! It can be done without changing a single line of the application code, this is what I showed you in the pull request. And to make it clear, it does not have to be a change to the fundamental behavior of the container. I am suggesting this as an optional mode of operation, that should be enabled explicitly by a special lifetime type or maybe some configuration flag.

I am offering help to implement this, but I guess it will not make sense if you totally against any possible change in that direction…

Best regards
Jarik

from container.

ENikS avatar ENikS commented on September 2, 2024

from container.

ENikS avatar ENikS commented on September 2, 2024

After thinking about it a bit more I admit, you are making a valid point. Some lifetimes do require limiting scope to the container where they are registered.

I will try to implement it in next release of Unity.

from container.

jarikp avatar jarikp commented on September 2, 2024

Hi @ENikS

This is really great news! 👍

I know that you are busy working on v.6, and I'd be happy to help implementing it in v.5 branch. I think UnityContainer is really interesting project and would like to contribute to it.

If you could share your thoughts about a solution design, I can give you a hand to with writing code and tests

Best regards,
Jarik.

from container.

ENikS avatar ENikS commented on September 2, 2024

from container.

jarikp avatar jarikp commented on September 2, 2024

Hi @ENikS,

Have you had a chance to review the spec tests, are they in the format you would expect?

Best regards,
Jarik

from container.

ENikS avatar ENikS commented on September 2, 2024

I've incorporated them into spec test suilte

from container.

jarikp avatar jarikp commented on September 2, 2024

Hi again,
Thanks for closing this. I am not sure, if it that you have changed the behavior of unity so it now works as wanted in the cases above?

Also, I see that my pull request with the test cases is still pending, and they are not in the source code.

The reason I am asking is because you wrote earlier:

"I will add necessary changes to Abstractions and will let you know how it could be fixed in v5. I will be out of town for few days, so perhaps next week… Meanwhile if you could come up with all the necessary tests it would be great. I have relevant set of tests you could add to here... "

So I don't follow your decision to close this and not using the things you asked me to help you with?..

Best regards
Jarik

from container.

ENikS avatar ENikS commented on September 2, 2024

PR was merged but I moved and renamed some of the tests

from container.

jarikp avatar jarikp commented on September 2, 2024

Hi Eugene,

I am talking about this one:
unitycontainer/specification-tests#2

It is mentioned in this thread, just below your message 24 days ago.

But maybe there is some kind of misunderstanding? 🤔

Best regards
Jarik

from container.

ENikS avatar ENikS commented on September 2, 2024

I've merged it too. Missed it somehow.

from container.

jarikp avatar jarikp commented on September 2, 2024

@ENikS, I see that all tests are green now on v5. In the code it looks like you have fixed the remaining bits of this issue, and there is no more expected work left? Sorry if this is obvious for you, but I could not find any relevant info or release notes about this.

from container.

ENikS avatar ENikS commented on September 2, 2024

from container.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.