WebFormsMvp 使用 (ASP.NET Model-View-Presenter tool)

Web Forms Mvp 使用 (ASP.NET Model-View-Presenter tool)
簡單介紹用Web Forms Mvp component 來寫ASP.NET Model-View-Presenter pattern

雖然用 MVP(Model-View-Presenter) 模式寫 asp.net 有蠻長的一段時間了,但 code 幾乎都是自己實作出來

其實有一些third-party 的component 可以使用,現在要簡介是WebFormsMvp

因為之前都是CTP版,總覺得在正式專案中使用並不妥,不過到了2011年3月出了 V1 版,目前已到 V1.2 版

所以打算先來試看看,或許下一個專案會改用

 

此篇重心放在WebFormsMvp 介紹,關於Model-View-Presenter 的pattern 並不詳細說明,可以參考我之前的文章ASP.NETMVP UnitTest,或網路上search 也有一堆

至於使用它帶來的優缺點,自己或團隊要斟酌,不過我是覺得對於中大型的專案來說,是足以承擔MVP pattern所造成的成本,進而享受帶來的好處

 

1.首先加入WebFormsMvp library (WebFormsMvp 只支援NuGet)

1.AddLibrary

除了Web forms MVP 本身外,另外也提供Presenter 支援數種 IoC  ,例如Castle Windsor, Autofac, Unity….,不過在此做不說明了

 

2. 加入WebFormsMvp dll之後,我用一個簡單的範例來做說明,一個顯示人員的Page(ListPeopleWeb.aspx)

ListPeople

點選PersonId hyperlink進入單一人員Page(Person.aspx) 這2頁

Person

 

首先建立一個Person class


	public class Person {

		public Int32 PersonId { get; set; }

		public String Name { get; set; }		

		public String Group { get; set; }
	}

 

以及一個PersonService class,提供資料來源查詢


	public class PersonService {

		private static List<Person> People = new List<Person> { 
				new Person{PersonId = 1, Name = "蒙其·D·魯夫", Group = "草帽海賊團"},
				new Person{PersonId = 2, Name = "羅羅亞·索隆", Group = "草帽海賊團"},
				new Person{PersonId = 3, Name = "娜美", Group = "草帽海賊團"},
				new Person{PersonId = 4, Name = "騙人布", Group = "草帽海賊團"},
				new Person{PersonId = 5, Name = "香吉士", Group = "草帽海賊團"},
				new Person{PersonId = 6, Name = "多尼多尼·喬巴", Group = "草帽海賊團"},
				new Person{PersonId = 7, Name = "妮可·羅賓", Group = "草帽海賊團"},
				new Person{PersonId = 8, Name = "佛朗基", Group = "草帽海賊團"},
				new Person{PersonId = 9, Name = "布魯克", Group = "草帽海賊團"},
				new Person{PersonId = 10, Name = "「鷹眼」喬拉可爾·密佛格", Group = "王下七武海"},
				new Person{PersonId = 11, Name = "「暴君」巴索羅繆·大熊", Group = "王下七武海"},
				new Person{PersonId = 12, Name = "唐吉訶德·多佛朗明哥", Group = "王下七武海"},
				new Person{PersonId = 13, Name = "「海賊女帝」波雅·漢考克", Group = "王下七武海"},
				new Person{PersonId = 14, Name = "克洛克達爾", Group = "王下七武海"},
				new Person{PersonId = 15, Name = "「海俠」甚平", Group = "王下七武海"},
				new Person{PersonId = 16, Name = "「黑鬍子」馬歇爾·D·汀奇", Group = "王下七武海"},
				new Person{PersonId = 17, Name = "「月光·摩利亞", Group = "王下七武海"},
			};

		public IList<Person> GetPeople() {
			return People;
		}


		public Person FindPerson(int personId) {
			return People.FirstOrDefault(p => p.PersonId == personId);
		}		
	}

 

再來從ListPeople.aspx 下手,先建立一個ListPeopleView interface,繼承WebFormsMvp.IView interface

我個人習慣用event-driven,因此加入Query event,作為UI觸發display GridView event,而PeopleSource與TotalRowCount property 是給為UI Datasource object 使用

 

 


	public interface IListPeopleView : WebFormsMvp.IView {

		event QueryEventHandler Query;

		IEnumerable<Person> PeopleSource { set; }

		Int32 TotlaRowCount { set; }
	}

 

其中QueryEventHandler 會用到分頁的處理,因此加入StartIndex與MaxNumber property,當然如有需要,可以再加入Sorting 用的property


	public class QueryEventArgs {

		public int StartIndex { get; set; }

		public int MaxNumber { get; set; }

	}

	public delegate void QueryEventHandler(object sender, QueryEventArgs e);

 

另外建立處理的Presenter, ListPeoplePresenter,繼承WebFormsMvp.Presenter<>


	public class ListPeoplePresenter : WebFormsMvp.Presenter<IListPeopleView> {

		public ListPeoplePresenter(IListPeopleView view): base(view) {
			this.View.Query += new EventArguments.QueryEventHandler(View_Query);
		}

		void View_Query(object sender, EventArguments.QueryEventArgs e) {
			var service = new PersonService();
			this.View.TotlaRowCount = service.GetPeople().Count();
			this.View.PeopleSource = service.GetPeople().Skip(e.StartIndex).Take(e.MaxNumber);
		}
	}

 

 

 

最後完成ListPeopleWeb.aspx.cs,繼承WebFormsMvp.Web.MvpPage,並implement IListPeopleView

(若是UserControl ,則繼承WebFormsMvp.Web.MvpUserControl)

另用WebFormsMvp.PresenterBindingAttribute方式來宣告要用的Presenter


[PresenterBinding(typeof(ListPeoplePresenter))]
	public partial class ListPeopleWeb : WebFormsMvp.Web.MvpPage, IListPeopleView {

		protected void Page_Load(object sender, EventArgs e) {
			this.AutoDataBind = false;
		}

		#region IListPeopleView Members

		public event EventArguments.QueryEventHandler Query;
		
		public IEnumerable<Models.Person> PeopleSource {
			set { this.odsPeople.DataSource = value; }
		}

		public int TotlaRowCount {
			set { this.odsPeople.TotalRowCount = value; }
		}

		#endregion

		protected void odsPeople_Selecting(object sender, ObjectContainerDataSourceSelectingEventArgs e) {
			if (Query != null) {
				this.Query(this, new EventArguments.QueryEventArgs { StartIndex = e.Arguments.StartRowIndex, MaxNumber = e.Arguments.MaximumRows });
			}
		}

	}

上面的code 中,我的GridView 使用的DataSource 是ObjectContainerDataSource,雖然Web Forms MVP 有提供PageDataSource

但我個人還是喜歡用這個DataSource,主要的原因還是在於該object 是以event-driven 為出發點來設計

如此一來 ListPeopleWeb.aspx 即完成

 

3. 再來設計顯示單一Person 資料(PersonWeb.aspx),同樣先針對View與Presenter 做設計

IPersonView  interface,繼承IView<Model> ,這裡的Model 有點像是ASP.NET MVC 中的Model 概念


	public interface IPersonView : IView<Person>{

		Int32 PersonId { get; }
	}

所以若是習慣用ViewModel方式來處理Page 的資訊呈現,像是上面的ListPeopleView 也可以修改成ViewModel 方式,不過要多寫class 就是了

 

PersonPresenter class


	public class PersonPresenter : Presenter<IPersonView> {

		public PersonPresenter(IPersonView view) : base(view){
			this.View.Load += new EventHandler(View_Load);
		}

		void View_Load(object sender, EventArgs e) {
			var service = new PersonService();
			var person = service.FindPerson(this.View.PersonId);
			this.View.Model = person ?? new Person();
		}
	}

PersonWeb.aspx.cs,繼承MvpPage<Person> class


	[PresenterBinding(typeof(PersonPresenter))]
	public partial class PersonWeb : MvpPage<Person>, IPersonView {

		protected void Page_Load(object sender, EventArgs e) {

		}

		#region IPersonView Members

		public int PersonId {
			get {
				int personId;
				if (Int32.TryParse(Request.QueryString["personId"], out personId)) {
					return personId;
				}

				return 0;
			}
		}

		#endregion
	}

PersonWeb.aspx 的webcontrol可以直接Bind Model class來使用


	<div>
		<div>
			Name : <%# Model.Name%>
		</div>
		<div>
			Group : <%# Model.Group %>
		</div>
	</div>

 

簡單介紹到此。如果你是第一次接觸MVP pattern ,建議還是先看其他Model-View-Presenter文章,瞭解其基本架構

下載Sample Code MVPSampleWeb.zip