(This question does not rely on a specific IoC framework, so the interfaces and types in my samples are meta-types. Just replace them with the appropriate types for your favorite IoC framework in your head.)
In my main methods, I typically set up my container doing something like this:
static void Main()
{
IInjector in = new Injector();
in.Register<ISomeType>().For<SomeType>();
in.Register<IOtherType().For<OtherType>();
...
// Run actual application
App app = in.Resolve<App>();
app.Run();
}
My question is, how do you get the Injector sent around? I've normally just registered the injector with itself and had it injected into types that themselves are going to do injection, but I'm not sure if this is the proper "pattern".
You shouldn't pass the container around.
Instead, your entry-point/main method asks the container for the objects it needs to get started - such as your App object/bean. The container then returns the full object graph connected to App, which allows you to run app.Run(), with all the dependencies satisfied.
It's a bit of an anti-pattern for the objects to be aware of the container, or for each object to be asking the container for it's dependencies - if you do this then you have not inverted control and what you have is not dependency injection - you still have objects asking for what they need, rather than being given what they need.
It's best to avoid injecting the injector. Just create the types you need, and then start executing. I've written a somewhat longer post on this topic: Accessing the DI container
Related
I have a WebApi that needs to add a singleton for DI during Setup. But I need to instantiate it during Startup. All of the example code I've found online shows something like this:
services.AddSingleton(new MyService());
This is great, but what do you do if MyService() takes arguments that are setup in DI? For instance, if my service's constructor is like this:
public MyService(ILogger<MyService> logger, IConfiguration config)
There must be a way to instantiate the object when adding it to the DI services, but I'm at a loss.
I'm using .NET 6.
Thanks
You basically have two options:
Create the object -with its dependencies- before or during the registration process. With ASP.NET Core the typical place to do this is inside the Startup.ConfigureServices method (or before).
Register it normally and resolve it directly after the container was constructed. In ASP.NET Core this typically means inside the Configure method.
In case the object needs to be available before registration (for instance because the registrations depend on the outcome of a method call on that object), it's important to keep that object as slim and with as little dependencies as possible. Such object, for instance, might have more functionality and dependencies than needs to execute at that moment. In that case it's good to split the object into smaller pieces, such that you only have to compose the least amount of dependencies to get the logic executed.
For instance, instead of injecting an IConfiguration, think about injecting just the parts of the configuration that the object requires. Also think about whether you require logging at this point. Especially logging is tricky, because it's tightly coupled into the DI infrastructure, which makes it more difficult to construct such class manually. This could hold for other framework dependencies as well, because most framework dependencies are registered in the built-in configuration system.
For application components, on the other hand, it should typically fairly easy to compose them before hand. You would usually see that the kinds of services you need this early in the process tend to have little dependencies -or- they can be refactored as such.
If that 'startup' service requires a deeper object graph resolving it from the DI container makes the most sense, but again, that requires the DI Container to be built. Only when executing the Configure method (or later) do you have access to the container.
What I would suggest is the have the following call in the startup:
builder.Services.AddSingleton<IMyService, MyService>(); Then the DI will instantiate any objects that are required in the MyService constructor.
Hope this helps.
While reading about IoC/DI containers, I read in a few places (e.g. here and here and here) that the container should ideally be used only at startup.
Does this mean you need to always rely on the container injecting the parameters to the constructors of the objects you need to resolve? Even then, do you not still need the container to create those types?
What about classes that use an instance of a central service (typically a singleton) which is registered in the container?
What about classes whose constructors require parameters of types that are not registered in the container?
While reading about IoC/DI containers, I read in a few places (e.g.
here and here and here) that the container should ideally be used only
at startup.
They mean that you configure the container and register all components at application startup (or otherwise very early).
It makes sense, because typically you have a one or a few root objects (e.g. instantiated first by the container) and from there on the container should take of resolving dependencies if all of them are configured correctly.
In other situations you have to request the root objects from the container (e.g. a console or Windows Service application) because there's no way for it to integrate with the platform at startup like it can do for example for ASP.NET WebApi or MVC (well, no way excepting assembly instrumentation).
More exactly, you need to call Resolve or GetInstance (or whatever the DI framework supports) for the root objects in these situations.
What about classes that use an instance of a central service
(typically a singleton) which is registered in the container?
All DI containers support per-container lifetime, which is what a singleton basically gives you. So, you can register a singleton instance in the container with a lifetime matching that of the container and then inject that instance where you need it.
EDIT: as it turns out I got this backwards. You have here the options of either registering these classes with the container and let it do the injection, or call Resolve manually. However, as I said in the comments, some people consider service locator to be an anti-pattern. I think that if you don't abuse it and use it when it's more trouble than worth to register with the container, then do it.
What about classes whose constructors require parameters of types that
are not registered in the container?
I think that's the point of DI. If you want a component to not use DI, then don't register it and instantiate it as usual, via new.
Otherwise, if unresolved dependencies are detected by the DI container then it will most likely throw. And it should throw so you can see the error and correct it.
Imagine you have an application with several hundreds of classes implementing dozens of "high level" interfaces (meaning component level). Is there a recommend way of doing dependecy injection (like with unity). Should there be a "general container" that can be used for bootstrapping, accessible as a Singleton? Should a container be passed around, where all instances can RegisterInstance? Should everything be done by RegisterType somewhere in the startup? How can the container be made accessible when needed. Constructor injection seems false, controverse of being the standard way, you have to pass down interfaces from a component level to the very down where it is used right on startup, or a reference is hold ending up in a "know where you live" antipattern.
And: having a container "available" may bring developers to the idea of resolving server components in client context. how to avoid that?
Any discussion welcome!
edit for clarification
I figured out a somewhat realworld example to have a better picture of what problems i see.
lets imagine the application is a hifi system.
the system has cd player (integrated in a cd-rack) and
an usb port (integrated in an usb rack) to play music from.
now, the cd player and the usb port shall be able to play mp3 music.
i have an mp3 decoder somewhere around, which is injectable.
now i start the hifi system. there is no cd inserted yet and
no usb stick pluged in. i do not need a mp3 decoder now.
but with constructor injection, i have to already inject
the dependency into the cd rack and the usb rack.
what if i never insert a mp3 cd or an mp3 usb stick?
shall i hold an reference in the cd rack, so when an mp3 cd
is inserted, i have a decorder on hand? (seems wrong to me)
the decoder is needed in a subsystem of the cd rack, which
is only started if a mp3 gets inserted. now i have no container
in the cd rack, what about constructor injection here?
First of all, Dependency Injection is a design pattern that does not require a container. The DI pattern states:
Dependency injection is a software design pattern that allows a choice of component to be made at run-time rather than compile time
Take for example Guice (java dependency injection framework), in Java Guice is a DI framework but it is not a container itself.
Most of the DI tools in .Net are actually containers, so you need to populate the container in order to be able to inject the dependency
I do not like the idea to have to register every component every time in a container, I simply hate that. There are several tools that help you auto register components based on conventions, I do not use Unity, but I can point you for example to Ninject or AutoFac
I am actually writing a small utility to auto register components based on conventions using practically any DI tool, it is still in dev phase
About your questions:
Should there be a "general container" that can be used for bootstrapping, accessible as a Singleton?
The answer is yes, (there's a tool to abstract the DI tool used, it is called ServiceLocator) that's how DI tools work, there is a static container available to the application, however, it is not recommended to use it inside the domain objects to create instances, that's considered an anti-pattern
BTW I have found this tool really useful to register components at runtime:
http://bootstrapper.codeplex.com/
Should a container be passed around, where all instances can RegisterInstance?
No. that would violate the law of Demeter. If you decide to use a container is better to register the components when the application starts
How can the container be made accessible when needed
Well using the Common Service Locator you could use it anywhere in your application, but like I said, it is not recommended to use it inside the domain objects to create the required instances, instead, inject the objects in the constructor of the object and let the DI tool to automatically inject the correct instance.
Now based on this:
Constructor injection seems false, controverse of being the standard way, you have to pass down interfaces from a component level to the very down where it is used right on startup, or a reference is hold ending up in a "know where you live" antipattern
Makes me think that you are not writing unit tests heavily for your application which is bad. So my suggestion is, before choosing between which DI tool you are going to use, or before taking all the answers you get to this question into consideration, refer to the following links which are focus on one thing: Write clean testable code, this is by far the best source you could get to answer yourself your own question
Clean Code talks:
http://www.youtube.com/watch?v=wEhu57pih5w&feature=player_embedded
http://www.youtube.com/watch?v=RlfLCWKxHJ0&feature=player_embedded
Articles
http://misko.hevery.com/2010/05/26/do-it-yourself-dependency-injection/
http://misko.hevery.com/code-reviewers-guide/
Previous link in PDF http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf
The following links are super highly recommended
http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/
http://www.loosecouplings.com/2011/01/how-to-write-testable-code-overview.html
First, there is the Composition Root pattern, you set up your dependencies as soon as possible, Main() in desktop, global.asax/app_start in web. Then, rely on constructor injection as this makes your dependencies clear.
However, you still need something to actually RESOLVE dependencies. There are at least two approaches known to me.
First one consist in using the Service Locator (which is almost equal to making the container a singleton). This is considered an antipattern for a lot of people, however it just works great. Whenever you need a service, you ask your container for it:
... business code...
var service = ServiceLocator.Current.GetInstance<IMyService>();
service.Foo();
Service Locator just uses a container you set up in the Composition Root.
Another approach consist in relying on object factories available as singletons with the container injected into them:
var service = IMyServiceFactory.Instance.CreateService();
The trick is that implementation of the factory uses the container internally to resolve the service. However, this approach, with an additional factory layer, makes your business code independent and unaware of the IoC! You are free to completely redesign the factories to not to use IoC internally and still maintain every single line of business code.
In other words, it's just a trick then to hide the container/locator behind a factory layer.
While tempted to use the former approach (rely directly on the locator) I prefer the latter. It just feels cleaner.
I wonder if there are other viable alternatives here.
Should a container be passed around
No, since this leads to the Service Locator anti-pattern.
where all instances can RegisterInstance
Services should be registered in the start-up path of the application, not by types themselves. When you have multiple applications (such as web app, web service, WPF client), there will often be a common bootstrapper project that wires all services together for shared layers (but each application will still have its unique wiring, since no application behaves the same).
Should everything be done by RegisterType somewhere in the startup
Yes, you should wire everything up at start-up.
How can the container be made accessible when needed.
You shouldn't. The application should be oblivious to the use of a container (if any container is used, since this is optional). If you don't do this, you will make a lot of things much harder, such as testing. You can however, inject the container in types that are defined in the startup path of the application (a.k.a. the Composition Root). This way the application keeps clean from knowing anything about the container.
Constructor injection seems false, controverse of being the standard way
Constructor injection is the prefered way of injecting dependencies. However, it can be challanging to refactor an existing application towards constructor injection. In **rare* circumstances where constructor injection doesn't work, you can revert to property injection, or when it is impossible to build up the complete object graph, you can inject a factory. When the factory implementation is part of the composition root, you can let it depend on the container.
A pattern I found very useful, that can be built on top of the Dependency Injection pattern and the SOLID design principles, is the command / handler pattern. I found this a useful pattern in smaller apps, but it will shine when applications get big, such as enterprise applications.
now i start the hifi system. there is no cd inserted yet and no usb
stick pluged in. i do not need a mp3 decoder now.
This seems like a perfect fit for Setter injection (=property injection in C#). Use a NeutralDecoder or NullDecoder as a default and inject an Mp3Decoder when you need it. You can do it by hand or using a DI container and conditional/late binding.
http://blog.springsource.com/2007/07/11/setter-injection-versus-constructor-injection-and-the-use-of-required/
We usually advise people to use constructor injection for all
mandatory collaborators and setter injection for all other properties.
It could seem a stupid question because in my code everything is working, but I've registered a singleton this way with my Unity container _ambientContainer:
_ambientContainer.RegisterType<Application.StateContext>(new ContainerControlledLifetimeManager());
In order to avoid to use my local field, I use:
get {
return ServiceLocator.Current.GetInstance<Application.StateContext>();
}
inside my get property to get an instance of my object.
This way I get always the same instance (Application.StateContext is still a singleton) or does GetInstance create a new one?
Is it better to use the local _ambientContainer field instead?
get {
return _ambientContainer.Resolve<Application.StateContext>();
}
Thank you.
Passing around instances of the container to consumer classes isn't generally a good idea, since you are no longer guaranteed to have a single place in your application where components and services are being registered (known as the Composition Root).
Classes should state their dependencies in their public API, ideally by specifying them as constructor arguments, which the container will automatically provide an instance for whenever it's been asked to resolve a specific type (a process known as Autowiring).
Dependency Injection is usually the preferred choice but it isn't always applicable. In those cases using a Service Locator, like you're doing in your example, is the next best solution to decouple a class from its dependencies.
In conclusion, if Dependency Injection is not an option, I would avoid having my classes reference the container directly and instead have them access it through a Service Locator.
Preferably you should avoid both ways of (ab)using your container.
The ServiceLocator is considered an anti-pattern in modern application architecture.
I'm assuming that the ServiceLocator type is from the CommonServiceLocator project, and that you're using the Unity adapter, in which case GetInstance invokes container.Resolve, so both lines are equivalent.
You can view the source here - http://commonservicelocator.codeplex.com/wikipage?title=Unity%20Adapter&referringTitle=Home
I'm using NInject on a new web application and there are two things that are unclear to me:
Don't I need to keep a reference to the Kernel around (Session/App variable) to insure that GC doesn't collect all my instances? For example, if I specify .Using() and then the Kernel object gets collected, aren't all my "singletons" collected as well?
If I do need keep a reference to a Kernel object around, how do I allow the arguments passed in to WithArguments() to change or is that not possible.
It's true that you don't want to pass around the kernel. Typically, in a web app, I store the kernel in a static property in the HttpApplication. If you need a reference to the kernel, you can just expose a dependency (via constructor argument or property) that is of the type IKernel, and Ninject will give you a reference to the kernel that activated the type.
If you use WithArguments() on a binding, they will be used for all activations. If you use IParameters, they will only be used for that activation. (However, if the service you're activating has a re-usable behavior like Singleton, it won't be re-activated even if you pass different IParameters.)
This is a common pitfall when starting to use a IoC container. See this related question.
In a nutshell:
It's bad practice to pass your container around (been there, done that, and it really hurts)
If you really need to invocate directly the container, first consider abstracting to an injected factory, then as a last resource consider using a static gateway to the container
Mark Seeman -- author of Manning Dependency Injection Suggust to Use Hollywood principle Don't call us(IOC framework) instead We will call you ... .. The IOC container should be placed in the Application's Composition root.. and it needs to instantiated as requested.. like wat nate mentioned
.. For the Web Application the Composition root is Global.asax file where the u can use the override the startup events and There u can bind your Ninject to resolve the component