2010-01-27 74 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 
{ 
    // ... 
}