Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple registration, how? #558

Open
Bezarius opened this issue Sep 30, 2023 · 16 comments
Open

Simple registration, how? #558

Bezarius opened this issue Sep 30, 2023 · 16 comments

Comments

@Bezarius
Copy link

Bezarius commented Sep 30, 2023

We have a kind of third-party plugin that is a provider for various plug-in subsystems. These subsystems are created by the provider itself and this provider manages their lifecycle.

Issue: if we register them in a container, the container will take over the lifecycle management of these dependencies. Which will cause Dispose to be called in the container and in a third-party provider. This is incorrect behavior, because in this situation the container is not the producer of the object and should not take responsibility for the release.

The question is, how to register so that the vContainer does not manage the lifecycle?

Example:

     // This class is third-party code
    public interface IClassA { }

    // This class is third-party code
    public class ClassA : IClassA, IDisposable
    {
        public void Dispose()
        {
            
        }
    }

    // This class is third-party code
    public interface IClassB { }

    // This class is third-party code
    public class ClassB : IClassB , IDisposable
    {
        public void Dispose()
        {
            
        }
    }
    
    // This class is third-party code
    public class ClassContainer : IDisposable
    {
        public IClassA ClassA => _classA;
        private ClassA _classA = new();
        public IClassB ClassB = new();
         private ClassB _classB = new();
        
        public void Dispose()
        {
            // ... here other inner disposables
            _classA .Dispose();
            _classB .Dispose();
        }
    }

And registrations, which naturally won't work:

 builder.Register<ClassContainer>(Lifetime.Scoped)
                .AsSelf()
                .AsImplementedInterfaces();
          
            // here I make registraion of `IClassA`, but `vcontainer` would look into all class interfaces and will register `IDisposable`, which will lead to a double `Dispose` call in the future
            builder
                .Register<IClassA>(x =>  x.Resolve<ClassContainer>().ClassA, Lifetime.Singleton)
                .AsSelf();

            builder
                .Register<IClassB>(x => x.Resolve<ClassContainer>().ClassB, Lifetime.Singleton)
                .AsSelf();

Injecting ClassContainer everywhere is obviously a bad idea.

@IaroslavGusiev
Copy link

IaroslavGusiev commented Oct 3, 2023

Maybe just use constructor ?)))))))))))

@pnarimani
Copy link
Contributor

Maybe just use constructor ?)))))))))))

Obviously this is sample. It's possible that OP cannot use ClassA and ClassB constructors due to them being third party code.

@Bezarius
Copy link
Author

Bezarius commented Oct 3, 2023

Obviously this is sample. It's possible that OP cannot use ClassA and ClassB constructors due to them being third party code.

Exactly.

@IaroslavGusiev
Copy link

Maybe just use constructor ?)))))))))))

Obviously this is sample. It's possible that OP cannot use ClassA and ClassB constructors due to them being third party code.

use factory!) Lol.

@Bezarius
Copy link
Author

Bezarius commented Oct 3, 2023

use factory!) Lol.

RegisterFactory obviously won't work either :\

@IaroslavGusiev
Copy link

IaroslavGusiev commented Oct 3, 2023

use factory!) Lol.

RegisterFactory obviously won't work either :\

Main question here is that VContainer is focus on non-lazy instance creation. Anyway SetA and SetB should be good to inject from method. This move will encapsule logic, because injection from properties isn't good as it looks like. Anyway you can inject properties.

For such cases I use such extension - https://pastebin.com/irNEeivs

@Bezarius
Copy link
Author

Bezarius commented Oct 4, 2023

@IaroslavGusiev It seems to me that you don't understand the problem at all. I'm not trying to do an injection of a class properties or something like this :\ I'm trying to figure out how to register dependency from Resolve.
Like this: master...Bezarius:VContainer:master
Btw, for non-zazy initialization, it is enough to use IInitializable or IStartable.

@hadashiA
Copy link
Owner

hadashiA commented Oct 8, 2023

Simple registration, how?

What is the problem with this issue?

You haven't explained it?
What is wrong with the third party code?

  • Is it that ClassContainer is a getter only?
  • Or is it a problem that ClassContainer is not resolved from anywhere, so nothing really happens?

Or maybe it's a different issue.
Please include the issue title and description.

@Bezarius
Copy link
Author

@hadashiA issue was updated

@Valerio-Corso
Copy link

If you just want to manually handle the lifecycle you can register the instance, as that is not managed by the container.

var b = builder.Resolve<ClassContainer>().ClassB;
builder.RegisterInstance<ClassB>(b).As<IClassB>();

@Bezarius
Copy link
Author

@Valerio-Corso What you wrote here won't even compile :\ VContainer aren't Zenject.

@Valerio-Corso
Copy link

Valerio-Corso commented Oct 16, 2023

sorry my bad, that was from top of my head and syntax may be wrong but the idea of registering an instance stands.

Otherwise, not sure if these solution fits your case but what i would try:

  • move 3rd parties to another lifetimescope you know won't be disposed, perhaps the root
  • Register the class .Register<ClassB> but manually specify which interfaces you want and omit IDisposable, never tried this tbh.

@Bezarius
Copy link
Author

@Valerio-Corso #554 this is how it could work in my opinion.

Author rejected this pull, so there should be another way to solve this problem simply using existing options.

Lifetimescope have a different role, so the solution through them will be a bad idea. What should I do if I have a lot of such cases?

Register the class .Register but manually specify which interfaces you want and omit IDisposable, never tried this tbh.

If you look at the very first post, then the option is considered there and it is written why it will not work.

@Bezarius
Copy link
Author

@hadashiA mb you need more context?

@ArkTarusov
Copy link

Perhaps you will find the answer at this link? https://vcontainer.hadashikick.jp/registering/register-type#register-instance

// ...
var obj = new ServiceA();
// ...

builder.RegisterInstance(obj);

Instances registered with RegisterInstance are not managed by the container.

  • Dispose will not be executed automatically.
  • Method Injection will not be executed automatically

@hadashiA
Copy link
Owner

hadashiA commented May 6, 2024

Sorry, I doubt I understand the context well enough. But does this mean that the third-party plugin sets up a DI container and the application registers against it?

In my opinion, DI is not necessary for mere third-party plug-ins or libraries. Even if such a mechanism were used, the DI container should not be shared between the library application side and the library side.

Dependency inversion with a DI container is only for writing applications.
The library is always the 'dependent party'.
(By the same token, it is ridiculous to introduce a clean or layered architecture for a mere library.

The exception, of course, is frameworks. But in this case, the lifespan management should match, because it provides the application with the lifespan management of the framework.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants