Dependency Injection in a Non-Trivial WinForm Application
I would like to ask someone who can help in injecting dependency injection into a sample WinForm application. We have an application with the following structure (not a complete graph):
MainForm <-> MainModel
| |β -----------------------β
| β ------------β |
FA <-> MA FB <-> MB FC <-> MC
| | |β-----------------β
| β-----------β β----β |
FAA <-> MAA FAB <-> MAB FCA <-> MCA FCB <-> MCB
|||
β--------------β|β----------------β
FCAA <-> MCAA FCAB <-> MCAB FCAC <-> MCAC
||
β--------------ββ----------------β
FCAAA <-> MCAAA FAB <-> MAB
I can implement a composition root where I can print something like this:
var container = new Container();
container.RegisterSingle<IMainForm, MainForm>();
container.Register<IMainModel, MainModel>();
container.Register<IFA, FA>();
...
I know how to get the first MainForm and show it (simple permutation). But I am still struggling with the correct logic of how to create other forms and models on demand. I don't want to pass a reference to my container in mainform and resolve dependencies in mainform because it smells like a servicelocator template. I would like to avoid creating an obscure Factory with the methods CreateFA, CreateFB, CreateFAAA ... I would like to avoid full plotting in mainform too.
Also, I would like to use in MCAA some implementation of an IJob interface that can be defined as part of root, but I would like to avoid passing the IJob instance through all the layers of the forms or passing some kind of factory ...
The easiest way to create all instances of windows, models and ect. since I need them, use the ServiceLocator ... But, well ... How about DI?
Preferred DI: SimpleInjector, Preferred Language: C #
source to share
I would like to avoid to pass the complete constructed graph to mainform too.
It will make your life easier if you create your application as being completely native .
If your issue is performance related, start by plotting your entire graph up and measure to see if you have a performance issue. If you find that you have subgraphs that you need to defer, you can use the virtual proxy pattern to defer creating branches until you need them.
If the real problem is that you cannot create the whole graph upwards because some subgraphs depend on runtime values, you can use an abstract Factory ; you don't have to come up with countless abstract Factory interfaces: one generic interface is enough IFactory<T, TInput>
.
Other alternatives to selecting dependencies based on runtime values ββare
Also, I would like to use in MCAA some implementation of the IJob interface
Just type IJob
in MCAA
like any other class. You don't need to pass it through layers if those layers are never created MCAA
. Only the root composition needs to contain an implementation reference, because only the root composition creates MCAA
.
source to share
I think you basically have 3 options, right? Although you've already decided that you don't really like 2 of them :)
- Inject form instances into MainForm from composition root
- Introduce a single factory to create all forms in MainForm at the root of the composition
- Nest many factories to create each form separately in the MainForm at the root of the composition.
I prefer the third option to the second, as each form only needs the factories for the forms it really needs to create.
How viable the first option might be may depend on whether your forms are a single instance or not.
DI and container won't magically provide you with a solution, they will just make it easier to connect your preferred solution.
source to share