[ASP.NET] : 實做 MVC + CRUD Pattern
前言 :
[ASP.NET] : WebForm MVC Pattern
[ASP.NET] : WebForm CRUD Pattern
上面兩篇為之前發表過的兩個ASP.NET的Pattern,內容主要是在描述MVC的分工以及CRUD的頁面。
這篇文章綜合上述的兩個Pattern來實做,以期能更清楚描述出CRUD的樣版以及MVC的精神。
物件導向的程式,因為把職責分散到各個物件去看起來會很零碎。
可能要參照上述兩篇文章內容,才能將程式碼在腦海裡組織起來。
(另外也想傳達物件導向程式撰寫時的思路,所以會顯的囉嗦點...)
系統架構 :
下圖的詳細內容可以參照之前的兩篇文章。
UserData And UserStore :
UserData : 新增修改刪除查詢(CRUD)的物件。
UserStore : 跟儲存裝置做連接的資料連接層。
而在UserStore可以使用UserData的Id來查詢UserData。
public class UserData
{
public Guid Id;
public string Name;
public string Description;
}
public class UserStore
{
// Operate
public void Insert(UserData user) { }
public void Update(UserData user) { }
public void Delete(UserData user) { }
// Find
public IEnumerable FindAll() { return null; }
public UserData FindOne(Guid id) { return null; }
}
*UserStore內容比較多就不條列了,主要是依照儲存裝置撰寫相應的ORM。
UserManageModel :
UserManageModel 主要負責MVC內Model的職責。
在這邊除了上述職責之外,也將 UserStore生成的工作擺在這一層。
並且包裝UserStore,將UserStore跟整個ASP.NET的頁面做隔離。
public class UserManageModel
{
// Member
private UserStore CreateUserStore()
{
return new UserStore();
}
public void Insert(UserData user)
{
UserStore store = this.CreateUserStore();
store.Insert(user);
}
public void Update(UserData user)
{
UserStore store = this.CreateUserStore();
store.Update(user);
}
public void Delete(IEnumerable userCollection)
{
UserStore store = this.CreateUserStore();
foreach (UserData user in userCollection)
{
store.Delete(user);
}
}
public IEnumerable FindAllUser()
{
UserStore store = this.CreateUserStore();
IEnumerable userCollection = store.FindAll();
return userCollection;
}
public UserData FindOneUser(Guid id)
{
UserStore store = this.CreateUserStore();
UserData user = store.FindOne(id);
return user;
}
}
IUserManageController :
IUserManageController主要負責MVC內Controller的職責。
但是這邊只是定義介面(原因前篇文章有描述),實際完成Controller的內容是建立在UserManageConsole。
在這個介面內每個Function,主要是由頁面功能來定義出來的。
Index() : 進入顯示全部使用者資料功能。
Index(Guid userId) : 進入顯示單一使用者資料功能。
Insert() : 進入新增使用者功能。
Insert(UserData user) : 新增使用者功能。
Update(Guid id) : 進入修改使用者功能。
Update(UserData user) : 修改使用者功能。
Delete(IEnumerable<Guid> idCollection) : 進入刪除使用者功能。
Delete(IEnumerable<UserData> userCollection) : 刪除使用者功能。
public interface IUserManageController
{
// Index
void Index();
void Index(Guid id);
// Operate
void Insert();
void Insert(UserData user);
void Update(Guid id);
void Update(UserData user);
void Delete(IEnumerable idCollection);
void Delete(IEnumerable userCollection);
}
UserManageConsole :
為程式的主要進入點,是一個WebForm。
UserManageConsole實際完成IUserManageController的職責。
在這邊除了上述職責之外,也將所有View、還有Model生成的工作擺在這一層。
<%@ Register src="UserListView.ascx" tagname="UserListView" tagprefix="uc1" %>
<%@ Register src="UserInsertView.ascx" tagname="UserInsertView" tagprefix="uc2" %>
<%@ Register src="UserNotifyView.ascx" tagname="UserNotifyView" tagprefix="uc3" %>
<!--...-->
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<uc1:UserListView ID="_listView" runat="server" Visible="false" />
<uc2:UserInsertView ID="_insertView" runat="server" Visible="false" />
<uc3:UserNotifyView ID="_notifyView" runat="server" Visible="false" />
<!--...-->
</form>
</body>
</html>
public partial class UserManageConsole : System.Web.UI.UserControl, IUserManageController
{
// Properties
private UserManageModel _model = null;
// Construction
protected void Page_Init(object sender, EventArgs e)
{
// Model
_model = new UserManageModel();
// View
UserBaseView view;
foreach (Control control in this.Controls)
{
if (control is UserBaseView)
{
view = (UserBaseView)control;
view.Model = _model;
view.Controller = this;
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack == false)
{
this.Index();
}
}
// Member
private void ShowView(UserBaseView view)
{
foreach (Control control in this.Controls)
{
if (control is UserBaseView)
{
((UserBaseView)control).Hidden();
control.Visible = false;
}
}
view.Visible = true;
}
#region IUserManageController 成員
// Index
public void Index()
{
this.ShowView(_listView);
_listView.Show();
}
public void Index(Guid userId)
{
this.ShowView(_detailView);
_detailView.Show(userId);
}
public void Insert()
{
this.ShowView(_insertView);
_insertView.Show();
}
public void Insert(UserData user)
{
_model.Insert(user);
this.ShowView(_notifyView);
_notifyView.Show("新增資料完成");
}
public void Update(Guid userId)
{
this.ShowView(_updateView);
_updateView.Show(userId);
}
public void Update(UserData user)
{
_model.Update(user);
this.ShowView(_notifyView);
_notifyView.Show("修改資料完成");
}
public void Delete(IEnumerable<Guid> userIdCollection)
{
this.ShowView(_deleteView);
_deleteView.Show(userIdCollection);
}
public void Delete(IEnumerable<UserData> userCollection)
{
_model.Delete(userCollection);
this.ShowView(_notifyView);
_notifyView.Show("刪除資料完成");
}
#endregion
}
UserBaseView :
UserXxxxxxxView主要負責MVC內View的職責。由Controller來決定現在該顯示哪個View,並且接受使用者輸入及資料驗證。
UserBaseView 主要是將一些View內通用的功能提取出來,建立為View通用的父物件。
並且UserBaseView 本身為UserControl的延伸物件,所有的View也將都會是UserControl。
public class UserBaseView : System.Web.UI.UserControl
{
// Member
private UserManageModel _model = null;
public UserManageModel Model
{
set
{
_model = value;
}
get
{
return _model;
}
}
private IUserManageController _controller = null;
public IUserManageController Controller
{
set
{
_controller = value;
}
get
{
return _controller;
}
}
public void Hidden()
{
this.ClearChildState();
this.ViewState.Clear();
}
}
UserListView :
UserListView繼承UserBaseView。
UserListView在CRUD的職責主要是顯示所有使用者資料。
在使用者按下新增鍵的時候,呼叫Insert()進入新增使用者功能。
在使用者按下刪除鍵的時候,呼叫Delete(IEnumerable<Guid> idCollection)進入刪除使用者功能。
<!-- button -->
<asp:Button ID="Button1" runat="server" Text="新增" CommandName="Insert" OnCommand="Button_Command" />
<asp:Button ID="Button3" runat="server" Text="刪除" CommandName="Delete" OnCommand="Button_Command" />
<asp:Button ID="Button4" runat="server" Text="重新整理" CommandName="Refresh" OnCommand="Button_Command" />
<hr />
<!-- content -->
<h1>使用者列表</h1>
<hr />
<asp:ListView ID="_userListView" runat="server" DataKeyNames="Id">
<LayoutTemplate>
<table width="100%">
<asp:PlaceHolder runat="server" ID="itemPlaceholder"></asp:PlaceHolder>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td align="left" nowrap width="1%">
<asp:CheckBox ID="_itemCheckBox" runat="server" />
</td>
<td align="left" nowrap width="1%">
<asp:LinkButton ID="_nameLinkButton1" runat="server" CommandName="Display" CommandArgument='<%# Eval("Id") %>' OnCommand="Button_Command"><%# HttpUtility.HtmlEncode((string)Eval("Name")) %></asp:LinkButton>
</td>
<td align="left">
<asp:Label ID="_descriptionLabel" runat="server" Text='<%# HttpUtility.HtmlEncode((string)Eval("Description")) %>' ></asp:Label>
</td>
</tr>
</ItemTemplate>
</asp:ListView>
public partial class UserListView : UserBaseView
{
// Member
public void Show()
{
}
private IEnumerable<Guid> GetSelectUserId()
{
List<Guid> guidList = new List<Guid>();
foreach (ListViewDataItem dataItem in _userListView.Items)
{
CheckBox checkBox = dataItem.FindControl("_itemCheckBox") as CheckBox;
if (checkBox != null)
{
if (checkBox.Checked == true)
{
guidList.Add((Guid)(_userListView.DataKeys[dataItem.DisplayIndex].Value));
}
}
}
return guidList;
}
protected void Button_Command(object sender, CommandEventArgs e)
{
IEnumerable<Guid> guidCollection;
switch (e.CommandName)
{
case "Insert":
this.Controller.Insert();
break;
case "Delete":
guidCollection = this.GetSelectUserId();
if (guidCollection.Count() > 0)
{
this.Controller.Delete(guidCollection);
}
break;
case "Refresh":
this.Controller.Index();
break;
case "Display":
this.Controller.Index(new Guid(e.CommandArgument as string));
break;
}
}
}
UserInsertView :
UserInsertView繼承UserBaseView。
UserInsertView在CRUD的職責主要是接受使用者輸入新使用者資料。
在使用者按下確認鍵的時候,呼叫Insert(UserData user)新增使用者功能。
在使用者按下取消鍵的時候,呼叫Index()進入顯示全部使用者資料功能。
<!-- button -->
<asp:Button ID="Button1" runat="server" Text="確認" CommandName="Apply" OnCommand="Button_Command" />
<asp:Button ID="Button2" runat="server" Text="取消" CommandName="Cancel" OnCommand="Button_Command" />
<hr />
<!-- content -->
<h1>使用者新增</h1>
<hr />
Name : <asp:TextBox ID="_nameTextBox" runat="server" Text="" class="large_text"></asp:TextBox><br />
Description : <asp:TextBox ID="_descriptionTextBox" runat="server" Text="" class="large_text"></asp:TextBox>
public partial class UserInsertView : UserBaseView
{
// Member
public void Show()
{
_nameTextBox.Text = string.Empty;
_descriptionTextBox.Text = string.Empty;
}
protected void Button_Command(object sender, CommandEventArgs e)
{
switch (e.CommandName)
{
case "Apply":
UserData user = new UserData();
user.Id = Guid.NewGuid();
user.Name = _nameTextBox.Text;
user.Description = _descriptionTextBox.Text;
this.Controller.Insert(user);
break;
case "Cancel":
this.Controller.Index();
break;
}
}
}
UserNotifyView :
UserNotifyView繼承UserBaseView。
UserInsertView在CRUD的職責主要是顯示程式執行的通知訊息。
在使用者按下確認鍵的時候,呼叫Controller.Index()進入顯示全部使用者資料功能。
<!-- button -->
<asp:Button ID="Button1" runat="server" Text="確認" CommandName="Apply" OnCommand="Button_Command" />
<hr />
<!-- content -->
<h1>使用者通知</h1>
<asp:Label ID="_messageLabel" runat="server" Text="Label"></asp:Label>
public partial class UserNotifyView : UserBaseView
{
// Member
public void Show(string message)
{
_messageLabel.Text = message;
}
protected void Button_Command(object sender, CommandEventArgs e)
{
switch (e.CommandName)
{
case "Apply":
this.Controller.Index();
break;
}
}
}
OtherView :
剩下的View
UserDeleteView.ascx
UserDetailView.ascx
UserUpdateView.ascx
這幾個View跟上述幾個View大同小異就不贅述了。
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。