在ASP.NET MVP应用程序的Presenter中注入下层依赖项

在ASP.NET MVP应用程序的Presenter中注入下层依赖项,asp.net,dependency-injection,inversion-of-control,mvp,Asp.net,Dependency Injection,Inversion Of Control,Mvp,我最近读了一篇文章,其中他给出了一个为ASP.NET实现模型视图演示器的示例。其中一个代码段显示了视图类的代码是如何运行的 public partial class _Default : System.Web.UI.Page, IPostEditView { PostEditController controller; public _Default() { this.controller = new PostEditController(thi

我最近读了一篇文章,其中他给出了一个为ASP.NET实现模型视图演示器的示例。其中一个代码段显示了视图类的代码是如何运行的

public partial class _Default : System.Web.UI.Page, IPostEditView
{    
    PostEditController controller;
    public _Default()
    {
         this.controller = new PostEditController(this, new BlogDataService());
    }
}
但是,在这里,视图构造了BlogDataService的实例,并将其传递给演示者。理想情况下,视图不应该知道BlogDataService或演示者的任何下层依赖关系。但我也更喜欢将BlogDataService作为演示者的构造函数注入依赖项,因为它使演示者的依赖项显式化

在stackoverflow上也提出了同样的问题

其中一个答案建议使用服务定位器获取BlogDataService的实例,并将其传递给演示者的构造函数。但是,此解决方案无法解决视图了解BlogDataService并需要显式获取其引用的问题

是否有一种方法可以使用IoC或DI容器工具自动构造presenter对象,这样视图就不必显式地创建BlogDataService对象,也不必将视图和服务实例注入presenter的构造函数中。我更喜欢尽可能使用构造函数注入模式

还是有更好的设计来解决这个问题?。如果我构建的是WinForms应用程序而不是ASP.NET WebForms应用程序,是否有更好的方法来实现这一点


谢谢您的反馈。

是的,有。例如,在webform构造函数中使用StructureMap:

 public partial class AttributeDetails : EntityDetailView<AttributeDetailPresenter>, IAttributeDetailView
    {
 public AttributeDetails()
        {
            _presenter = ObjectFactory.With<IAttributeDetailView>(this).GetInstance<AttributeDetailPresenter>();
        }

....
}

您还可以对webforms使用StructureMapBuilding功能,这样您就可以避免在视图中直接使用ObjectFactory。

我就是这么做的。该解决方案基于Autofac,但可以在任何容器上实现

首先,定义一个接口,该接口表示在向MVP系统的请求中显示视图的权限:

public interface IMvpRequest
{
    void Present(object view);
}
接下来,创建具有该类型属性的基本页:

public abstract class PageView : Page
{
    public IMvpRequest MvpRequest { get; set; }
}
此时,为页面设置依赖项注入。大多数容器具有ASP.NET集成,通常以HTTP模块的形式。因为我们不创建页面实例,所以不能使用构造函数注入,只能在这里使用属性注入

设置完成后,创建表示已准备好显示的视图的事件参数:

public class PresentableEventArgs : EventArgs
{}
现在,在
PageView
中捕获事件并将其传递给请求(同时显示页面):

最后,为要用作视图的每种类型的控件(母版页、复合控件等)创建基类:

这将通过
IMvpRequest
将控制树连接到MVP系统,您现在必须在应用程序级容器中实现并注册它。ASP.NET集成应注意将实现注入页面。这使页面完全与演示者创建分离,依靠
IMvpRequest
进行映射

IMvpRequest
的实现将是特定于容器的。演示者将像其他类型一样在容器中注册,这意味着它们的构造函数将自动解析

您将拥有从视图类型到演示者类型的某种映射:

public interface IPresenterMap
{
    Type GetPresenterType(Type viewType);
}
这些是您将从容器解析的类型

(这里的一个问题是视图已经存在,这意味着容器不创建实例,也不知道它。您必须将其作为分辨率参数传入,这是大多数容器支持的另一个概念。)

一个合适的默认映射可能如下所示:

[Presenter(typeof(LogOnPresenter))]
public class LogOnPage : PageView, ILogOnView
{
    // ...
}

@eptika-感谢您的回复。这是一个比构建服务对象并将其传递给演示者的视图更好的解决方案。WinForms应用程序的设计会改变吗?在WinForms应用程序中,是先创建视图,然后再像在WebForms中那样创建演示者,还是相反?
public abstract class UserControlView : UserControl
{
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        EnsureChildControls();

        RaiseBubbleEvent(this, new PresentableEventArgs());
    }
}
public interface IPresenterMap
{
    Type GetPresenterType(Type viewType);
}
[Presenter(typeof(LogOnPresenter))]
public class LogOnPage : PageView, ILogOnView
{
    // ...
}