Why and how to use DI container only at startup? - c#

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.

Related

In ASP.NET, how to instantiate a singleton object that uses DI during Startup?

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.

Is it possible to use a scoped lifestyle in Castle Windsor without passing the container around?

It's generally accepted that passing an IoC container around your application and using it like a service locator is bad practice.
I prefer to use the container only in the composite root of my application and tend to make a single call to Resolve() - resolving the top level object in my application and replying on the container to inject dependencies to classes lower in the object graph.
Castle Windsor has recently added a scoped lifestyle, where you can call container.BeginScope() within a "using" block. From within this "using" block, resolving a component that was registered with a scoped lifestyle will return the same instance each time, for the duration of the "using" block.
container.Register(Component.For<A>().LifestyleScoped());
using (container.BeginScope())
{
var a1 = container.Resolve<A>();
var a2 = container.Resolve<A>();
Assert.AreSame(a1, a2);
}
Question: Given that BeginScope() is an extension method on the container, I fail to see how a scoped lifestyle could be used in an application unless the container is passed around (which I really don't want to do). Does anyone have any examples of where/how the scoped lifestyle can be used?
Thanks,
Tom
I think the use would typically be inside of a factory, which does generally get to see the container. Think of a web application: in a sense, each invocation of a controller in an MVC app, or a "page", is running a semi-independent program. It's not unreasonable to have that "program" resolve its own dependencies. That is, each controller invocation should resolve its dependencies using the container.
In the scope of a particular web request, or TCP request, or user session, you may want the container to resolve objects differently. This is a way for you to cleanly do so inside one of your own factories. As with all uses of IoC, you have to be care not to abuse it such that business logic ends up sneaking into your registration code.

UnityContainer.Resolve or ServiceLocator.GetInstance?

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

Dependency injection: How to pass the injection container around?

(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

NInject: Where do you keep your reference to the Kernel?

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

Categories

Resources