1.Introducing MVC
The Model-View-Controller pattern is certainly nothing new. It has been around for decades. There have been many variations of it and many articles, book chapters, and blog posts written about it. The original impetus for the pattern was to help intelligently structure an application to handle low-level user input, back when UI controls were quite primitive. As the developer-friendliness and richness of UI controls has improved over time, MVC has taken on broader meaning.
These days MVC generally refers to the separation of concerns wherein you have a Model to represent the logic and data of the problem domain, a View to display the Model on-screen, and a Controller to handle user interaction events and inform the Model when processing needs to occur. The Controller is interested in user interaction; such as keyboard, mouse, or stylus input; for an entire form or user control…not just one button or dropdown.

Now that I have regurgitated a generic explanation of MVC, let us see what it really means in practice. Previously we saw how loosely coupling application logic to the UI has many desirable advantages. What we did not review was how to implement that loose coupling. As you have probably guessed by now, the MVC pattern is a fantastic way to do it.
The essence of a loosely coupled system boils down to one (bizarre) term that I coined: referencelessness. A loosely coupled system does not have unnecessary object references directly connecting its major functional components. Where there are direct references between parts of the system, they should often be expressed as interfaces or abstract base classes, to allow for dependency injection and object mocking (more on that later). The only places in the system where it makes sense to have a direct reference between two components is where the Controller references the Model, and possibly between the Controller and View in certain situations. As we examine how the demo application uses MVC, the reasoning behind these statements will become apparent.
2.My Demo
In my demo application, I write one application to make it clear. Assuming we have a table, as it is shown in the following.
Student Information Table
(Field) |
(Type) |
StuId(Primary Key) |
Int |
StuNo |
Char(8) |
StuName |
Varchar(16) |
Sex |
Char(1) |
Brithday |
Datetime |
Address |
Varchar(64) |
Telphone |
Varchar(16) |
Remark |
Varchar(128) |
We want to operate this Student Information Table with one application based MVC pattern. It can add a record, modify a record, delete a record, and show all the record.
I write the Model Layer like this. It’s very easy, isn’t it? :-)
Code
1
namespace Model
2

{
3
public class StudentInfo
4
{
5
private string _stuNo;
6
private string _stuName;
7
private string _sex;
8
private DateTime _brithday;
9
private string _address;
10
private string _telphone;
11
private string _remark;
12
13
public string StuNo
14
{
15
get
16
{
17
return _stuNo;
18
}
19
set
20
{
21
_stuNo = value;
22
}
23
}
24
public string StuName
25
{
26
get
27
{
28
return _stuName;
29
}
30
set
31
{
32
_stuName = value;
33
}
34
}
35
public string Sex
36
{
37
get
38
{
39
return _sex;
40
}
41
set
42
{
43
_sex = value;
44
}
45
}
46
public DateTime Brithday
47
{
48
get
49
{
50
return _brithday;
51
}
52
set
53
{
54
_brithday = value;
55
}
56
}
57
public string Address
58
{
59
get
60
{
61
return _address;
62
}
63
set
64
{
65
_address = value;
66
}
67
}
68
public string Telphone
69
{
70
get
71
{
72
return _telphone;
73
}
74
set
75
{
76
_telphone = value;
77
}
78
}
79
public string Remark
80
{
81
get
82
{
83
return _remark;
84
}
85
set
86
{
87
_remark = value;
88
}
89
}
90
}
91
}
92
And then I write the Controller Layer like this.
Code
1
sing System;
2
using System.Collections.Generic;
3
using System.Text;
4
using System.Data;
5
using System.Data.SqlClient;
6
using Model;
7
namespace Manage
8

{
9
public class StudentManage
10
{
11
SqlConnection sqlCon;
12
public StudentManage(string strCon)
13
{
14
sqlCon = new SqlConnection(strCon);
15
}
16
Get all Students’ Informathion#region Get all Students’ Informathion
17
public DataTable GetAllStudent(out string strInfo)
18
{
19
strInfo = "";
20
DataTable objDataTable = new DataTable();
21
SqlCommand sqlCom = new SqlCommand();
22
sqlCom.CommandText = "select * from info";
23
sqlCom.Connection = sqlCon;
24
SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCom);
25
try
26
{
27
sqlDa.Fill(objDataTable);
28
if (objDataTable.Rows.Count == 0)
29
{
30
strInfo = "No Record";
31
}
32
}
33
catch
34
{
35
strInfo = "Can Not Find Database";
36
}
37
finally
38
{
39
sqlDa.Dispose();
40
sqlCom.Dispose();
41
}
42
return objDataTable;
43
}
44
#endregion
45
Get Student’s Information Via Student’s NO#region Get Student’s Information Via Student’s NO
46
public DataTable GetStudentByNo(string strStuNo,out string strInfo)
47
{
48
strInfo = "";
49
DataTable objDataTable = new DataTable();
50
SqlCommand sqlCom = new SqlCommand();
51
52
sqlCom.CommandText = "select * from info where StuNo like '%"+strStuNo+"%'";
53
sqlCom.Connection = sqlCon;
54
SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCom);
55
try
56
{
57
sqlDa.Fill(objDataTable);
58
if (objDataTable.Rows.Count == 0)
59
{
60
strInfo = "No Record";
61
}
62
}
63
catch
64
{
65
strInfo = "Failure";
66
}
67
finally
68
{
69
sqlDa.Dispose();
70
sqlCom.Dispose();
71
}
72
return objDataTable;
73
}
74
#endregion
75
Get Student’s Information Via Student’s Name#region Get Student’s Information Via Student’s Name
76
public DataTable GetStudentByName(string strStuName, out string strInfo)
77
{
78
strInfo = "";
79
DataTable objDataTable = new DataTable();
80
SqlCommand sqlCom = new SqlCommand();
81
sqlCom.CommandText = "select * from info where StuName like '%" + strStuName + "%'";
82
sqlCom.Connection = sqlCon;
83
SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCom);
84
try
85
{
86
sqlDa.Fill(objDataTable);
87
if (objDataTable.Rows.Count == 0)
88
{
89
strInfo = "No Record";
90
}
91
}
92
catch
93
{
94
strInfo = "Failure";
95
}
96
finally
97
{
98
sqlDa.Dispose();
99
sqlCom.Dispose();
100
}
101
return objDataTable;
102
}
103
104
#endregion
105
Add Students’s Information#region Add Students’s Information
106
public void AddStudent(StudentInfo objStudent, out string strInfo)
107
{
108
strInfo = "";
109
SqlCommand sqlCom = new SqlCommand();
110
sqlCom.CommandText = "insert into info(StuNo,StuName,Sex,Brithday,Address,Telphone,Remark) values('" + objStudent.StuNo + "','" + objStudent.StuName + "','" + objStudent.Sex + "','" + objStudent.Brithday + "','" + objStudent.Address + "','" + objStudent.Telphone + "','" + objStudent.Remark + "')";
111
sqlCom.Connection = sqlCon;
112
try
113
{
114
sqlCon.Open();
115
sqlCom.ExecuteNonQuery();
116
strInfo = "Successful";
117
}
118
catch
119
{
120
strInfo = "Failure";
121
}
122
finally
123
{
124
125
sqlCom.Dispose();
126
sqlCon.Close();
127
}
128
}
129
#endregion
130
Modify Students’s Information#region Modify Students’s Information
131
public void ModifyStudent(StudentInfo objStudent,int stuId, out string strInfo)
132
{
133
strInfo = "";
134
SqlCommand sqlCom = new SqlCommand();
135
sqlCom.CommandText = "update info set StuNo='" + objStudent.StuNo + "',StuName='" + objStudent.StuName + "',Sex='" + objStudent.Sex + "',Brithday='" + objStudent.Brithday + "',Address='" + objStudent.Address + "',Telphone='" + objStudent.Telphone + "',Remark='" + objStudent.Remark + "'where StuId="+stuId;
136
sqlCom.Connection = sqlCon;
137
try
138
{
139
sqlCon.Open();
140
sqlCom.ExecuteNonQuery();
141
strInfo = "Successful";
142
}
143
catch
144
{
145
strInfo = "Failure";
146
}
147
finally
148
{
149
150
sqlCom.Dispose();
151
sqlCon.Close();
152
}
153
}
154
#endregion
155
Delete Students’ Information#region Delete Students’ Information
156
public void DeleteStudent( int stuId, out string strInfo)
157
{
158
strInfo = "";
159
SqlCommand sqlCom = new SqlCommand();
160
sqlCom.CommandText = "delete from info where StuId=" + stuId;
161
sqlCom.Connection = sqlCon;
162
try
163
{
164
sqlCon.Open();
165
sqlCom.ExecuteNonQuery();
166
strInfo = "Successful";
167
}
168
catch
169
{
170
strInfo = "Failure";
171
}
172
finally
173
{
174
175
sqlCom.Dispose();
176
sqlCon.Close();
177
}
178
}
179
#endregion
180
181
}
182
}
183
Then I write some code to test this Controller Layer, of course, I use the Nunit Test to do this.
Code
1
// 以下代码由 Microsoft Visual Studio 2005 生成。
2
// 测试所有者应该检查每个测试的有效性。
3
using Microsoft.VisualStudio.TestTools.UnitTesting;
4
using System;
5
using System.Text;
6
using System.Collections.Generic;
7
using Manage;
8
using Model;
9
using System.Data;
10
namespace Test
11

{
12
/**////
13
///这是 Manage.StudentManage 的测试类,旨在
14
///包含所有 Manage.StudentManage 单元测试
15
///
16
[TestClass()]
17
public class StudentManageTest
18
{
19
20
21
private TestContext testContextInstance;
22
23
/**////
24
///获取或设置测试上下文,上下文提供
25
///有关当前测试运行及其功能的信息。
26
///
27
public TestContext TestContext
28
{
29
get
30
{
31
return testContextInstance;
32
}
33
set
34
{
35
testContextInstance = value;
36
}
37
}
38
附加测试属性#region 附加测试属性
39
//
40
//编写测试时,可使用以下附加属性:
41
//
42
//使用 ClassInitialize 在运行类中的第一个测试前先运行代码
43
//
44
//[ClassInitialize()]
45
//public static void MyClassInitialize(TestContext testContext)
46
//{
47
//}
48
//
49
//使用 ClassCleanup 在运行完类中的所有测试后再运行代码
50
//
51
//[ClassCleanup()]
52
//public static void MyClassCleanup()
53
//{
54
//}
55
//
56
//使用 TestInitialize 在运行每个测试前先运行代码
57
//
58
//[TestInitialize()]
59
//public void MyTestInitialize()
60
//{
61
//}
62
//
63
//使用 TestCleanup 在运行完每个测试后运行代码
64
//
65
//[TestCleanup()]
66
//public void MyTestCleanup()
67
//{
68
//}
69
//
70
#endregion
71
72
73
/**////
74
///AddStudent (StudentInfo, out string) 的测试
75
///
76
[TestMethod()]
77
public void AddStudentTest()
78
{
79
string strCon = "server=.;user id =sa;password=sa;database= StuInfo;"; // TODO: 初始化为适当的值
80
81
StudentManage target = new StudentManage(strCon);
82
83
StudentInfo objStudent = new StudentInfo (); // TODO: 初始化为适当的值
84
objStudent.StuNo = "20083111";
85
objStudent.StuName = "李四";
86
objStudent.Sex = "M";
87
objStudent.Brithday = DateTime.Parse("1984-07-07");
88
objStudent.Address = "湖北武汉";
89
objStudent.Telphone = "02787342182";
90
objStudent.Remark = "好学生!";
91
string strInfo="";
92
string strInfo_expected = "Successful"; // TODO: 初始化为适当的值
93
94
target.AddStudent(objStudent, out strInfo);
95
96
Assert.AreEqual(strInfo_expected, strInfo);
97
98
}
99
100
101
102
/**////
103
///GetAllStudent (out string) 的测试
104
///
105
[TestMethod()]
106
public void GetAllStudentTest()
107
{
108
string strCon = "server=.;user id =sa;password=sa;database= StuInfo;"; // TODO: 初始化为适当的值
109
110
StudentManage target = new StudentManage(strCon);
111
112
string strInfo="";
113
114
DataTable actual;
115
116
actual = target.GetAllStudent(out strInfo);
117
Assert.AreNotEqual(actual.Rows, 0);
118
119
120
}
121
122
/**////
123
///GetStudentByName (string, out string) 的测试
124
///
125
[TestMethod()]
126
public void GetStudentByNameTest()
127
{
128
string strCon = "server=.;user id =sa;password=sa;database= StuInfo;"; // TODO: 初始化为适当的值
129
130
StudentManage target = new StudentManage(strCon);
131
132
string strStuName = "李四"; // TODO: 初始化为适当的值
133
134
string strInfo="";
135
string strInfo_expected = "Failure"; // TODO: 初始化为适当的值
136
137
DataTable actual;
138
139
actual = target.GetStudentByName(strStuName, out strInfo);
140
141
Assert.AreNotEqual(strInfo_expected, strInfo);
142
Assert.AreNotEqual(actual.Rows.Count, 0);
143
}
144
145
/**////
146
///GetStudentByNo (string, out string) 的测试
147
///
148
[TestMethod()]
149
public void GetStudentByNoTest()
150
{
151
string strCon = "server=.;user id =sa;password=sa;database= StuInfo;"; // TODO: 初始化为适当的值
152
153
StudentManage target = new StudentManage(strCon);
154
155
string strStuNo = "20083111"; // TODO: 初始化为适当的值
156
157
string strInfo="";
158
string strInfo_expected = "Failure"; // TODO: 初始化为适当的值
159
160
DataTable actual;
161
162
actual = target.GetStudentByNo(strStuNo, out strInfo);
163
164
Assert.AreNotEqual(strInfo, strInfo_expected);
165
Assert.AreNotEqual(actual.Rows.Count, 0);
166
}
167
168
/**////
169
///ModifyStudent (StudentInfo, int, out string) 的测试
170
///
171
[TestMethod()]
172
public void ModifyStudentTest()
173
{
174
string strCon = "server=.;user id =sa;password=sa;database= StuInfo;"; // TODO: 初始化为适当的值
175
176
StudentManage target = new StudentManage(strCon);
177
178
StudentInfo objStudent = new StudentInfo (); // TODO: 初始化为适当的值
179
objStudent.StuNo = "20083111";
180
objStudent.StuName = "李世民";
181
objStudent.Sex = "M";
182
objStudent.Brithday = DateTime.Parse("1984-07-07");
183
objStudent.Address = "湖北武汉";
184
objStudent.Telphone = "027873582";
185
objStudent.Remark = "坏学生!";
186
187
int stuId = 1; // TODO: 初始化为适当的值
188
189
string strInfo="";
190
string strInfo_expected = "Failure"; // TODO: 初始化为适当的值
191
192
target.ModifyStudent(objStudent, stuId, out strInfo);
193
194
Assert.AreEqual(strInfo_expected, strInfo);
195
196
}
197
198
/**////
199
///StudentManage (string) 的测试
200
///
201
[TestMethod()]
202
public void ConstructorTest()
203
{
204
string strCon = "server=.;user id =sa;password=sa;database= StuInfo;"; // TODO: 初始化为适当的值
205
206
StudentManage target = new StudentManage(strCon);
207
208
// TODO: 实现用来验证目标的代码
209
Assert.Inconclusive("Successful");
210
}
211
/**////
212
///DeleteStudent (int, out string) 的测试
213
///
214
[TestMethod()]
215
public void DeleteStudentTest()
216
{
217
string strCon = "server=.;user id =sa;password=sa;database= StuInfo;"; // TODO: 初始化为适当的值
218
219
StudentManage target = new StudentManage(strCon);
220
221
int stuId = 1; // TODO: 初始化为适当的值
222
223
string strInfo="";
224
string strInfo_expected = "Failure"; // TODO: 初始化为适当的值
225
226
target.DeleteStudent(stuId, out strInfo);
227
228
Assert.AreNotEqual(strInfo_expected, strInfo);
229
}
230
231
}
232
233
234
}
235
At last, I finish the View Layer. It’s UI like this.
And the form of adding and modifying students’ information is as this.
