Cyclic reference issue in MVP pattern using Windsor castle for Dependency injection
Asked Answered
G

2

6

I am facing a problem of cyclic dependency when creating the following MVP design (for winforms) using windsor container.

My presenter depends on the view and model:

ConcretePresenter(IView view, IModel model)
{
    this.view = view;
    this.model = model;
}

My view depends on the presenter:

ConcreteView(ConcretePresenter presenter)
{
    //actual requirement that the presenter use the current instance of the view and a model object 
    //new presenter(this, new model()) 
    this.presenter = presenter;
}

I am registering all components using Windsor castle (in a separate composition root class) as below:

IWindsorContainer container;
container = new WindsorContainer();
container.Register(Component.For<ConcretePresenter>().ImplementedBy<ConcretePresenter>());
container.Register(Component.For<IModel>().ImplementedBy<ConcreteModel>());                      
container.Register(Component.For<IView>().ImplementedBy<ConcreteView>()); 

Resolving the View brings up the issue of cyclic reference issue:

container.Resolve<ConcreteView>(); //doesn't resolve because of cyclic dependency

A possible solution would be to remove the constructor injection from the view and resolve the presenter separately. But this causes me to use the container in two places which i was not looking to do and probably is wrong.

ConcreteView()
{
    container.Resolve<ConcretePresenter>(); //resolving at 2 different points       
}

Is there any better solution to this. Am I doing something wrong in MVP itself?

Glazing answered 20/12, 2012 at 13:27 Comment(1)
possible duplicate: #1783624Pagas
T
4

There are several solutions to this problem, but all of them break the dependency cycle by removing either the presenter or the view from as constructor dependency.

The easiest solution would be by introducing the view as property on the presenter:

// Presenter
ConcretePresenter(IModel model)
{
    this.model = model;
}

public IView View { get; set; }

// View
ConcreteView(ConcretePresenter presenter)
{
    this.presenter = presenter;
    this.presenter.View = this;
}

Downside of this is that you need to configure each presenter as it is injected into the view, so you could also move this to a base class:

// View
ConcreteView(ConcretePresenter presenter) : base(presenter)
{
}

BaseView(IPresenter presenter)
{
    Contract.Requires(presenter != null);
    presenter.View = this;
    this.Presenter = presenter;
}

Another option is to inject a presenter factory into the view and request it from there:

// View
ConcreteView(IPresenterFactory factory)
{
    this.presenter = factory.CreatePresenterFor(this);
}

Downside is that this constructor calls a factory, which is not the cleanest thing to do, but manageable.

Toby answered 21/12, 2012 at 11:26 Comment(2)
I have used the first option as suggested by you and it works for me.Glazing
I think this is poor Di cause Move injection from Composite root to another point.Cargile
M
0

Create a factory for instantiating your presenters. Your view (the WinForm) will use the factory in the constuctor. You could probably use the Typed Factory Facility -- meaning you'd only have to define the interface for the presenter factory and let the facility do the rest.

Mudra answered 20/12, 2012 at 21:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.