StructureMap을 사용한 모델-뷰-전진자 패턴의 발표자 주입
-
21-08-2019 - |
문제
나는 자신의 모델보기 발표자 패턴 (웹 클라이언트 소프트웨어 공장의 정맥) 사본을 구현하여 수많은 문제가있는 WCSF의 ObjectBuilder에 연결되는 대신 내 자신의 DI 프레임 워크를 활용할 수 있습니다. 나는 그것을 할 수있는 몇 가지 방법을 생각해 냈지만 그들 중 누구도 특히 나를 행복하게하지 않습니다. 다른 사람이 다른 아이디어를 가지고 있는지 알고 싶었습니다.
해결책 #1A
httpmodule을 사용하여 컨텍스트를 가로 채기 위해 객체 actortory.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가 빌드 업을 할 수 있습니다.
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;
}
}
}
편집하다: 추가 용액 1c, 2b
해결책
솔루션 #1B를 사용하고 a 레이어 슈퍼 타입 모든 페이지의 경우 발표자 초기화를 조금 더 건조시키기 위해. 이와 같이:
페이지 코드 :
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해야합니다 요약 또는 가상 ?
템플릿 메소드 원래이 방법은 서브 클래스가이를 구현하도록 강제하여 수퍼 클래스 계약을 준수하기 위해 추상적이어야한다고 말합니다. ( "독점"< "게임"의 Wikipedia 예제 참조).
반면 에이 특정한 경우, 우리는 사용자 클래스가 우리의 방법을 재정의하도록 강요하고 싶지 않지만 그렇게 할 기회를줍니다. 당신이 그것을 추상적으로 선언한다면, 많은 클래스는 그 방법을 비워 두는 방법을 재정의해야합니다 (이것은 분명히 코드 냄새입니다). 따라서 우리는 현명한 기본값을 제공하고 (아무것도하지 않음) 방법을 가상으로 만듭니다.
다른 팁
나는 나 자신의 MVP 프레임 워크를 만들었습니다. 가장 좋은 방법은 기본 페이지 클래스와 함께 제네릭을 사용하는 것입니다. 일반 클래스 정의에서 발표자 유형을 지정하면 각 제안에 필요한 대부분의 코드를 놓칠 수 있습니다.
그러나 그렇게하는 것에 대해 내가 좋아하지 않는 것들이 있습니다. 클래스 정의는 다소 복잡해 보일 수 있으며 초보자를 읽기 쉽지 않습니다. 또한 기본 페이지에서 이벤트 모델을 사용하는 좋은 방법을 완전히 해결하지 못했습니다.
죄송합니다. 여기에 코드가 없지만 원하는 경우 게시 할 수 있습니다. 또한 www.codeplex.com/aspnetmvp에 게시 된 이전 버전의 코드가 있습니다.
나는 다음과 같이 기본 페이지 클래스를 사용하고 있습니다.
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 구성에서 발표자와 뷰 주입 모두에 대한 컨벤션을 사용하십시오.
매우 귀중한 의견에 감사드립니다. 귀하의 답변은 각각 내 최종 솔루션에서 함께 결합 할 수있는 귀중한 아이디어를 주었고 이것이 제가 생각해 낸 것입니다.
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
}