1

I am working on a WinForms application which has been configured into the typical 3 layers of UI, BLL, and DAL. I created a separate project to act as the startup project. Another project was also created to act as a home made dependency injection container with the purpose of performing all the dependency injection setup. The home made dependency injection container is instantiated by the startup project which then passes in the instantiated objects to the first WinForm.

The home made dependency injection container implementation is shown below:

public class AppDependencyInjection
{
    public BLL.DataServices.DepartmentDataServices BllDeptDataServices = null;
    private DAL.DataServices.DepartmentDataServices DalDeptDataServices = null;

    public BLL.ReportServices.RequestReports BllRequestReports = null;
    private DAL.ReportServices.RequestReports DalRequestReports = null;

    public AppDependencyInjection()
    {
        DalDeptDataServices = new DAL.DataServices.DepartmentDataServices();
        BllDeptDataServices = new BLL.DataServices.DepartmentDataServices(DalDeptDataServices);//inject actual implementations

        DalRequestReports = new DAL.ReportServices.RequestReports();
        BllRequestReports = new BLL.ReportServices.RequestReports(DalRequestReports);//inject actual implementations
    }
}

The startup project is shown below:

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    //instantiate dependent classes and inject into class constructors 
    AppDependencyInjection aDI = new AppDependencyInjection(); 

    //Pass objects with injected dependencies into app startup WinForm
    Application.Run(new MDIS.WinForms.UI.Form1(aDI.BllDeptDataServices, aDI.BllRequestReports));
}

The receiving WinForm is instantiated as follows with the injected objects:

public Form1(BLL.DataServices.DepartmentDataServices aBllDeptDataServices,
             BLL.ReportServices.RequestReports aBllRequestReports)
{
    InitializeComponent();
    BllDeptDataServices = aBllDeptDataServices;
    BllRequestReports = aBllRequestReports;
}

The WinForm uses the injected objects in the following two button click events:

private void btnGetAllDepartments_Click(object sender, EventArgs e)
{
    List<DepartmentDto> aDepartmentDtoList = BllDeptDataServices.GetAllDepartments();
}

private void btnGetAllRequests_Click(object sender, EventArgs e)
{
    List<RequestDetailDto> aRequestDetailDtoList = BllRequestReports.GetAllRequestDetail();
}

This works for now with not much problem because I am only passing in 2 injected objects. But this seems to be a problem if the number of objects grows to more than 5 then I'll be passing in more than 5 parameters to the startup WinForm. I can limit the parameters to be passed in to just one if I decide to pass in the home made dependency injection container called AppDependencyInjection to the WinForm instead of individual injected classes. If I do this, it will make the presentation layer dependent on the home made dependency injection project, thereby making the presentation layer dependent on both the BLL and the dependency injection project. Is this acceptable? What else can I do to accommodate future growth of dependency injected classes in the application?

Robertcode
  • 911
  • 1
  • 13
  • 26

1 Answers1

2

But this seems to be a problem if the number of objects grows to more than 5 then I'll be passing in more than 5 parameters to the startup WinForm.

If you inject more than 5 dependencies, that is an indication that your class does too much; has too many responsibilities. It violates the Single Responsibility Principle. If that happens you start thinking about splitting your classes in multiple smaller classes. For instance, you might be able to group certain dependencies and their logic into Aggregate Services or your can split up our Form into multiple smaller components/controls. Rembember: the key is composition.

I decide to pass in the home made dependency injection container called AppDependencyInjection to the WinForm instead of individual injected classes.

You shouldn't do this. This is a pattern called Service Locator and it has many downsides. Stick to dependency injection and only inject what a class directly needs If this gets cumbersome, for instance because a class has too may dependencies, there's something wrong with your code/design (such as a SRP violation).

Also note that it is not advisable to create your own DI library. Such library will lack many important features that the available DI libraries give you, yet gives no advantage over using Pure DI (i.e. hand-wiring object graphs). You lose compile-time support, without getting anything back.

When your application is small, you should start with Pure DI and once your application and your DI configuration grow to the point that maintaining you Composition Root becomes cumbersome, you could consider switching to one of the established DI libraries.

In your case, it seems you are somewhere in the middle. Although dependencies seem to come from a common 'dependency injector', you are still hand-wiring your classes manually without reflection (i.e. you are calling the constructors explicitly). Please be aware that once you are start using reflection, it becomes time to use one of the known DI libraries.

Siyual
  • 16,415
  • 8
  • 44
  • 58
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thanks Steven. I'm going to investigate Aggregate Services as you suggested. I have about a dozen entity models in my project each which will need repository actions applied like the Department one I used in my example. It sounds like using Aggregate Services I may be able to group several of them together so I don't have to setup an injection for each DAL implementation. – Robertcode Dec 17 '15 at 09:23