2010-01-27 39 views
2

我最近阅读Phil Haack's post,他给出了一个实现用于ASP.NET的Model View Presenter的示例。其中一个代码片段显示了视图类的代码。在ASP.NET MVP应用程序中注入Presenter中的较低层依赖关系

public partial class _Default : System.Web.UI.Page, IPostEditView 
{  
    PostEditController controller; 
    public _Default() 
    { 
     this.controller = new PostEditController(this, new BlogDataService()); 
    } 
} 

但是,这里视图构造了BlogDataService的实例并将其传递给演示者。理想情况下,视图不应该了解BlogDataService或任何演示者的较低层依赖关系。但我也更愿意将BlogDataService作为构造函数注入演示者的依赖项,因为它使演示者的依赖性显式化。

在stackoverflow上发送同样的问题here

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

有没有办法使用IoC或DI容器工具自动构造演示者对象,以便视图不必处理显式创建BlogDataService对象并将视图和服务实例注入演示者的构造函数中。尽可能使用构造函数注入模式。

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

感谢您的任何反馈意见。

回答

2

是的。例如,在Web窗体构造函数中使用StructureMap:

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

.... 
} 

,正如你可以在这里看到演示者需要视图和服务注入

public AttributeDetailPresenter(IAttributeDetailView view, IAttributeService attributeService) 
     { 
      MyForm = view; 
      AppService = attributeService; 
     } 

您还可以使用StructureMap 积累功能的web表单,这样就可以避免直接在视图中使用ObjectFactory。

+0

@eptika - 感谢您的答复。这比构建服务对象并将其传递给演示者的视图更好。 – Scott 2010-01-30 17:37:15

+0

WinForms应用程序的设计会改变吗?在WinForms应用程序中,首先创建视图,然后创建WebForms中的演示者,还是以其他方式? – Scott 2010-01-30 18:12:34

2

我做了这个。该解决方案基于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并将它们传递到请求(目前的页为好) :

protected override bool OnBubbleEvent(object source, EventArgs args) 
{ 
    var cancel = false; 

    if(args is PresentableEventArgs) 
    { 
     cancel = true; 

     Present(source); 
    } 
    else 
    { 
     cancel = base.OnBubbleEvent(source, args); 
    } 

    return cancel; 
} 

protected override void OnLoad(EventArgs e) 
{ 
    base.OnLoad(e); 

    Present(this); 
} 

private void Present(object view) 
{ 
    if(MvpRequest != null && view != null) 
    { 
     MvpRequest.Present(view); 
    } 
} 

最后,创建用于每个类型的控制的基类要充当视图(主页,复合控制等):

public abstract class UserControlView : UserControl 
{ 
    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     EnsureChildControls(); 

     RaiseBubbleEvent(this, new PresentableEventArgs()); 
    } 
} 

这将控制树通过IMvpRequest连接到MVP系统,您现在必须在应用程序级容器中实施和注册。 ASP.NET集成应该注意将实现注入到页面中。这将页面完全从创建者分离出来,依靠IMvpRequest来完成映射。

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

您将有某种从视图类型的地图的演示者类型:

public interface IPresenterMap 
{ 
    Type GetPresenterType(Type viewType); 
} 

这些都是你会从容器中解决的类型。

(这里的一个问题是视图已经存在,这意味着容器不会创建实例或者不知道它,您必须将它作为解析参数传递,这是大多数容器支持的另一个概念。 )

一个体面的默认映射可能是这样的:

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