这个系列的第一篇建造了一个简单的电子商务产品列表/浏览网站。它讨论了MVC后面的高层次的概念,示范了如何从头创建一个新的asp.net mvc项目,实现和测试这个电子商务产品列表功能。系列的第二篇对asp.net mvc框架的URL路径选择(routing)架构做了深入探讨,讨论了它的工作原理以及你如何使用它来处理更高级的URL路径选择场景。
此篇,将讨论控制器是如何与视图做交互的,具体来说,我将讨论你可以把数据从控制器传到视图以显示返回到客户端的回复的各种方式。
第一部分的扼要简述
在这个系列的第一部分,我们创建了一个电子商务网站,实现了基本的产品列表/浏览支持。我们是用asp.net mvc框架实现这个网站的,这个方法会很自然地将代码结构化为独特的控制器,模型和视图组件。
当浏览器向我们的网站发送一个HTTP请求时,asp.net mvc框架将使用它的URL路径选择引擎,把进来的请求映射到一个控制器上的action方法来处理它。在基于MVC的应用中的控制器负责处理进来的请求,处理用户输入和交互,执行基于这些输入和交互的应用逻辑(获取或更新存储在数据库中的模型数据等等)。
到生成返回到客户端的HTML回复的时候,控制器一般是与“视图”组件合作,这些视图组件是以独立于控制器的单独的类或模板的形式实现的,其目的是完全注重于封装显示逻辑。
视图不应该含有任何应用逻辑或数据库访问代码,所有的应用/数据逻辑应该由控制器类来处理。这么划分的动机是帮助强制你的应用/数据逻辑与界面生成代码间的清晰分离。同时这也方便你独立于你的界面显示逻辑来单元测试你的应用/数据逻辑。
视图应该只使用从控制器传过来的特定于视图的数据来生成输出。在asp.net mvc框架中,我们称这个特定于视图的数据为“ViewData”。这个博客的其他部分将讨论你可以用来将ViewData从控制器传递给视图来生成显示的一些不同方法。
一个简单的产品列表场景
为帮助说明我们可以用来把ViewData从控制器传递给视图的一些技术,让我们来建造一个简单的产品列表网页:
我们将用一个CategoryID整数来过滤我们想要显示在页面上的产品。注意上面我们是如何把CategoryID嵌在URL中的(例如,Products/Category/2 或 /Products/Category/4 )。
然后,我们的产品列表网页显示了2个不同的动态内容元素。第一个元素是我们要显示的分类的文本名称(例如,Condiments-调味品),第二个元素是一个HTML < ul>< li/>< /ul> 产品名字列表。我在上面的屏幕截图中对这2个元素用红笔画了圈。
在下面,我们将看一下我们可以使用的2个不同的方法来实现ProductsController类,这个类处理进来的请求,获取处理请求所需的数据,然后将这个数据传给一个List视图来显示。我们要研究的第一个方法是用后期绑定的字典对象传递这个数据,第二个方法则使用强类型类的方式来传递这个数据。
方法 1:使用 Controller.ViewData 字典来传递ViewData
Controller基类有个ViewData字典属性,可以用来填充你要传给视图的数据。你使用键/值模式将对象加入 ViewData 字典。
下面是个ProductsController类,其中的Category action方法实现了我们上面的产品列表场景。注意,它是如何使用分类的ID参数来查询该分类的文本名称,以及获取该分类中的产品列表的。它使用“CategoryName”和“Products”两个键将这两个数据存储在Controller.ViewData 集合中:
然后,我们上面的Category action方法调用 RenderView("List") 来表示它要用哪个模板来做显示。当你象这样调用RenderView时,它会将ViewData字典传给视图,以显示对应的回复。
实现我们的视图
我们将使用居于我们项目的\Views\Products目录下的List.aspx文件来实现我们的List视图。这个 List.aspx 将继承 \Views\Shared 文件夹中的Site.Master母版页中的布局(在你创建一个新的视图网页时,你可以在 VS 2008 中,右击,选择添加新项->MVC视图内容网页来接连一个母版页):
当我们使用MVC视图内容网页模板来创建List.aspx网页时,它不是从通常的 System.Web.UI.Page 类继承而来,而是从System.Web.Mvc.ViewPage 基类继承而来(是现有的Page类的一个子类):
ViewPage基类提供一个ViewData字典属性,我们可以在视图网页里访问由控制器添加的数据对象。然后我们可以取出这些数据对象,使用它们来显示HTML输出,可以用服务器控件的方式,或者用 < %= %> 显示代码的方式。
使用服务器控件来实现我们的视图
下面是一个如何使用现有的< asp:literal> 和 < asp:repeater>服务器控件来实现我们的HTML界面的例子:
我们可以用下面的后台代码类将 ViewData 绑定到这些控件之上(注意我们是如何使用ViewPage的ViewData字典来实现的 ):
注: 因为页面上没有 < form runat="server">,是不会输出 view-state 的。上面的控件也不会自动生成任何ID值,这意味着你对输出的HTML有完全的控制。
使用 < %= %> 代码来实现我们的视图
如果你更喜欢使用行内代码来生成输出的话,你可使用下面的 List.aspx 来实现跟上面完全一样的结果:
注: 因为ViewData的类型是含有“objects”的字典,为了对它使用foreach语句,我们需要将ViewData["Products"]的类型转换成 List< Product> 或者 IEnumerable< Product>。我在页面上引用了System.Collections.Generic 和 MyStore.Models 命名空间 以避免输入 List< T> 和 Product 类型的完整名称。
注: 上面使用了“var”关键词,这是VS 2008中新的 C# 和 VB “类型推断”特性的一个例子(在这里阅读我以前的相关贴子)。因为我们将ViewData["Products"] 转换成了 List< Product>,我们在 List.aspx 文件中的 prduct 变量上得到了完整的intellisense:
这样就使用ASP.NET MVC框架实现了一个电子商务网站。
【编辑推荐】