Using an IOC-container like Unity,AutoFac or others you have to Register and Resolve the IInterface to get the instance. This you do in the app class the root of all.
After doing the Register/Resolve stuff I am creating my MainController and pass them ALL resolved Services like:
protected void Application_Start(object sender, EventArgs e)
{
var builder = new ContainerBuilder();
builder.Register<IUserService1, UserService1>();
builder.Register<IUserService2, UserService2>();
builder.Register<IUserService3, UserService3>();
builder.Register<IAnotherService, AnotherService>();
// And many more Services...
_container = builder.Build();
var userService1 = _container.Resolve<IUserService1>();
var userService2 = _container.Resolve<IUserService2>();
var userService3 = _container.Resolve<IUserService3>();
var anotherService = _container.Resolve<IAnotherService>();
var vm = new MainController(userService1,userService2,userService3,anotherService)
}
public class MainController
{
private UserController1 _userVM1;
private UserController2 _userVM2;
private UserController3 _userVM3;
public MainController(IUserService1 userService1,IUserService2 userService2,IUserService3 userService3,anotherService)
{
_userVM1 = new UserController1(userService1,anotherService);
_userVM2 = new UserController2(userService2,...,...);
_userVM3 = new UserController3(userService3,...,...,...);
}
}
// Such a Controller class needs to be created 10 times... and what I do here is typical for all Controllers driving the GUI
public class UserController1
{
private readonly IUserService1 _userService1;
public UserController1(IUserService1 userService1,IAnotherService anotherService)
{
_userService1 = userService1;
//Bind data to GUI
UserData1Collection = ConvertModelIntoViewModelCollection(userService1,anotherService);
}
public ObservableCollection<UserData1> UserData1Collection { get; set; }
private ObservableCollection<UserData1ViewModel> ConvertModelIntoViewModelCollection(IAnotherService anotherService)
{
var userData1ViewModelCollection = new ObservableCollection<UserData1ViewModel>();
_userService1.GetUserData1().ForEach(user =>
{
userData1ViewModelCollection.Add(new UserData1ViewModel(user, anotherService,...));
});
return userData1ViewModelCollection;
}
}
Now the question:
There is a lot of falling through/passing trough services because I have to call services when for example properties of viewmodels change via lost_focus on gui controls.
Is that all right what I do? Do you see any disadvantage? Or how would you do it?
Update
That DI stuff is a massiv attack on my vicious habits :P
Did you meant it that way Can?
Btw. why should I do that controller factory? Why then not a ServiceFactory too... then we are back to the ServiceLocator...
How do I get now that controller instances in my MainViewModel? via extending the Constructor of my MVM with many additional params? ending up with 30 params? ...
protected override void OnStartup(StartupEventArgs e)
{
IContainerBuilder builder = new ContainerBuilder();
// Firstly Register ALL existing Services
builder.Register<IAdminService, AdminService>();
builder.Register<IDocumentService, DocumentService>();
builder.Register<ILessonPlannerService, LessonPlannerService>();
builder.Register<IMediator, Mediator>();
builder.Register<IMainRepository, MainRepository>();
builder.Register<MainViewModel>();
IContainer _container = builder.Build();
// THEN Register ALL Controllers needing the previously registered Services
IControllerFactory factory = new ControllerFactory(builder);
IDailyPlanner controller1 = factory.Create<IDailyPlanner>();
IWeeklyPlanner controller2 = factory.Create<IWeeklyPlanner>();
SchoolclassAdministrationViewModel controller3 = factory.Create<SchoolclassAdministrationViewModel>();
// THEN Register the mainViewModel(MainController) which should take ALL Services and ALL Controller... WOW thats a massive Ctor param count... is that pure? Did you mean it that way???
MainViewModel mainViewModel = _container.Resolve<MainViewModel>();
//MainWindow mainWindow = _container.Resolve<MainWindow>();
//mainWindow.DataContext = mainViewModel;
//mainWindow.ShowDialog();
}
public class ControllerFactory : IControllerFactory
{
private readonly IContainerBuilder _builder;
private readonly IContainer _container;
/// <summary>
/// Takes the IOC container to register all Controllers
/// </summary>
public ControllerFactory(IContainerBuilder builder)
{
_builder = builder;
_builder.Register<SchoolclassAdministrationViewModel>();
_builder.Register<IDailyPlanner, LessonPlannerDailyViewModel>();
_builder.Register<IWeeklyPlanner, LessonPlannerWeeklyViewModel>();
_container = _builder.Build();
}
/// <summary>
/// Returns an Instance of a given Type
/// </summary>
public T Create<T>()
{
return _container.Resolve<T>();
}
}
Update2:
Now I changed my code that the MainViewModel accepts the IControllerFactory as Parameter and added these two lines of code to the App class:
builder.Register<IControllerFactory, ControllerFactory>();
builder.Register<IContainerBuilder, ContainerBuilder>();
That way I dont need to pass all controllers in the MainViewModel Ctor instead the MainViewModel gets the controller instances from the Factory.
Is there anything better I can do here? Or is that an acceptable good solution? I have no experience at all with DI so I ask :)
Update3
OK I did some code refactoring and made comments for others so they understand whats the final solution:
protected override void OnStartup(StartupEventArgs e)
{
IContainerBuilder builder = new ContainerBuilder();
// Firstly Register ALL existing Services
builder.Register<IAdminService, AdminService>();
builder.Register<IDocumentService, DocumentService>();
builder.Register<ILessonPlannerService, LessonPlannerService>();
builder.Register<IMediator, Mediator>();
builder.Register<IMainRepository, MainRepository>();
builder.Register<IControllerFactory, ControllerFactory>();
builder.Register<IDailyPlanner, LessonPlannerDailyViewModel>();
builder.Register<IWeeklyPlanner, LessonPlannerWeeklyViewModel>();
// Just for visual separation THEN register the MainController driving all other Controllers created via the IControllerFactory
builder.Register<MainViewModel>();
// Build the container
IContainer container = builder.Build();
// THEN Register the MainController which should take ALL IServices and the IFactory
MainViewModel mainViewModel = container.Resolve<MainViewModel>();
// LATER in the mainViewModel`s Ctor you can create all 10 Controller instances with the IControllerFactory like this
// _dailyPlannerController = controllerFactory.Create<IDailyPlanner>();
MainWindow mainWindow = new MainWindow();
mainWindow.DataContext = mainViewModel;
mainWindow.ShowDialog();
}
public class ControllerFactory : IControllerFactory
{
private readonly IContainer _container;
/// <summary>
/// Takes the IOC container to resolve all Controllers
/// </summary>
public ControllerFactory(IContainer container)
{
_container = container;
}
/// <summary>
/// Returns an Instance of a given Type
/// </summary>
public T Create<T>()
{
return _container.Resolve<T>();
}
}
Thank you very much for your time, @Can. I have learned a lot!