在本系列文章中,我们将针对微软最新推出的ASP.NET MVC 2.0中提供的新特征相关的基础性编程问题进行全面的探讨。在本文(第一篇)中,我们将通过对比ASP.NET MVC框架与ASP.NET Web表单框架的方式来学习ASP.NET MVC 2.0提供的新功能。
在2010年4月,微软正式发布了Visual Studio的下一个版本2010。ASP.NET MVC 2.0也作为其中的一个新框架成员一同发行。ASP.NET MVC如今已是一个成熟的产品,采用了全新的设计,大大提高了开发效率。
从因特网上你可以轻易找到专家们给出的这样的结论:ASP.NET Web表单仍然是基于微软.NET平台开发Web应用的首选-其成熟性、稳定性和高效性是经过实践检验的,而且现成和将来会继续被微软所支持。另一方面,ASP.NET MVC虽然是一个新框架,但是其针对大型应用提供了更清晰的框架支持。因此,你可以把ASP.NET MVC框架可以作为开发Web应用的另一种替代方案。
一、回顾ASP.NET Web表单框架的主要特征
ASP.NET 1.0的发布成为ASP开发人员的极大期待。从此以后,开发人员基本上实现了HTML标记与服务器端代码的分离管理。HTML标记部分可以置于一个ASPX页面中,而所有的后台逻辑驻留在一个后缀为ASPX.CS或ASPX.VB的单独的代码隐藏文件中。而且,在代码隐藏文件中可以充分地控制服务器端控件,例如标签,文本框和其他控件,等等。
代码隐藏文件中提供了一系列的事件供触发之用,从而让您的代码以一种有序的方式执行。开发人员可以响应各种UI事件(如按钮点击,回寄到服务器端的下拉列表框选择,超链接重定向,等等)。开发人员可以访问各种设施来实现缓存数据,并实现跨页面回寄保留这些数据,因为每一个到服务器端的请求都是唯一且无状态的。
最后,ASP.NET Web表单框架中提供了很多现成的内置的服务。ViewState结构能够为您跨越表单回寄保留数据,所以你不需要把数据存储在例如文本框和下拉列表框等各种控件内。表单数据在提交前能够被充分地验证,从而确保用户没有提交任何HTML内容(避免潜在的XSS脚本或注入式攻击)。
二、代码隐藏文件与控制器
ASP.NET MVC版本的代码隐藏文件就是控制器类。但是,控制器类的工作方式有所不同。在ASP.NET MVC中,没有使用任何服务器控件、页面生命周期以及其他那些ASP.NET Web表单程序员所熟悉的组件。我们不妨来看一下清单1中给出的ASP.NET Web表单框架下的隐藏代码。
清单1—ASP.NET Web表单页面示例
public class Customer
Page : Page
{
//protected withevents TextBox FirstName;
//protected withevents TextBox LastName;
//protected withevents GridView OrdersGrid;
protected override void OnLoad(EventArgs e)
{
UserInformation info = (UserInformation)Session["User"];
this.FirstName.Text = info.FirstName;
this.LastName.Text = info.LastName;
var dal = new OrdersDAL();
this.OrdersGrid.DataSource = dal.GetOrders(info.ID);
this.OrdersGrid.DataBind();
}
protected void OrdersGrid_RowDataBound(
object sender, GridViewRowEventArgs e)
{
if (e.Row.ItemType == DataRowControlState.DataItem)
{
e.Row.Cells[3].Text = ((Order)e.Row.DataItem).HasShipped
? "Yes" : "No";
}
}
}
在这个示例页面中,我们从一个存储了UserInformation对象的会话变量中提取姓名信息。接下来,调用数据访问层提供的一个方法GetOrders来获取针对特定的用户ID的订单信息,并把结果绑定到网格控件中。
因此,在上面这个简单的例子中,代码隐藏文件的作用是负责把数据赋给页面中的控件,如把数据加载到一个网格控件中,并实现对数据访问层的访问。
下面,我们来观察MVC框架中通过控制器提供的实现思路。
清单2—ASP.NET MVC控制器示例
public class CustomerModel
{
public UserInformation User { get; set; }
public IEnumerable<Order> Orders { get; set; }
}
public class CustomerController : Controller
{
public ActionResult Index()
{
var dal = new OrdersDAL();
var user = (UserInformation)Session["User"];
return View(new CustomerModel
{
User = user,
Orders = dal.GetOrders(user.ID)
});
}
}
怎么样?在MVC控制器和前面的ASP.NET Web表单之间的确存在一些相当大的变化。首先,CustomerModel类包含了将要在视图中显示的实际数据。在Web表单中,由代码隐藏文件把数据分配给视图;而在MVC中,由控制器为视图创建模型,进行数据访问操作,以及从会话中访问数据。那么,我们是如何与在Web表单环境下熟悉的文本框、网格及其他控件打交道呢?下面清单3给出了一个在MVC框架下显示用户界面的视图的示例。
清单3—MVC视图举例
<@Page … >
<html>
<body>
<% Html.BeginForm(); %>
<div>
<span>First</span>
<%= Html.TextBox("FirstName", Model.User.FirstName)%>
</div>
<div>
<span>Last</span>
<%= Html.TextBox("LastName", Model.User.LastName)%>
</div>
<div>
<table>
<thead>
<tr>
<th>Date</th>
<th>Amount</th>
<th># Products</th>
<th>Has Shipped?</th>
</tr>
</thead>
<tbody>
<% foreach (var order in Model.Orders){%>
<tr>
<td><%= order.Date %></td>
<td><%= order.Amount.ToString("C")%></td>
<td><%= order.ProductCount %></td>
<td><%= order.HasShipped ? "Yes" : "No" %></td>
</tr>
<%}%>
</tbody>
</table>
</div>
<% Html.EndForm(); %>
</body>
</html>
与Web表单相比,这里显然发生了巨大改变。MVC视图更多地控制着数据在用户界面上的显示。尽管其工作方式类似于Web表单,但还要由它指定要加载的数据,而且由视图来管理用户界面的显示方式,而不必涉及到Web表单框架下代码隐藏文件的干预。
归纳来看,上面清单1中在GridView的最后一个单元格中显示Yes/No数据时,是通过代码隐藏文件把一个布尔值转换成一个Yes/No值。但是,在MVC中框架下,上述这种方式的转换都是以内联方式发生的,而不需要添加事件处理器。尽管这仅仅是小例一个,但已经初步展示了Web表单框架与MVC框架渲染数据方式的不同。
三、资源问题
在ASP.NET窗体下,开发人员可以使用广泛的外部资源来存储数据。用户可以使用如Session,Cache和Application及其他集合来存储数据,甚至能够跨越页面回寄。在ASP.NET MVC框架中仍然可以使用这些结构来保留数据,但是又得到了更好的改善。
伴随ASP.NET动态数据的出现,系统引入了一个新的System.Web.Abstractions程序集,其中,针对Session、Cache、Request、Response等重要组件均提供了基类支持。这些基类的形式类似于HttpContextBase,HttpRequestBase,等等。这真是一个好消息,因为ASP.NET针对这类对象都提供了相应的具体的实现类(分别命名为HttpContextWrapper,HttpRequestWrapper,等等)以便提供实际服务。出于测试目的,您可以创建自己的测试类,这个测试类可以是继承自HttpContextBase类,也可以是其他上述基类。
在ASP.NET Web表单框架下,访问页面的Request属性总会返回一个针对HttpRequest的引用。这个HttpRequest类是不可扩展的,而且与Web表单框架高度耦合到一起。相比之下,在MVC框架中请求对象是HttpRequestBase基类的引用。ASP.NET MVC框架使用HttpRequestWrapper包装类来实现这个基类,以便实际使用底层的HttpRequest对象。但是,出于测试目的,您可以创建一个继承自HttpRequestBase的虚构类,由它来实现测试一些方法,以便包含你要测试的代码并使用NUnit、MBUnit或其他测试框架加以测试。
四、生命周期
使用ASP.NET Web表单时,页面将触发Init,Load,PreRender,和Unload等事件。但是,在ASP.NET MVC中,并没有利用这个生命周期,而是对行为方法发出请求。这对于习惯了Web表单框架的开发人员可能需要一个不断熟悉的过程。
五、小结
可以说,ASP.NET MVC框架是传统型ASP.NET Web表单框架的巨大转变。本文主要从代码隐藏文件和用户界面角度对这两个框架进行了比较。在后面其他文章中,我们还要通过对比的方式来学习这两个框架的其他重要区别,当然重点还在于学习MVC 2.0框架的新特征。
【相关文章】:巨大转变!ASP.NET MVC2用户界面新实践
巨大转变!ASP.NET MVC2调用AJAX新特征
巨大转变!ASP.NET MVC2行为方法新改进