Scott的ASP.net MVC框架系列文章之三: 视图数据的传递

[原文地址] [阅读该系列的其他文章]

前几周我发表了一系列文章介绍我们正在研究的 ASP.NET MVC 框架。 ASP.NET MVC 框架为你提供了一种新的开发 Web 应用程序的途径,这种途径可以让应用程序变得更加层次清晰,而且更加有利于对代码进行单元测试和支持 TDD (测试驱动开发)开发。
 
这一些列的 第一篇文章 创建了一个简单的电子商务产品列表 / 浏览站点。他涉及到了 MVC 背后的高层次概念并演示了一个 ASP.NET MVC 项目从设计到实现的过程和对产品列表功能的测试。该系列的 第二篇文章 深入介绍了 ASP.NET MVC 框架的 URL 映射机制并针对其工作原理和更复杂 URL 映射的处理进行了深入讨论。
 
本文将要讨论控制类 ( 英文名称 :Controller ,以下统一称 Controller) 如何与视图类 ( 英文名称 Views ,以下统称 Views) 进行交互,并专门介绍从 Controller Views 传递数据以便给客户端呈现内容的方式。
 
Part 1 回顾
 
该系列的 第一篇文章 我们采用 ASP.NET MVC 框架创建了一个电子商务站点,实现了基本的产品列表 / 浏览功能,并把代码自然的划分到不同的 Controller, 模型 ( 英文名称: Model ,以下统一称 Model) View 部分。
 
当浏览器向服务器发送一个 HTTP 请求时, ASP.NET MVC 框架将使用 URL映射引擎 将该请求映射到 controller 的操作方法来处理。 MVC 应用程序中的 Controller 处理客户端请求,捕获用户输入和进行交互,并执行相应的应用逻辑 ( 获取或更新数据库中的模型数据等 )
 
当需要向客户端返回 HTML 回应时, controller 针对 views 进行操作, Views 是独立于 controller 的类或模板,并主要完成显示逻辑的封装。
 
https://i-blog.csdnimg.cn/blog_migrate/2ae4f871f4e03df16e02ec7a9cfb9332.jpeg
 
Views 不应该包含任何应用逻辑或数据访问代码,所有的应用 / 数据逻辑都应该有 controller 来完成。这样做的好处是让应用 / 数据逻辑与 UI 呈现代码有更加清晰的分离,并使得针对应用 / 数据逻辑的单元测试与 UI 呈现逻辑相分离。
 
View 应当只根据由 Controller 针对该 View 传来的数据生成输出。在 ASP.NET MVC 框架中,我们把该数据成为视图数据 (ViewData) 。下面将要介绍将视图数据转换为输出的不同方式。
 
简单的产品列表场景
 
让我们常见一个产品列表页来说明我们从 Controller View 传递视图数据的技术:
 
https://i-blog.csdnimg.cn/blog_migrate/f967e1b5675bb3de96ad39bae0482f1f.png
 
我们将要使用 CategoryID 整数来过滤出我们希望产生在页面上的产品。注意上面我们是如何把 CategoryID 作为 URL 的一部分的(例如 : /Products/Category/2 /Products/Category/4
 
我们的产品列表页要产生两个独立的动态内容元素,第一部分是我们要显示的目录名称 ( 例如: Condiments) ,另一部分是一组 HTMl <ul><li></li></ul> 标记显示产品名称列表。这两部分我都已经在上面的截图中作出红色标记。
 
下面我们将要分别介绍两种方式,来实现 ProductsController 类处理请求,获取数据并显示数据的过程。第一种方式我们要使用迟绑定 (late-bound) 对象,另一种方式我们要使用强类型类 (strong-typed)
 
方式 1 :使用 Controller.ViewData 传递视图数据
 
Controller 基类包含一个名为 ”ViewData” 的属性可以用来存放传递给视图的数据,你可以使用 name/value 的形式向 ViewData 中添加对象。
 
下面的 ProductsController 类中包含一个 Category 方法可以实现上面所说的产品列表功能。注意该类是如何使用目录的 ID 参数来寻找该目录的名称的,以及如何获取该目录中的所有产品。这两部分内容都被存放在 Controller.ViewData 集合中,并分别使用 ”CategoryName” “Products” 名称作为主键:
 
https://i-blog.csdnimg.cn/blog_migrate/a1b454e9690b5a971ccb5e8c4ffc8779.png 
 
上面的 Category 方法调用 RenderView(“List”) 并指明了将要使用哪个视图模板来产生输出,当调用 RenderView 方法时, Controller 将把 ViewData 传递到 View 中以便进行显示。
 
实现 View
 
我们将使用 /Views/Products 目录下的 List.aspx 页面文件来实现 List 视图,该文件将继承 /Views/Shared 目录下 Site.Master 母版页的布局(在 VS2008 中创建新的视图时右单击项目选择 添加新项目 ”->”MVC 视图内容页 选择母版页):
 
https://i-blog.csdnimg.cn/blog_migrate/ba45b6097f0f8deb969f36e223c7aed9.png
 
当我们使用 MVC 视图内容也模板创建 List.aspx 页时,并不是从 System.Web.UI.Page 类继承而来,而是继承自 System.Web.Mvc.ViewPage 基类(该类是 Page 类的子类):
 
https://i-blog.csdnimg.cn/blog_migrate/c9eb6573d13275465c75aa2db00ba3d6.png
 
ViewPage 基类同样为我们提供了 ViewData 属性,我们可以在 View 中使用该属性访问由 Controller 添加的对象,我们可以使用这些数据并通过服务器控件或 <%=%> 标记产生 HTML 输出。
 
使用服务器控件实现 View
 
在下面的例子里我们使用已有的 <asp:literal> <asp:repeater> 服务器控件实现 HTML 输出:
 
https://i-blog.csdnimg.cn/blog_migrate/6217e9f7672e05b986c4f27ec01f7115.png
 
我们可以采用如下方式通过后台代码类将视图数据绑定到这些控件(注意我们是如何使用视图页的 ViewData 属性来实现的):
 
https://i-blog.csdnimg.cn/blog_migrate/df0e28e76f0a7daf07693a1e5f546ef9.png
 
注意:因为页面上没有 <form runat=”server”> 标记,因此不会生成视图状态 (ViewState). 上面的控件同样不会自动产生任何 ID 值,这意味着你将对 HTML 输出具备完全的控制。
 
通过 <%=%> 实现视图
 
如果你希望使用迁入代码的方式产生输出,你可以用下面的 List.aspx 页面实现与上面相同的效果:
 
https://i-blog.csdnimg.cn/blog_migrate/ea3aebbfe3bceb7b7d39fb8e64a6d880.png
 
注意:因为 ViewData 属性的类型为包含对象 (object) 的字典,我们需要将 ViewData[“Products”] 转换成 List<Product> 类型或 Ienumerable<Product> 类型来使用 foreach 语句。在页面上引用 System.Collections.Generic MyStore.Models 命名空间避免在 List<T> Product 类型中使用完整的类型名称。
 
注意:上面 ”var” 关键字的使用是在 VS2008 中使用新的 C# VB”Type inference (字面意思为类型推理) 特性的例子 ( 点击 这里 阅读相关文章 ) 。因为我们已经将 ViewData[“Products”] 转换为 List<Product> 类型,在 List.aspx 文件中我们将获得 product 变量的智能感知支持。
https://i-blog.csdnimg.cn/blog_migrate/2f988de55612dbcfad0173f2f963010a.png
 
方式 2 :使用强类型 (strong-typed) 类传递视图数据
 
除了对迟绑定数据源方式之外, ASP.NET MVC 框架同时允许从 Controller View 中传递强类型的视图数据对象。使用强类型的方式有如下优点:
  1. 避免使用字符串来搜索对象,同时对ControllerView代码都可以得到编译时错误检查
  2. 避免在使用强类型语言(例如C#)时对视图数据进行强制类型转换
  3. 在视图页的标记和后台代码中可以有代码只能感知支持
  4. 你可以使用代码反射工具在应用程序和单元测试代码范围内对代码进行自动修改
下面的 ”ProductsListViewData” 强类型类封装了 List.aspx 视图中用户产品列表的数据,它具有 CategoryName Products 属性(通过 C# 中新的 自动属性automatic property 支持实现):
 
https://i-blog.csdnimg.cn/blog_migrate/bd4c3599d2843bde7d48a33447a7ac43.png
 
修改 ProductsController 使用该对象将强类型的视图数据传递到视图中:
 
https://i-blog.csdnimg.cn/blog_migrate/089f883b9935f44ab60cb8390f9a093e.png
 
注意上面我们是向 RenderView() 方法中传入一个额外的参数将强类型的 ProductsListViewData 对象传递给视图的。
 
使用视图的 ViewData 属性访问强类型的 ViewData 对象
 
我们在前面实现的 List.aspx 视图不需要修改仍可以正常工作。这是因为当强类型的 ViewData 对象传入继承自 ViewPage 类的 View 时, ViewData 属性将应用反射机制自动查找该对象的各种属性值,因此我们视图中的代码如下所示:
 
https://i-blog.csdnimg.cn/blog_migrate/243369904c37872a4ae46ed087a2aa82.png
 
RenderView() 方法被调用是,上面的代码将会利用反射从我们传入的强类型 ProductsListViewData 对象中获取 CategoryName 属性。
 
对象类型 ViewData 使用 ViewPage<T> 基类
 
为了提供对 ViewPage 基类的支持, ASP.NET MVC 框架同时包含了一个泛型基类 ViewPage<T> ,如果你的视图继承自 ViewPage<T> ,其中 T 代表 Controller 传入 View ViewData 的类型,那么 ViewData 将被强类型话为指定的类型。
 
例如,我们可以修改 List.aspx.cs 文件使其继承自 ViewPage<ProductsListViewData> 而不是 ViewPage 基类:
https://i-blog.csdnimg.cn/blog_migrate/5e9816fca9cca83a2c5e707b573a8dfc.png
 
此时该页的 ViewData 属性将自动定义为 ProductsListViewData 。这样我们可以使用强类型属性而不是字符串索引的方式获取数据:
 
https://i-blog.csdnimg.cn/blog_migrate/ea4d1e820232e496310675006bfc3470.png
 
然后我们可以使用服务器控件或 <%%> 的方式生成基于 ViewData HTML 输出。
 
通过服务器控件实现 ViewPage<T>
 
在下面的例子中我们将使用 <asp:literal> <asp:repeater> 服务器控件实现 HTML UI ,与前面继承自 ViewPage 基类的 List.aspx 页面相同:
 
https://i-blog.csdnimg.cn/blog_migrate/6217e9f7672e05b986c4f27ec01f7115.png
 
后台代码如下所示。注意因为该类继承自 ViewPage<ProductsListViewData>, 所以我们可以直接访问属性而不需要任何转换(同时在任何时候我们希望修改属性名称时都可以得到反射工具的支持):
 
https://i-blog.csdnimg.cn/blog_migrate/e006e820989e5a9818258ca7e7b146aa.png
 
使用 <%%> 实现 ViewPage<T>
 
如果你希望使用嵌入代码的方式来生成输出,你可以使用下面的代码实现与上面相同的效果:
https://i-blog.csdnimg.cn/blog_migrate/7fe20ac53cc025f2061e6c25f496ce88.png
 
采用 ViewPage<T> 的方式我们避免使用字符串来检索视图数据,更重要的是属性成为强类型之后我们就不需要再进行属性的类型转换。这意味着我们可以直接使用 foreach (var product in ViewData.Products) 语句而不需要转换得到 Products 。在循环语句 product 变量将会有完全的智能感知支持:
 
https://i-blog.csdnimg.cn/blog_migrate/8b06ee04b1d8c273f2b4b9936f09039d.png
 
总结
 
希望上面的文章已经对 Controller View 传递用于呈现的数据的过程有了更加深入的介绍,你可以使用迟绑定的方式或强类型的方式来达到这一目的。
 
当你第一次创建一个 MVC 应用程序时,你或许会对将应用控制逻辑与表现代码相互分开的概念感到陌生,你需要一些时间来适应这种接受请求 - 执行应用逻辑 - 包装用于显示的视图数据 - 呈现的处理过程。重要: MVC 方式为可选方式,如果你对这种开发模式并不习惯你可以不使用它。
 
这种方式的优点在于将运行和测试业务逻辑的过程与 UI 呈现分离,这是的开发单元测试更加简便,同时支持 TDD 开发模式。后面的文章我将深入介绍这一点,并讨论对代码进行测试的实践。
 
希望对你有所帮助,
Scott
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值