How to organize MVP with an IoC container?

旧巷老猫 提交于 2019-12-03 00:35:39

Your problem is that there is a dependency cycle between the View and the Presenter, since they depend on each other. The general rule in breaking this dependency cycle is to fallback to property injection, which will work in your case as well.

With MVP, best is to let the View assign itself to a created Presenter by injecting it into a property of the Presenter:

mPresenter = container.Resolve<Presenter>();
mPresenter.View = this;

If you can, hide the container from the application. Since you are using MVP, the only things you'll ever need to directly resolve are presenters. So instead of letting the Forms communicate with the Container, let them communicate with a static PresenterFactory. This factory will use the container under the covers:

mPresenter = PresenterFactory.Create<MyPresenter>();
mPresenter.View = this;

Your PresenterFactory might look like this:

public static class PresenterFactory
{
    private static IContainer container;

    public static TPresenter Create<TPresenter>()
        where TPresenter : IPresenter
    {
        return (TPresenter)
            container.Resolve(typeof(TPresenter));
    }

    public static void SetContainer(IContainer container)
    {
        PresenterFactory.container = container;
    }
}

And your Composition Root might look like this:

static void Main()
{
    Bootstrap();
}

private static void Bootstrap()
{
    var builder = new ContainerBuilder();
    // TODO: register presenters

    var container = builder.Build();

    PresenterFactory.SetContainer(container);
}

UPDATE

Perhaps even better would it be to do something like this:

interface IPresenter<TView>
{
    TView View { get; set; }
}

public static class PresenterFactory
{
    private static IContainer container;

    public static IPresenter<TView> CreateForView<TView>(TView view)
    {
        var presenter = container.Resolve<IPresenter<TView>>();
        presenter.View = view;
        return presenter;
    }
}

// View
mPresenter = PresenterFactory.CreateForView(this);

This hides the actual implementation of the presenter from the view and centralizes the registration of the view to the presenter.

Alexey Zimarev

You need a property in the presenter

public IAppService service;

and it will be injected by the container, you don't need to pass it as a parameter. What you wrote is a service locator, in fact an anti-pattern for IoC.

If your view is strongly typed and registered with the container too, you can use .SingleInstance lifecycle of Autofac and a property

public IMyView view;

in your presented, the container will then inject the view instance into your presenter.

You basically look the code in another question: Register a Presenter with a View

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!