Dependency Injection in WinForms using Ninject and Entity Framework

19,626

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

Share:
19,626
XN16
Author by

XN16

Senior Software Developer in the MIS and Fabrication EPoS Energy Supplier EPoS Apprentice industry.

Updated on June 03, 2022

Comments

  • XN16
    XN16 about 2 years

    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

  • XN16
    XN16 over 11 years
    Thanks very much, I have managed to implement a version of your example successfully.
  • FMM
    FMM over 11 years
    I think you're missing the point of what a Composition Root is intended to do. Your "Composition Root" is actually a service locator, which is often considered an antipattern. A true composition root is the "top level" object in your running application's object graph, and should be the only object that you explicitly ask for from the kernel (factories excluded). Everything else should be resolved via injection when the root is constructed, or via instantiation via a factory.
  • Ilya Ivanov
    Ilya Ivanov over 11 years
    My CompositionRoot is not a service locator. Form1 ask IRepository<Process> as constructor argument, not CompositionRoot. CompositionRoot resolves a complete objects graph at the start of the application. You don't ask CompositionRoot from the kernel, but instead you ask the top objects from CompositionRoot and it provides a complete resolved object graphs for you.
  • FMM
    FMM over 11 years
    The method public static T Resolve<T>() { } makes it a service locator, especially considering there's no appreciable logic in your CompositionRoot class to handle composing modules. There's nothing to "compose" in your composition root, there's only one module. We're likely arguing semantics here. In a simple winforms app, the main form serves as the composition root, since it is the "root" of the object graph and all objects reachable from it are instantiated either by constructor injection or instantiation via a factory.
  • Ilya Ivanov
    Ilya Ivanov over 11 years
    Does public T Get<T>() in IKernel makes it a service locator? If it is static it doesn't mean, that it is service locator. I don't want to use Form1 as a composition root because it has it's own logic, which you don't want to touch in tests. Also, in tests you should also create yet another CompositionRoot?
  • Ilya Ivanov
    Ilya Ivanov over 11 years
    I think i've got what you mean. Mark Seeman provide similar example of Service Locator at his blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx. But there are key differences - SL uses dictionary, which is crutial, also in constructor you call SL.Resolve<T> while call I call Root in one place and nowhere else. If any misunderstandings left - please note
  • Zoltán Tamási
    Zoltán Tamási about 11 years
    @IlyaIvanov, this looks nice in this simple scenario. I would like to know what you think a best practice would be if my "main" form would have to create sub forms, also using DI. How would I avoid calling the CompositionRoot.Resolve method there (which would be treated as the "evil service locator")? Thank you for your update.
  • wezzix
    wezzix over 9 years
    The creation of objects after the top level object has been created is usually done using factories. There is a factory extension to NInject which makes this convenient github.com/ninject/ninject.extensions.factory/wiki equivalent to Autofac DelegateFactory.
  • MoonKnight
    MoonKnight over 8 years
    @IlyaIvanov why are you not implementing the "Register, Resolve, Release" methodology that Seemann seems to suggest we must when using a DI Container (Section 3.3.2 in his book)? I am totally new to this and am following what you have provided above, but am slightly confused over the use of Factories against what you are doing here? Why do we need this? I also assume I am free to implement a "Release" method in CompositionRoot and implement IDisposible which merely calls ninjectKernel.Dispose()?
  • MoonKnight
    MoonKnight over 8 years
    Ps. I have a question with an open bounty here stackoverflow.com/questions/35802180/…