Dependency Injection in WinForms using Ninject and Entity Framework

XN16 picture XN16 · Jan 2, 2013 · Viewed 18.1k times · Source

I am currently working on a project where we are converting our old DataSet, Stored Procedure WinForm application to use Entity Framework so new websites can access the same object model and repositories.

Anyway, I am trying to implement Dependency Injection into the Forms so that we can use mocked Repositories for unit testing. I am using Ninject for the the simple reason I have used it before in MVC websites, however trying to implement this in the WinForm application is proving to be problematic to say the least, hampered even more by the lack of information on DI in WinForms on the web.

So far I have created the Ninject Factory and repositories, but I haven't had much luck injecting the repositories into forms.

Therefore can anyone help me or make any suggestions?

Below I have parts of my code that might help:

Ninject Factory:

public class NinjectFactory : NinjectModule
{
    private IKernel _ninjectKernel;

    public NinjectFactory()
    {
        _ninjectKernel = new StandardKernel();
    }

    public override void Load()
    {
        _ninjectKernel.Bind(typeof(IRepository<>)).To(typeof(GenericRepository<>));
        _ninjectKernel.Bind(typeof(IProductionRepository)).To(typeof(ProductionRepository));
    }
}

Form with repositories:

Public Class TaskForm
    Inherits BaseBusinessDialogForm

    Private _repository As TaskRepository
    Private _task As Production.Task = Nothing

    Public Sub New(ByVal task As Production.Task)

        InitializeComponent()

        _repository = New TaskRepository(ConnectString)

        If task.TaskID = 0 Then
            _task = task
        Else
            _task = _repository.GetByID(task.TaskID)
        End If

        MyBase.BusinessObject = _task
        Me.TaskBindingSource.DataSource = MyBase.BusinessObject

    End Sub

Class that launches the MDI form which holds the above form:

Dim kernel As IKernel = New StandardKernel(New NinjectFactory())
''Dim kernel As IKernel = New StandardKernel(New NinjectFactoryTest())
mfrmMDI = kernel.Get(Of Forms.MDI)()

Application.DoEvents()
mfrmMDI.ShowDialog()

I understand that my question is a bit vague, but I'm not sure where the problem lies or what I need to complete.

Thanks very much

Answer

Ilya Ivanov picture Ilya Ivanov · Jan 4, 2013

You create composition root as one entry point for your resolutions. You pass INjectModule as a parameter so that you can configure it it tests differently. One of the benefits of Composition Root is that not all of your assemblies will depend on NInject and you will have one single point to change resolution logic. It is really a cool pattern, when you might change IoC container or introduce some dynamic interception in future.

public class CompositionRoot
{
    private static IKernel _ninjectKernel;

    public static void Wire(INinjectModule module)
    {
        _ninjectKernel = new StandardKernel(module);
    }

    public static T Resolve<T>()
    {
        return _ninjectKernel.Get<T>();
    }
}

Your module would look like this

public class ApplicationModule : NinjectModule
{
    public override void Load()
    {
        Bind(typeof(IRepository<>)).To(typeof(GenericRepository<>));
    }
}

In main method you pass ApplicationModule as a parameter and resolve Form1 and start it.

[STAThread]
static void Main()
{
    CompositionRoot.Wire(new ApplicationModule());

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    Application.Run(CompositionRoot.Resolve<Form1>());
}

In Form1 constructor you pass required repository with specific closed generic parameters

public partial class Form1 : Form
{
    private IRepository<Process> _processRepository;

    public Form1(IRepository<Process> productionRepository)
    {
        this._processRepository = productionRepository;        
        InitializeComponent();
    }  

    private void button1_Click(object sender, EventArgs e)
    {
        MessageBox.Show(_processRepository.ToString());
    }
}

Your repositories could be very complex, but I won't add any functionality to them, instead of ToString() method so that we could see if a dependency was resolved correctly. Note there are no attributes whatsoever on repositories.

public interface IRepository<T>
{
}

public class GenericRepository<T> : IRepository<T>
{
    public override string ToString()
    {
        return "MyRepository with type : "+typeof(T).Name;
    }
}

Now when you run your application, you will see, that all has wired up and message box shows an enclosed type as Process

enter image description here