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

Lifecycle sopes with factory provider #140

Open
ibox4real opened this issue Nov 22, 2020 · 4 comments
Open

Lifecycle sopes with factory provider #140

ibox4real opened this issue Nov 22, 2020 · 4 comments

Comments

@ibox4real
Copy link

Is your feature request related to a problem? Please describe.
Currently you cant use lifecycle scopes with useFactory provider. Transient is supported by default and Singleton can be achieved with the instacneCachingFactory wrapper, but there is no way to do ContainerScoped or ResolutionScoped.

Is there a way to get ContainerScoped working with factories? Should we maybe support Lifecycle.Singleton instead of the instanceCachingFactory and add support for scopes isntead?

Factory called

  • always - Transient (default)
  • once - Singleton
  • once per container - ContainerScoped
  • once per resolution - ResolutionScoped

This would result in a more powerful and consistent registration api in my opinion.

The predicateAwareClassFactory could also be scrapped basically, since the same result can be achieved without it;

container.register('PREDICATE_AWARE_FACTORY',{
  useFactory: (c) => {
    return c.resolve(Bar).useHttp ? c.resolve( FooHttps) : c.resolve( FooHttp)
  }
})

Any thoughts on this.

@DrBlax
Copy link

DrBlax commented Nov 23, 2020

+1

@daniel-white
Copy link
Contributor

daniel-white commented May 30, 2021

I would like to see this as well - it would make dynamic external configuration much easier.

import { ThirdPartyClient } from 'third-party-client`;

@singleton() 
class Configuration {
  public readonly optionX = 'xxx';
  public readonly optionY = 'yyy';
}

@scoped(Lifecycle.ContainerScoped)
class State {
  public readonly option: 'X' | 'Y';
}

container.Register(ThirdPartyClient, {
  useFactory: c => {
    const state = c.resolve(State);
    const config = c.resolve(Configuration);
    const option = configuration[`option${state.option}`];
    return new ThirdPartyClient({ option })
  }, 
  lifecycle: Lifecycle.ContainerScoped
);

// later per request
const scopedContainer1 = container.createChildContainer();
const client1a = container.Resolve(ThirdPartyClient);
const client1b = container.Resolve(ThirdPartyClient);
assert(client1a === client1b);

const scopedContainer2 = container.createChildContainer();
const client2 = container.Resolve(ThirdPartyClient);
assert(client1a === client2);

I think this could be implemented with a custom factory type and a weak map

@daniel-white
Copy link
Contributor

Ok I hacked this together.

import { FactoryFunction, DependencyContainer } from "tsyringe";

export default function instancePerContainerCachingFactory<T>(
  factoryFunc: FactoryFunction<T>
): FactoryFunction<T> {
  const cache = new WeakMap<DependencyContainer, T>();
  return (dependencyContainer: DependencyContainer) => {
    let instance = cache.get(dependencyContainer);
    if (instance == undefined) {
      instance = factoryFunc(dependencyContainer);
      cache.set(dependencyContainer, instance);
    }
    return instance;
  };
}

@johan13
Copy link

johan13 commented Jun 1, 2022

Thanks @daniel-white

However, for my use-case I need to be able to clear the singletons with container.clearInstances(). I ended up using this instead:

import { DependencyContainer, FactoryFunction } from "tsyringe";

export default function instancePerContainerCachingFactory<T>(
  factoryFunc: FactoryFunction<T>,
): FactoryFunction<T> {
  let token = Symbol();
  return (dependencyContainer: DependencyContainer) => {
    if (dependencyContainer.isRegistered(token)) {
      return dependencyContainer.resolve(token);
    } else {
      const instance = factoryFunc(dependencyContainer);
      dependencyContainer.registerInstance(token, instance);
      return instance;
    }
  };
}

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

No branches or pull requests

5 participants