在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 CustomerPage : 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框架的新特征。