Castle Windsor lazy load services
Asked Answered
S

3

9

Occasionally I find myself in a situation where I need to resolve a service only if a certain condition is met. For example, a user might select to send an email or an sms notification. I would like to lazy load the email or sms service depending on what the user chooses so that I don't have to load both of them and waste resources (what if there were, for example, 10 options for the user...?).

The problem I have is with using the container outside of my bootstrap code (I dont want my code dependent on th container). I can't seem to find a way around using the container for lazy loading services (unless I create the needed services by hand and do all the DI manually). Is this a situation where the rules can be bent or is there a better way of doing it?

Seriate answered 26/12, 2012 at 15:27 Comment(0)
F
5

If you are using Castle Windsor 3.0 or newer, you can use lazy resolving.

See What's new in Windsor 3 for more details.

Registration process changes a bit (new component loader must be registered).

After that, you are just registering components as always, but resolve dependencies as Lazy<T> instead of T. Until you won't access .Value property of your Lazy<T>, dependency will not be resolved, so you can pass few lazily evaluated objects and access only the one you will need and when you need.

If you have more options to the user, maybe you should consider creating some sort of abstract factory interface. You would then register and resolve only this factory and the factory itself would create appropriate service for sending notifications (be it a mail or a sms or any other option). Implementation of the factory can be coded by hand or Castle Windsor can you with that (I think from version 3.0).

Often when I do use such factory, I implement it by hand and pass container as it's dependency, so only factory implementation depends on my container.

Frivolous answered 26/12, 2012 at 15:36 Comment(0)
D
3

Just an example to simplify (based on Marcin Deptuła answer)

// activate Lazy initialization feature  for all Components
.Register(Component.For<ILazyComponentLoader>().ImplementedBy<LazyOfTComponentLoader>())     
// register rest of component(s)
.Register(Component.For<IIssueRepository>().ImplementedBy<IssueRepository>()) 
. ....

resolve lazily (property injection)

public Lazy<IIssueRepository> IssueRepository { get; set; }
IssueRepository.Value.GetLastIssue();

resolve normal (property injection)

public IIssueRepository IssueRepository { get; set; }
IssueRepository.GetLastIssue();
Dairying answered 21/8, 2013 at 5:4 Comment(0)
G
1

In general, you can do that with the Typed Factory Facility.

In a nutshell, when you resolve the component that uses those services, instead of giving it an email or sms service, you give it a factory that can create them (which is defined by you, without references to the container)

The facility will take care of "implementing" your factory (from the interface you create), so there's very little to do.

Goy answered 26/12, 2012 at 15:37 Comment(2)
What if each of my services has its own unique set of dependencies. For example, the sms service has 3 unique dependencies, the email service has 4 unique dependencies, etc. Would I just inject 20 (or however many there are) dependencies into the factory? Great response btw.Seriate
The factory is implemented by castle. You just configure your services as usual.Goy

© 2022 - 2024 — McMap. All rights reserved.