使用StructureMap在Model-View-Presenter模式中进行Presenter注入

6
我已经实现了自己的模型视图控制器模式副本(类似于Web客户端软件工厂),这样我就可以利用自己的DI框架,而不必受WCSF的ObjectBuilder的约束,因为我有很多问题。我想到了几种方法,但没有一种让我特别满意。我想知道是否还有其他人有其他想法。

解决方案#1a

使用HttpModule拦截context.PreRequestHandlerExecute以调用ObjectFactory.BuildUp(HttpContext.Current.Handler)

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

解决方案#1b

在页面加载时调用生成而不是使用HttpModule。

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        ObjectFactory.BuildUp(this);
    }
}

解决方案 #1c

如果需要,通过属性允许Getter来构建Presenter。

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    public EmployeePresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                ObjectFactory.BuildUp(this);
            }

            return _presenter;
        }
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

解决方案 #2

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                _presenter = ObjectFactory.GetInstance<EmployeePresenter>();
                _presenter.View = this;
            }

            return _presenter;
        }
    }
}

解决方案#2b

public partial class _Default : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    private EmployeePresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                Presenter = ObjectFactory.GetInstance<EmployeePresenter>();
            }

            return _presenter;
        }
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

Edit: Added solution 1c, 2b

4个回答

7
我会使用解决方案#1b,并为所有页面创建一个层超类型,以便更好地DRY演示者初始化。就像这样:
页面代码:
public partial class _Default : AbstractPage, IEmployeeView
{
    private EmployeePresenter presenter;

    private EmployeePresenter Presenter
    {
        set
        {
            presenter = value;
            presenter.View = this;
        }
    }
    protected override void Do_Load(object sender, EventArgs args)
    {
        //do "on load" stuff 
    }

}

摘要页面代码:

public abstract class AbstractPage : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ObjectFactory.BuildUp(this);
        this.Do_Load(sender,e); 
        //template method, to enable subclasses to mimic "Page_load" event

    }
    //Default Implementation (do nothing)
    protected virtual void Do_Load(object sender, EventArgs e){}
}

使用这个解决方案,您只需要在一个类中进行演示者初始化(由ObjectFactory创建),如果以后需要修改它,您可以轻松地完成。

编辑:

Do_Load应该是抽象的还是虚拟的?

模板方法最初指出该方法应该是抽象的,以强制子类实现它,遵守超类合同。(请参见维基百科上“大富翁”<“游戏”的例子)。

另一方面,在这种特殊情况下,我们不想强制用户类重新定义我们的方法,而是给它这样做的机会。如果您将其声明为抽象的,许多类将被迫重新定义该方法,只是将其留空(这显然是一种代码味道)。因此,我们提供一个明智的默认值(什么都不做)并使该方法成为虚拟的。


这可能会成为被接受的答案,我唯一遇到问题的是决定Do_Load更好地标记为虚拟还是抽象。 - Chris Marisic

1

我也建立了自己的MVP框架。我发现对我来说最好的方法是使用基于页面类的泛型。通过在泛型类定义中指定Presenter类型,我可以省略掉每个提案所需的大部分代码。

然而,这种方式有一些我不喜欢的地方。类定义可能会变得相当复杂,并且对于新手来说并不容易阅读。我还没有完全解决如何在基础页面中使用事件模型的好方法。

很抱歉我没有在这里为您提供代码,但如果您希望,我可以为您发布一些。我还在www.codeplex.com/aspnetmvp上发布了旧版本的代码,如果您想看看它是如何工作的。


1

我一直在使用一个基础页面类,其中包括:

protected override void OnInit(EventArgs e)
    {
        StructureMap.ObjectFactory.BuildUp(this);
        base.OnInit(e);
    }

基类方法同样适用于用户控件,这让我不想使用模块(不想有两种设置方式)。 对于页面而言,则是这样的

public partial class Employee : View, IEmployeeView
{
    public ViewPresenter Presenter { get; set; }
    private void Page_Load(object sender, EventArgs e){}
}

我通过构造函数注入视图。为了避免在structuremap配置中出现循环引用问题,只需使用此辅助方法:

static T GetView<T>()
{
    return (T) HttpContext.Current.Handler;
}

在StructureMap配置中,使用一个约定来进行Presenter和View注入。

0

非常感谢大家宝贵的意见。你们的答案给了我宝贵的想法,让我最终得出了这个方案:

public abstract class ViewBasePage<TPresenter, TView> :
    Page where TPresenter : Presenter<TView>
{
    protected TPresenter _presenter;

    public TPresenter Presenter
    {
        set
        {
            _presenter = value;
            _presenter.View = GetView();
        }
    }

    /// <summary>
    /// Gets the view. This will get the page during the ASP.NET
    /// life cycle where the physical page inherits the view
    /// </summary>
    /// <returns></returns>    
    private static TView GetView()
    {
        return (TView) HttpContext.Current.Handler;
    }

    protected override void OnPreInit(EventArgs e)
    {
        ObjectFactory.BuildUp(this);
        base.OnPreInit(e);
    }
}

并且被我的原始页面继承:

public partial class _Default : 
    ViewBasePage<EmployeePresenter, IEmployeeView>, IEmployeeView
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            _presenter.OnViewInitialized();
        }

        _presenter.OnViewLoaded();
        Page.DataBind();
    }

    #region Implementation of IEmployeeView

    ...

    #endregion
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接