質問

I have a presenter to handle the behaviour of my form something like this:

public class Form1Presenter
{
    IForm1View _view;
    IUnitOfWork _unitOfWork;
    IService1 _service1;
    IService2 _service;

    public Form1Presenter(
        IForm1View view,
        IUnitOfWork unitOfWork,
        IService1 service1,
        IService2 service2)
    {
        _view = view;
        _unitOfWork = unitOfWork;
        _service1 = service1;
        _service2 = service2;
    }
}

The services are injected with the same unit of work object as is injected into the presenter above. Like this:

public class Service1 : IService1
{
    IUnitOfWork _unitOfWork;

    public Service1(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
}

To create Form1Presenter by hand, I'd have to do something like this:

public class Form1 : Form, IForm1View
{
    public Form1()
    {
        IUnitOfWork unitOfWork = new UnitOfWork();
        IService1 service1 = new Service1(unitOfWork);
        IService1 service2 = new Service2(unitOfWork);
        Form1Presenter presenter = new Form1Presenter(this, unitOfWork, service1, service2);
    }
}

Is there a nice way to do this with Ninject? I'm new to this and can't seem to work it out.

役に立ちましたか?

解決

So you want to create a unit of work for each form. I'm not going into whether that is a sensible choice or not.

There's several ways to achieve this:

1 - manual management

var unitOfWork = IResolutionRoot.Get<IUnitOfWork>();
IResolutionRoot.Get<Form1Presenter>(new ConstructorArgument("unitOfWork", unitOfWork, true);

Here you have ninject create a unit of work, then request a form and put the unitOfWork as ConstructorArgument on the request. The form and all it's dependencies which use the unitOfWork need to have a constructor parameter IUnitOfWork unitOfWork. The name needs to be same as specified in the constructor argument.

So this is quite a lot of work and does not make use of all the sweetnees an IoC can provide. So i would not recommend using this approach.

2 Named Scope

Have a look at Ninject Named Scope Extension. Create the bindings as follows:

const string UnitOfWorkScopeName = "UnitOfWorkScopeName";

IBindingRoot.Bind<IUnitOfWork>().To<UnitOfWork>()
            .InNamedScope(UnitOfWorkScopeName);

IBindingRoot.Bind<Form1Presenter>().ToSelf()
            .DefinesNamedScope(UnitOfWorkScopeName);
IBindingRoot.Bind<Form2Presenter>().ToSelf()
            .DefinesNamedScope(UnitOfWorkScopeName);
IBindingRoot.Bind<Form3Presenter>().ToSelf()
            .DefinesNamedScope(UnitOfWorkScopeName);

This will result in all the object bound with DefinesNamedScope and all it's dependencies getting the same instance of IUnitOfWork. However, you can never instanciate an IUnitOfWork when you are not in the correct scope. Thus all your forms need to define a (the same) scope. Also, a form may not depend on another form, because then you would have scope overlap.

3 Call Scope

InCallScope() means that all objects created by one IResolutionRoot.Get() will receive the same object.

IBindingRoot.Bind<IUnitOfWork>().To<UnitOfWork>()
            .InCallScope();

The bindings of all other components does not need to be adjusted.

This does not work in case you are instanciating multiple forms by one call to IResolutionRoot.Get()


Of course there's even more ways how you can manage the lifetime of a unit of work. We have decoupled session management from IUnitOfWork and use a ThreadLocal to determine whether we need to start a new session/transaction or use an existing one.

他のヒント

Install Ninject.Extensions.Conventions and then you can bind all classes to their default interface (class name with an "I" in front) like this

IKernel kernel = new StandardKernel();
            kernel.Bind(x =>
                x.FromThisAssembly()         // Scans currently assembly
                 .IncludingNonePublicTypes() // Including Non-public types
                 .SelectAllClasses()         // Retrieve all non-abstract classes
                 .BindDefaultInterface());   // Binds the default interface to them, e.g. class name without preceding "I"
var Form1Presenter = kernel.Get<Form1Presenter>();
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top