Is there a reliable way to retrieve already created instances from the root injector? My use case is that I need to instantiate a type myself (with the new construct) but when setting up said type I need to grab two Angular2 Injector-managed instances.
app: ApplicatinRef;
Where the above app variable is retrieved via DI itself.
const rootInjector: Injector = app.injector;
rootInjector.get(SomeInstance);
When I use the above code the SomeInstance type will be instantiated a second time and I was expecting it to retrieve the same instance created during bootstrapping.
Do note, however, when I call
rootInjector.get(SomeInstance);
multiple times after initially calling it, it will not instantiate it again. So it only instantiates twice: during bootstrapping process and when calling upon the injector itself the first time.
There are no other providers for SomeInstance in the DI hierarchy, only specified at application level when bootstrapping.
Am I missing something?
You don't need to get the injector at this way, angular already inject the injector. If you don't provide in any other place the instance will be the same to all components in the hierarchy. Also you don't need to use the injector directly you could ask for the instance of your service in the constructor, like this:
...
constructor(private serviceInstance : ServiceClassName){
this.serviceInstance.doSomething();
}
If you provide in your main component, this instance will be the same in all components:
import { provide } from '#angular/core';
...
bootstrap(..., provide(ServiceClassName, {useClass : ServiceClassName}));
But you could add this instance in any place of your hierarchy using the providers configuration paramater:
import { provide } from '#angular/core';
...
#Component({
...
providers : [provide(ServiceClassName, {useClass : ServiceClassName})]
})
Providing like this will create an instance just for this component and his sub-components.
Related
I am new to dependency injection pattern. I love the idea, but struggle to apply it to my case. I have a singleton object, let’s call it X, which I need often in many parts of my program, in many different classes, sometimes deep in the call stack. Usually I would implement this as a globally available singleton. How is this implemented within the DI pattern, specifically with .NET Core DI container? I understand I need to register X with the DI container as a singleton, but how then I get access to it? DI will instantiate classes with constructors which will take reference to X, that’s great – but I need X deep within the call hierarchy, within my own objects which .NET Core or DI container know nothing about, in objects that were created using new rather than instantiated by the DI container.
I guess my question is – how does global singleton pattern aligns/implemented by/replaced by/avoided with the DI pattern?
Well, "new is glue" (Link). That means if you have new'ed an instance, it is glued to your implementation. You cannot easily exchange it with a different implementation, for example a mock for testing. Like gluing together Lego bricks.
I you want to use proper dependency injection (using a container/framework or not) you need to structure your program in a way that you don't glue your components together, but instead inject them.
Every class is basically at hierarchy level 1 then. You need an instance of your logger? You inject it. You need an instance of a class that needs a logger? You inject it. You want to test your logging mechanism? Easy, you just inject something that conforms to your logger interface that logs into a list and the at the end of your test you can check your list and see if all the required logs are there. That is something you can automate (in contrast to using your normal logging mechanism and checking the logfiles by hand).
That means in the end, you don't really have a hierarchy, because every class you have just gets their dependencies injected and it will be the container/framework or your controlling code that determines what that means for the order of instantiation of objects.
As far as design patterns go, allow me an observation: even now, you don't need a singleton. Right now in your program, it would work if you had a plain global variable. But I guess you read that global variables are "bad". And design patterns are "good". And since you need a global variable and singleton delivers a global variable, why use the "bad", when you can use the "good" right? Well, the problem is, even with a singleton, the global variable is bad. It's a drawback of the pattern, a toad you have to swallow for the singleton logic to work. In your case, you don't need the singleton logic, but you like the taste of toads. So you created a singleton. Don't do that with design patterns. Read them very carefully and make sure you use them for the intended purpose, not because you like their side-effects or because it feels good to use a design pattern.
Just an idea and maybe I need your thought:
public static class DependencyResolver
{
public static Func<IServiceProvider> GetServiceProvider;
}
Then in Startup:
public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider)
{
DependencyResolver.GetServiceProvider = () => { return serviceProvider; };
}
And now in any deed class:
DependencyResolver.GetServiceProvider().GetService<IService>();
Here's a simplified example of how this would work without a singleton.
This example assumes that your project is built in the following way:
the entry point is main
main creates an instance of class GuiCreator, then calls the method createAndRunGUI()
everything else is handled by that method
So your simplified code looks like this:
// main
// ... (boilerplate)
container = new Container();
gui = new GuiCreator(container.getDatabase(), container.getLogger(), container.getOtherDependency());
gui.createAndRunGUI();
// ... (boilerplate)
// GuiCreator
public class GuiCreator {
private IDatabase db;
private ILogger log;
private IOtherDependency other;
public GuiCreator(IDatabase newdb, ILogger newlog, IOtherDependency newother) {
db = newdb;
log = newlog;
other = newother;
}
public void createAndRunGUI() {
// do stuff
}
}
The Container class is where you actually define which implementations will be used, while the GuiCreator contructor takes interfaces as arguments. Now let's say the implementation of ILogger you choose has itself a dependency, defined by an interface its contructor takes as argument. The Container knows this and resolves it accordingly by instantiating the Logger as new LoggerImplementation(getLoggerDependency());. This goes on for the entire dependency chain.
So in essence:
All classes keep instances of interfaces they depend upon as members.
These members are set in the respective constructor.
The entire dependency chain is thus resolved when the first object is instantiated. Note that there might/should be some lazy loading involved here.
The only places where the container's methods are accessed to create instances are in main and inside the container itself:
Any class used in main receives its dependencies from main's container instance.
Any class not used in main, but rather used only as a dependency, is instantiated by the container and receives its dependencies from within there.
Any class used neither in main nor indirectly as a dependency somewhere below the classes used in main will obviously never be instantiated.
Thus, no class actually needs a reference to the container. In fact, no class needs to know there even is a container in your project. All they know is which interfaces they personally need.
The Container can either be provided by some third party library/framework or you can code it yourself. Typically, it will use some configuration file to determine which implementations are actually supposed to be used for the various interfaces. Third party containers will usually perform some sort of code analysis supported by annotations to "autowire" implementations, so if you go with a ready-made tool, make sure you read up on how that part works because it will generally make your life easier down the road.
I need to provide a date format to our application. We use this to set the format for all display and input of dates.
I need to provide this in numerous places to the application. However, the date varies depending on the client. We have an API call that provides a variety of settings (one of which is the date config) as a JSON object.
I want to be able to provide an object representing the configuration options as a value via DI. There are lots of examples of providing values, but they are all static rather than dynamic.
I want to do something like this in my DI composition root
provide('DateFormat', {
useValue: 'dd/MM/yyyy'
})
However, I want 'dd/MM/yyyy' to come from settings at startup.
I have tried providing it via services, but it is causing issues with race conditions in a few places (value not available when one service runs). Some of this could be solved by re-writing it using more observables, but it just makes the code more complex. So I want some way to provide the object via DI and have the values set before doing anything else.
Any ideas how to achieve this?
If you provide the service in the bootstrap, or in the providers:[] in the root component of your app it will instantiate the service. In the service constructor you can get the data via the api.
If you need to wait until it loads before the first page shows, you could have one observable that indicates the data is loaded or not. Use that observable to route to a new component by subscribing to the observable. Or depending on the structure of your app, use *ngIf on the boolean observable set by the service to show an initialization screen until the api call returns and the data is initialized.
Any other component that needs that configuration can use that instance of the service by injecting via the constructor args.
import {ConfigurationService} from 'path/to/configuration-service';
#Component({
selector : '',
providers: [ConfigurationService] <<-- This instantiates a new
uninitialized service. Do this only in the root component.
})
export ComponentNeedingDateFormat() {
constructor(private configurationService: ConfigurationService) { }
}
If you include it in component providers: [] it will instantiate a new service. You want to inject it only in the root component.
https://angular.io/docs/ts/latest/guide/dependency-injection.html
When creating an service container in Symfony2 you mostly pass "static" arguments (like other classes etc.) to its constructor.
However I'd like to create a factory and therefore I need to be able to pass an dynamic argument to the service constructor.
The examples I found ( e.g. http://symfony.com/doc/current/cookbook/service_container/factories.html) are all ending up using static arguments as argument.
But what do I have to do, if I want my factory to decide which object to return based on (for example) user input?
I have some problems understanding why service factory should not work on your case. Do you need to return different service class unrelated to each other?
What I see from the factory example is that you could do something like this:
class NewsletterFactory
{
public function __constructor(...)
{
// Receive arguments needed to create the service below
}
public function get()
{
// Say the variable $userInput exists and is derived from constructor
if ($userInput === 'string')
return new NewsletterManager($dynamicArgument1);
if ($userInput === 'integer')
return new AnotherNewsletterManager($dynamicArgument2);
return new DefaultNewsletterManager();
}
}
Now, if this doesn't fit your needs. You can also create a service say CustomFactory that returns what you need. What is returned is not directly a service, so you can do whatever you want. But this would prevent you from requesting the objects created by CustomFactory from the dependency container.
Similar to that is the FormFactory. It is the factory used to instantiate form type. But the FormFactory is more powerfull since it is coupled with a dependency injection tag and a compiler pass, which register each types into the dependency injection system so they can be retrieved on their own. I don't exactly all the internals of the Form component but I think it could solve your problem if other methods do not.
Regards,
Matt
I try to create a class to manage some part of my app
but I need to access the configuration in resources/config.yml
I tryed to extends my class with containerAware as a controler
But he container is not set...
I would like to be able to do something like that:
class MyClass extends ContainerAware
{
public function myFunciton()
{
$em = $this->get('Doctrine')->getEntityManager();
}
}
any suggestion is welcome
Extending ContainerAware does not automatically grant access to the service container - you would need to inject the container into your class. There are two ways to do that:
If your class is registered as a service, you can inject #service_container
If your class is not a service, but is being accessed from a class that does have access to the container (like a controller), you can explicitly call setContainer()
That being said, you should not inject the container into your classes. This makes it harder to test your classes. There are a few exceptions to this, but they don't come up often.
Instead, you should only inject services you need. In the case of the entity manager, you would inject #doctrine.orm.default_entity_manager.
In regards to accessing data from a config.yml, I would suggest including the file (which can be done when defining a service) and parsing the yml using either Symfony\Component\Yaml\Parser or Symfony\Component\Yaml\Yaml. The parsers converts a yml string to a PHP variable that you can then easily work with.
There's something I just don't get about guice: According to what I've read so far, I'm supposed to use the Injector only in my bootstrapping class (in a standalone application this would typically be in the main() method), like in the example below (taken from the guice documentation):
public static void main(String[] args) {
/*
* Guice.createInjector() takes your Modules, and returns a new Injector
* instance. Most applications will call this method exactly once, in their
* main() method.
*/
Injector injector = Guice.createInjector(new BillingModule());
/*
* Now that we've got the injector, we can build objects.
*/
RealBillingService billingService = injector.getInstance(RealBillingService.class);
...
}
But what if not all Objects I ever need can be created during startup? Maybe I want to respond to some user interaction when the application is running? Don't I have to keep my injector around somewhere (e.g. as a static variable) and then call injector.getInstance(SomeInterface.class) when I need to create a new object?
Of course spreading calls to Injector.getInstance() all over the place seems not to be desirable.
What am I getting wrong here?
Yes, you basically only should use the Injector to create get the instance for the root-object. The rest of the application shouldn't touch the Guice-Container. As you've noticed, you still need to create some objects when required. There are different approaches for doing that, each suitable for different needs.
Inject a Provider
Provider is a interface from Guice. It allows you to request a new instance of a object. That object will be created using Guice. For example.
class MyService{
private Provider<Transaction> transactionProvider;
public MainGui(Provider<Transaction> transactionProvider){
this.transactionProvider = transactionProvider;
}
public void actionStarted(){
Transaction transaction = transactionProvider.get();
}
Build a Factory
Often you need some kind of factory. This factory uses some injected services and some parameters and creates a new object for you. Then you use this factory for new instances. Then you inject that factory and use it. There also help for this with the AssistedInject-extension
I think with these two possibilities you rarely need to use the Guice-Injector itself. However sometimes is still appropriate to use the injector itself. Then you can inject the Injector to a component.
To extend on the answer Gamlor posted, you need to also differentiate between the object types you are using.
For services, injection is the correct solution, however, don't try to always make data objects (which are generally the leafs in your object graph) injectable. There may be situations where that is the correct solution, but injecting a Provider<List> is probably not a good idea. A colleague of mine ended up do that, it made the code base very confusing after a while. We just finished cleaning it all out and the Guice modules are much more specific now.
In the abstract, I think the general idea is that if responding to user events is part of the capabilities of your application, then, well...
BillingService billingService = injector.getInstance(BillingService.class);
billingService.respondToUserEvent( event );
I guess that might be a little abstract, but the basic idea is that you get from Guice your top-level application class. Judging from your question, I guess that maybe BillingService isn't your top-level class?