【原文地址】.NET Web Product Roadmap (ASP.NET, Silverlight, IIS7)
【原文发表日期】 Thursday, November 29, 2007 9:22 AM
上个星期,我们发布了Visual Studio 2008 和.NET 3.5。这个发布对.NET来说,非常巨大,它为web,客户端,办公,和移动开发提供了成堆的新功能和众多的改进。
在下几个月里,我们将发布建造在Visual Studio 2008 和.NET 3.5基础之上的一系列另外的产品,进一步完善.NET开发。下面是一些我的团队正在开发的,预定要在几个月内发布的.NET web开发方面的产品的路线图:
发布.NET Framework库的源码
上个月,我们宣布了我们将提供给开发人员下载和浏览.NET Framework库的源码的能力,以及使用Visual Studio 2008来启用集成的源码调试功能。你可以在我这里的博客贴子里了解有关详情。
我们目前正在完成提供这些源码的源码服务器的最后部署,不久就会发布如何在Visual Studio 2008中启用集成调试体验的说明。一旦发布,我会在博客里讨论启用这个功能的详细步骤。
ASP.NET 3.5 Extensions(扩展)
VS 2008 和.NET 3.5包含了成堆的ASP.NET开发方面的新特性。我们计划在明年发布的“ASP.NET 3.5 Extensions”产品里提供更多的ASP.NET功能,下个星期你将可以在网上下载这个产品的第一个公开预览版。
下个星期的ASP.NET 3.5 Extensions预览版将包括:
- ASP.NET MVC: 这个ASP.NET模型/视图/控制器(MVC)框架提供了结构化的模型,促成了web应用中的清晰关注分离,方便你单元测试你的代码和支持TDD流程。它还帮着提供了对你发布在应用中的URL更多的控制,以及从中输出的HTML的更多的控制。你可以在我的ASP.NET MVC教程系列的第一部分中了解有关详情。我希望在这个周末能找到时间撰写和发表这个系列的第二部分。
- ASP.NET AJAX改进: ASP.NET 3.5 Extensions中的新ASP.NET AJAX特性将包括更好的浏览器历史支持(往前,往后按钮的集成,通过 <asp:history> 新服务器端控件实现的服务器端历史管理支持),通过永久链接(permalinks)实现的改良的AJAX内容链接,以及另外的JavaScript库改进等。
- ASP.NET动态数据支持: ASP.NET 3.5 Extensions将提供允许你更快速地创建数据驱动网站的新特性,它提供了丰富的scaffolding框架(【注】scaffolding, 字典上是脚手架,搭脚手架,支架的意思,在这里大概的意思是指生成基本的应用代码,譬如可以根据数据库内的数据定义生成跟产品有关的模型,控制器,以及视图等),允许你使用ASP.NET WebForms和ASP.NET MVC进行快速的数据驱动网站的开发。
- ASP.NET Silverlight支持: 随着ASP.NET 3.5 Extensions的发布,我们将提供将Silverlight轻松集成进你的ASP.NET应用的支持,这些支持将包括一些新控件,它们方便你在网站上集成Silverlight视频,音频和可交互性内容。
- ADO.NET Data Services (数据服务): 与此同时,我们还将发布ADO.NET Entity Framework(实体框架)。这提供了一个新的建模框架,允许开发人员定义与数据库数据定义相对应的概念性模型,这个概念性模型与信息的现实世界观更为接近。我们还将发布一套新的数据服务(代号名为“Astoria”),方便你从ASP.NET应用中呈示基于REST的API端点。
Silverlight 2.0
2个月前,我们发布了可用于Mac和Windows的Silverlight 1.0,同时宣布了准备在Linux上推出Silverlight的计划。Silverlight 1.0注重于在浏览器中促成丰富的媒体场景,以及支持一个JavaScript/AJAX编程模型。
明年,我们将推出Silverlight的一个重大的更新版,注重于促进RIA应用的开发。这个发布将包括跨平台,跨浏览器版本的.NET Framework,促成浏览器中的丰富的.NET开发平台。今年早些时候,我们发布了一个早期Alpha版本,内含一些该产品的基本的功能。我们下一个公开预览版将显著增加功能集。在下一个Silverlight公开预览版中将包括下面这些特定于.NET的新特性:
-
丰富的控件: Silverlight将提供一套丰富的控件,使得建造RIA应用极其容易。Silverlight的下一个公开预览版将增加对核心表单控件(文本框,复选框,单选框等),内置的布局管理控件(StackPanel, Grid等),常用的功能控件(TabControl, Slider, ScrollViewer, ProgressBar等),以及数据操作控件(DataGrid等)等的支持。
-
丰富的网络支持: Silverlight将提供丰富的网络支持。下一个预览版将增加对REST, POX, RSS, 和 WS* 通讯的支持。它还将增加对跨域网络访问的支持(这样Silverlight客户端可以访问网上任何一个可信任来源的资源和数据)。
我们以前一直把这个启用了.NET的Silverlight版本称为“Silverlight V1.1”。在退后一步,仔细看了其中包括的所有新功能之后(上面列出的只不过是一部分功能而已,还有许许多多的特性我们还没透露呢),我们意识到,将其称为1.1实在没有反映出它的真实本性来。因此,我们决定改名,在以后将其称为“Silverlight V2.0”。
我们将在2008年的第一个季度发布Silverlight 2.0的Beta版。这个Beta将支持一个Go-Live许可,允许开发人员开始建造和部署Silverlight 2.0应用。
我们还将发布一个免费的Visual Studio 2008工具更新,以在Visual Studio 2008内提供极棒的Silverlight 2.0工具支持,允许开发人员轻松地使用任何.NET语言建造Silverlight 应用。我们将同时在Visual Studio 2008的标准和专业版以及免费的Visual Studio 2008 Express版本中支持Silverlight开发。
我将在几个星期内开始撰写一个新的博客教程系列,讨论如何建造Silverlight 2.0应用,深入透彻地展示其中的新功能。欲知详情,请留意我的博客。
IIS 7.0
明年早些时候,我们将作为Windows Server 2008的一部分发布IIS 7.0的最终版。就象我以前在博客里讨论过的,IIS 7.0是我们web服务产品的重大更新,引进了显著改进的和新的扩展性,配置和管理架构。
IIS 7.0中一个非常酷的东西是它与.NET Framework有着极其良好的集成,允许你使用任何.NET语言扩展和定制服务器。你现在可以轻松地使用VB和C#来做一些以前需要非常繁琐的C++ ISAPI才能编写的东西。在服务器上对web应用的部署,管理和日常事务现在IIS和ASP.NET下统一起来了。
我们不久还将开始与大家分享新的IIS的web应用部署框架的细节,该框架允许你轻松地自动化在单机服务器或跨web farm机器上部署web应用。它将方便你对web应用进行版本控制(包括允许你快速回滚到先前的版本),以及在多个服务器间对他们进行自动调配,它还允许你实现部署任务的完全自动化(包括通过命令行以及PowerShell脚本API)。IIS7和这个web部署框架的组合将允许你比过去任何时候都能更好地部署和扩缩你的ASP.NET服务器应用。
结语
上个星期的VS 2008和.NET 3.5的发布对.NET开发来说,是向前跨出的巨大的一步。这个发布不光提供了成堆的新的语言,运行时和工具特性,而且更重要的是,提供了一个我们将来可以建筑在其之上的非常坚实的基础。请留意我的博客,我会对上面提到的产品做更详细的讨论。
希望本文对你有所帮助,
Scott
【原文地址】Visual Studio 2008 and .NET 3.5 Released
【原文发表日期】 Monday, November 19, 2007 10:34 AM
今天我们发布了 Visual Studio 2008 和 .NET 3.5。你可以使用下面的链接下载其最终版:
-
如果你是MSDN订阅者,你可以在MSDN订阅网站下载(注:其中一些版本才上传完毕,如果你还没看到的话,过一会儿再来看一下)。
-
如果你没有订阅MSDN,你可以在这里下载Visual Studio 2008 Team Suite的90天免费试用版本。Visual Studio 2008 专业版的90天试用版本(下载大小稍微小点)将于下个星期推出。Team Foundation Server的90天免费试用版本可以在这里下载。
-
如果你想使用免费的 Visual Studio 2008 Express 版本(下载大小更小一些,而且是完全免费的),你可以在这里下载。
-
如果你只想安装 .NET Framework 3.5运行时,你可以在这里下载。
一些新特性之快速指南
Visual Studio 2008 和 .NET 3.5 内含成堆的新功能和改进。想了解详情的话,下面是一些我以前写的相关博客贴子的链接,以及你可以观看的录像的链接:
VS 2008的多定向支持
VS 2008允许你构建针对多个.NET框架版本的应用。这意味着你可以使用VS 2008打开,编辑,和编译现有的.NET 2.0和ASP.NET 2.0应用(包括使用了ASP.NET AJAX 1.0的ASP.NET 2.0应用),继续在.NET 2.0机器上部署这些应用。你可以从下面的博客贴子里进一步了解其中的工作原理:
ASP.NET AJAX和JavaScript支持
ASP.NET AJAX已经成为.NET 3.5的一部分,不再需要单独下载了。除了包括ASP.NET AJAX 1.0的所有功能外,ASP.NET 3.5现在还包括下面这些丰富的支持: 集成了WebParts的UpdatePanel,与象<asp:menu> and <asp:treeview>这样的控件的 ASP.NET AJAX 集成,WCF对JSON的支持,以及许许多多AJAX方面的改进。
VS 2008 和 Visual Web Developer 2008 在将JavaScript和AJAX集成进你的应用方面还有特别棒的支持。你可以在我这里的贴子里了解相关详情:
你可以在这里观看一些讨论ASP.NET AJAX 和 Visual Studio 2008支持的录像。
我高度推荐这本佳作:ASP.NET AJAX in Action以进一步了解ASP.NET AJAX(客户端和服务器端)。
VS 2008 Web设计器和CSS支持
VS 2008包含一个显著改进的HTML web设计器(是Expression Web产品中的同一个设计器)。该设计器提供了分割视图编辑,嵌套母板页,以及出色的CSS集成。下面是我对此作了详述的2篇文章:
ASP.NET还提供了一个新的<asp:ListView>控件,该控件对数据场景提供了非常丰富的支持,允许对输出的标识做完全的控制,与VS 2008中的新CSS支持还有良好的协作,你可以在我这里的贴子里了解有关详情:
你可以在这里观看一些讨论Visual Studio 2008 新web设计器和新的ListView/DataPager控件的录像。
编程语言方面的改进和LINQ
VS 2008中新的VB和C#编译器对这些语言做了显著的改进。两者都添加了对函数式编程概念的支持,允许你编写更干净,更简洁,更具有表达性的代码。这些特性还促成了我们称之为LINQ(语言级集成查询)的新编程模型,使得查询和操作数据成为.NET中的一等编程概念。
下面是我撰写的一些讨论这些新语言特性的文章(用C#作为示例):
这里是我撰写的其他几个贴子,展示了一些新的VS 2008代码编辑支持和使用这些新的语言特性的一些很酷的方式:
Visual Basic开发团队还录制了一些很棒的讨论LINQ的免费录像,你可以在这里观看。
LINQ to SQL中的数据访问改进
LINQ to SQL是.NET 3.5中内置的OR/M (对象关系映射器)。它允许你使用.NET 对象模型对关系数据库进行建模。然后你可以使用LINQ对数据库进行查询,以及更新、插入,删除数据。LINQ to SQL完整支持事务,视图和存储过程。它还提供了一个把业务逻辑和验证规则结合进你的数据模型的简易方式。下面是一些我讨论如何使用LINQ to SQL的文章:
我认为你会发现LINQ 和 LINQ to SQL极大地方便你建造极其干净的数据模型,编写极其干净的数据代码。我在今后还会撰写更多LINQ to SQL的系列文章(一直没空写完,我非常抱歉,要做的事情太多,可惜时间太少了!)。
Scott Stanfield 正在为www.asp.net网站录像一些非常棒的LINQ to SQL录像,这些录像是基于我上面的系列文章的(录像有VB和C#版本)。你可以在这里观看其中的前四集。
使用Visual Studio浏览.NET Framework库源码
在几个星期前我在博客里提到, 我们将在这个发布里同时发布 .NET框架库源码的引用版本。Visual Studio 2008有内置的调试器支持,自动按需调试进入代码(VS 2008可以自动为你下载适当的.NET框架库文件)。
我们正在部署这些源码服务器,在几个星期里将发表启动这个功能的步骤。
说不尽的其他改进
上面的列表只是所做改进的一小部分。针对客户端开发,VS 2008 包含了对WPF设计器和项目的支持。ClickOnce 和WPF XBAPs现在在FireFox中也工作了。WinForms和WPF项目现在也能使用ASP.NET 应用服务(成员,角色和用户数据)来漫游用户数据了。
办公开发也更加丰富了,包括对Office 2007 Ribbon和Outlook的集成支持。Visual Studio办公工具支持现在也成为Visual Studio的一部分了(对,不用再购买另外的产品了)。
新的WCF和Workflow项目和设计器现在也包括在VS 2008中了。单元测试的速度大为提高,而且单元测试的支持现在包括在VS Professional版本(而不仅仅是VSTS版了)中了。连续集成支持现在也内置于TFS中了。AJAX web测试(单元和压力)现在也由VS Test产品支持了。还有许许多多多的改进,这里无法一一提及了。
安装建议
很多人问我该如何从Visual Studio 2008的早期beta版升级的问题。一般来说,我建议你先卸载Beta2。作为卸载的一部分,你应该卸载Visual Studio 2008 Beta2,.NET Framework Beta2以及Visual Studio Web Authoring Component ,这些是分开的安装,需要分别卸载。之后,我通常建议在卸载后,重新启动机器,以确保在你安装新东西之前,机器处于干净的状态。然后,你就可以在机器上安装VS 2008 和.NET 3.5的最终版了。
安装完毕后,我通常建议你运行 工具->引入和输出设置 菜单选项,选择“重置设置”选项,然后重新选择你喜欢的配置。这有助于确保去掉Beta2版本的老配置(有时还会有助于改进性能)。
注,VS 2008可以和VS 2005 并行,所以完全可以在同一台机器上同时安装它们,不会有任何问题的。
Silverlight工具和VS Web部署项目插件
可在VS 2008最终版下工作的2个非常受欢迎的Visual Studio插件尚未推出。它们是Visual Studio Silverlight 1.1工具 Alpha和Visual Studio Web部署项目插件。 我们希望在下2个星期内推出可在VS 2008最终版下工作的更新版本。如果你在使用VS 2008 Beta2 做Silverlight 1.1开发的话,你最好还是继续使用VS 2008 Beta2 ,直到这个插件的更新版推出为止。
希望本文对你有所帮助,
Scott
【原文地址】Using LINQ to SQL (Part 1)
【原文发表日期】 Saturday, May 19, 2007 12:41 AM
在过去的几个月中我写了一系列涵盖了VS和.NET Framework Orcas版中的一些新特性的帖子,下面是这些帖子的链接:
以上的语言特性帮助数据查询成为一等编程概念。我们称这个总的查询编程模型为“LINQ”--它指的是.NET语言级集成查询。
开发者可以在任何的数据源上使用LINQ。他们可以在他们选择的编程语言中表达高效的查询行为,选择将查询结果转换或构形成他们想要的任何格式,然后非常方便地操作这个结果集。有LINQ功能的语言可以提供完全的类型安全和查询表达式的编译时检查,而开发工具则可以提供在编写LINQ代码时完全的智能感知,调试,和丰富的重构支持。
LINQ支持一个非常丰富的的扩展性模型,该模型将有助于对不同的数据源生成不同的高效运算因子(domain-specific operators)。.NET Framework的Orcas版本将发布一些内置库,这些库提供了针对对象(Objects),XML,和数据库的LINQ支持。
什么是LINQ to SQL?
LINQ to SQL 是随.NET Framework Orcas版一起发布的O/RM(对象关系映射)实现,它允许你用.NET 的类来对一个关系型数据库建模。然后你可以用LINQ对数据库进行查询,以及进行更新/插入/删除数据的操作。
LINQ to SQL完全支持事务,视图和存储过程。它还提供了一种把数据验证和业务逻辑规则结合进你的数据模型的便利方式。
使用LINQ to SQL对数据库建模:
Visual Studio Orcas版中提供了一个LINQ to SQL设计器,该设计器提供了一种简易的方式,将数据库可视化地转换为LINQ to SQL对象模型。我下一篇博客将会更深入一些来介绍怎么使用该设计器(你可以观看我一月份时录制的这个关于如何从头开始创建LINQ to SQL模型的录像)。
通过LINQ to SQL设计器,我可以方便地设计出如下所示的Northwind数据库的示例模型:
上图定义了四个实体类:Product, Category, Order 和 OrderDetail。每个类的属性都映射到数据库中相应表的字段,类实体的每个实例代表了数据表中的一行记录。
在上图中,四个实体类间的箭头代表了不同实体间的关联/关系。它们主要是根据数据库中的主键/外键关系生成的。设计器上的箭头的指向表明了该关系是一对一还是一对多的关系。基于此,强类型的属性将会被加入到实体类中。例如,上边的Category类和Product类之间有一个“一对多”的关系。这意味着Category类将有一个"Products"属性,该属性代表了在该类中所有的产品对象的集合。而Product类将会有一个"Category"属性来指向一个Category类的实例,该Category类的实例表明了了产品所属的类别。
上图中LINQ to SQL设计器的右侧列出了与我们的数据库模型交互的存储过程。在上边的例子中,我添加了一个“GetProductsByCategory”存储过程。它有一个categoryID作为输入参数,返回一个产品实体序列作为结果集。下面的代码将展示如何调用该存储过程。
理解DataContext类
当你点击LINQ to SQL设计器上的“保存"按钮时,Visual Studio将会保存我们建立的代表了实体和数据库关系的各个类。针对加入到我们的解决方案的每一个LINQ to SQL设计器文件,同时也会生成一个自定义的DataContext类。这个DataContext类是我们从数据库中查询实体或者进行更改操作的主要渠道。生成的DataContext类将含有一些属性,对应于我们在数据库中建了模的每个数据表,以及一些方法,对应于我们添加的每个存储过程。
例如,下图就是基于我们上边设计的模型而生成的的NorthwindDataContext类:

LINQ to SQL 代码例子
用LINQ to SQL 设计器对我们的数据库建模之后,我们就可以很方便地编写代码对数据库进行操作了。下边是一些展示了常见的数据库操作的代码例子:
1) 从数据库中查询Products
下面的代码用LINQ to SQL 查询语法来获取Product对象的IEnumerable序列。注意代码是如何通过Product/Category关系来仅查出那些类别是"Beverages"的产品的:
C#:
VB:
2) 更新数据库中的一条产品记录
下面的代码示范了如何从数据库中查询出单一的一条产品记录,更新它的价格,然后将改动保存至数据库:
C#:
VB:
注意:VB在Orcas Beta1中尚不支持Lambda。但是在Beta2中,它就会支持了--那时代码就会能写得更为简洁一些。
3) 向数据库中插入一条新的Category和两条新的Products
下面的代码示范了如何生成一个新的分类,然后生成两条和该分类相关联的产品,然后将这三条记录保存到数据库中。
注意下边,我不用手工去维护主/外键关系,取而代之的是,我只向分类对象的“Products”集合中添加了两个Product记录,然后把该Category对象添加到DataContext的“Categories”集合中,LINQ to SQL将知道自动为我持久适当的PK/FK的关系。
C#
VB:
4) 从数据库中删除Products
下面的代码示范了如何从数据库中删除所有的玩具产品:
C#:
VB:
5) 调用存储过程
下面的代码示范了如何不使用LINQ查询语法,而是通过调用我们在上面向数据模型中添加的“GetProductsByCategory”存储过程来查询Product实体。注意,一旦我查询出了Product结果集,我可以更新/删除它们,然后再调用 db.SubmitChanges()来将这些更新提交到数据库。
C#:
VB:
6) 在服务器端分页查询Products
下面的代码示范了如何通过LINQ查询语法实现高效的服务器端数据库分页查询。通过使用下面的Skip()和Take()操作符,我们从数据库中只查询出从200行开始的10条记录:
C#:
VB:
总结
LINQ to SQL提供了一种很棒的、干净利索的方法来为你的应用程序来建立数据层。一旦你定义了数据模型,你就可以方便而且有效地对它进行查询,插入,更新和删除。
希望以上的介绍和代码例子刺激了你的胃口,希望了解到更多东西。在接下来的几周里我会在该系列中更具体地探讨LINQ to SQL。
希望本文对你有所帮助,
Scott
(博客园 韩现龙译)
【原文地址】ASP.NET MVC Framework (Part 1)
【原文发表日期】 Tuesday, November 13, 2007 3:45 AM
两个星期前, 我在博客里讨论了ASP.NET的一个新MVC(模型、视图,控制器)框架,我们将在不久的将来作为一个可选功能来支持。该框架提供了一个结构化的模型,来加强应用中的清晰关注分离,方便你单元测试代码和支持TDD流程。它还提供了对你在应用中发布的URL的更多的控制,也可以对从中输出的HTML提供更多的控制。
之后,我回答了来自迫切想了解更多详情的很多人的很多问题。鉴于如此高的兴趣,我觉得,写几个贴子更详细地描述如何使用这个框架,也许更有意义些。这是我将在以后几个星期里要撰写的相关贴子的第一个。
一个简单的电子商务店面应用
我将使用一个简单的电子商务商店应用来示范ASP.NET MVC框架的工作原理。在今天的贴子里,我将实现一个产品列单,以及相关的浏览应用场景。
具体来说,我们将建造一个网上商店,允许用户在访问该网站上的/Products/Categories网址时 浏览产品分类列表:
当用户点击上面网页上的产品分类链接时,他们将转到一个产品分类列表URL /Products/List/CategoryName上,该页面列出了指定分类中的还在销售的产品:
当用户点击个别的产品时,他们将转到产品细节URL /Products/Detail/ProductID上,这个网页将显示用户选定的产品的更多细节:
我们将使用新的ASP.NET MVC框架来实现上述的所有功能。这将会允许我们在应用的不同组件间保持“清晰的关注分离”,允许我们更轻易地集成单元测试和测试驱动的开发。
创建一个新的ASP.NET MVC应用
ASP.NET MVC框架包含一个Visual Studio项目模板,方便你创建新的MVC web应用。选择文件->新项目菜单,选择“ASP.NET MVC Web 应用”模板,用它创建一个新web应用。
在默认情形下,当你使用该选项生成一个新应用时,Visual Studio 将为你创建一个新的解决方案,然后往里面加2个项目。第一个项目是web项目,在其中你实现你的web应用的功能。第二个项目是个测试项目,你可以在其中编写单元测试,来测试你的应用代码:
你可以在ASP.NET MVC 框架中使用任何单元测试框架,包括NUnit, MBUnit, MSTest, XUnit以及其他的框架。VS 2008专业版现在包含了对MSTest的内置测试项目的支持(VS 2005版本的MSTest要求你拥有Visual Studio Team System版本才能使用),当你使用VS 2008时,默认的ASP.NET MVC 项目模块自动生成这样的测试项目。
我们还将发布可用以NUnit, MBUnit 和其他单元测试框架的项目模板,所以,如果你更喜欢那些框架的话,你可以轻松地一次点击即生成你的应用和可以马上使用的相应的测试项目。
理解项目的目录结构
ASP.NET MVC 应用的默认目录结构有三个顶层目录:
- /Controllers
- /Models
- /Views
你大概可以猜出来,我们建议把控制器类置于 /Controllers 目录之中,你的数据模型类置于/Models目录之中,你的视图模板置于 /Views 目录之中。
虽然ASP.NET MVC框架并不强迫你总是使用这个结构,但默认的项目模板使用这个模式,我们也把它作为结构化应用的一种比较容易的方式向你推荐。除非你有好的理由使用另外的文件布局,我建议你使用这个默认模式。
把URL映射到Controller类
在大多数web框架(ASP, PHP, JSP, ASP.NET WebForms等等)里,到来的URL一般都映射到保存在硬盘上的模板文件。譬如,"/Products.aspx"或者"/Products.php" URL一般都在硬盘上有个对应的Products.aspx 或Products.php 模板文件来处理请求。当一个web应用的http请求进入web服务器时,web框架运行由硬盘上的模板文件指定的代码,然后这代码负责处理该请求。很多时候,这代码使用Products.aspx 或 Products.php文件中的HTML 标识来帮助生成返回客户端的响应。
MVC框架一般以不同的方式把URL映射到服务器代码上。它不是将URL映射到硬盘上的模板文件,而是直接把URL映射到代码类上。这些类称为“Controllers(控制器)”,它们负责处理到来的请求,处理用户输入和交互,执行基于输入和交互的相应的应用和数据逻辑。然后,一个Controller类一般会调用单独的“视图”组件,该组件负责生成请求的实际的HTML输出。
ASP.NET MVC框架包括一个非常强大的URL映射引擎,在如何把URL映射到Controller类方面,该引擎提供了很多灵活性。你可以使用它来轻松地设置routing(路径选择,路由)规则,然后ASP.NET会根据这些规则,对进来的URL进行评估,选出一个Controller来运行。然后你也可以让routing引擎自动分析出你在URL里定义的变量,让ASP.NET自动把这些变量作为参数传给你的Controller。我将在这个系列将来的一个贴子里,讨论涉及URL routing引擎的比较高级的场景。
映射到控制器类的默认ASP.NET MVC URL Routing规则
在默认情形下,ASP.NET MVC项目有一套预先配置好的URL routing规则,这些规则允许你不用配置什么,就可以轻松地上路。这样,使用一套默认的基于名称的URL映射约定,你就可以开始编写代码了,这些约定是在Global.asax文件(由Visual Studio中新的ASP.NET MVC项目模板生成的)中的ASP.NET Application类中声明的。
默认的命名约定是这样的:把进来的HTTP请求的URL路径的开头部分,譬如 /Products/,映射到一个类,该类的名称遵循UrlPathController的模式,譬如在默认情形下,一个以/Products/开头的URL 会被映射到名为ProductsController的类上。
为建造我们的电子商务产品浏览功能,我们将在我们的项目中加一个新的“ProductsController”类 (你可以使用Visual Studio中的“添加新项”菜单从模板中轻松地创建一个Controller类):
我们的ProductsController是从System.Web.MVC.Controller 基类继承而来,从这个基类继承而来并不是必需的,但它含有一些我们以后可以使用的非常有用的辅助方法和功能:
在项目中定义这个ProductsController类之后,在默认情形下,ASP.NET MVC 框架就会使用它来处理所有到来的以"/Products/"开头的URL的应用请求。这意味着,它会自动被调用来处理我们将在我们的网上商店应用中开启的"/Products/Categories", "/Products/List/Beverages", 和 "/Products/Detail/3" 等URL。
在将来的贴子里,我们还将添加一个ShoppingCartController(以允许用户管理他们的购物车)以及 AccountController (允许用户在网站上创建新的成员帐号,实现登录和退出等功能)。在向我们的项目里添加这2个新的控制器类之后,以/ShoppingCart/ 和 /Account/开头的URL就会自动地导向到这些类做处理。
注:ASP.NET MVC框架并不要求你总是使用这个命名约定模式。我们的应用默认使用这个模式的唯一原因是因为在我们使用Visual Studio创建新的ASP.NET MVC项目时,有一个配置了这个模式的映射规则被自动地添加到了我们的ASP.NET Application 类中。如果你不喜欢这个规则,或者想使用另外的URL映射模式来对它进行定制,那么就到Global.asax中的ASP.NET Application类中做改动。我会在以后的一个贴子讨论该怎么做,到时我也会展示一些URL routing引擎允许的一些非常酷的场景。
理解控制器的Action方法
既然我们已经在项目里创建了一个ProductsController类,我们可以开始添加逻辑来处理来到应用的"/Products/" URL了。
在本贴子的前面定义我们的电子商务店面用例时,我说过我们将在网站上实现3个场景:1) 浏览所有的产品分类, 2) 列出特定分类里的产品, 和 3) 显示特定产品的细节。我们将使用下列这些SEO友好的URL来处理这三个场景:
| URL格式 |
行为 |
URL例子 |
| /Products/Categories |
浏览所有的产品分类 |
/Products/Categories |
| /Products/List/Category |
列出特定分类里的产品 |
/Products/List/Beverages |
| /Products/Detail/ProductID |
显示特定产品的细节 |
/Products/Detail/34 |
我们可以用几种方式在ProductsController类中编写代码来处理这三类到来的URL。一种方式是,覆盖Controller基类中的“Execute”方法,手工编写我们自己的 if/else/切换逻辑,对照用户请求的URL,然后执行适当的逻辑来处理这个请求。
但一种容易得多的方式是,使用MVC框架中内置的功能,该功能允许我们在我们的控制器中定义“action方法”,然后由Controller基类根据我们应用使用的URL routing规则来自动调用适当的action方法来执行。
譬如,我们可以往我们的ProductsController类里添加如下所示的三个控制器action方法,来处理上述的三个电子商务URL场景:
在项目创建时默认配置的URL routing规则会把紧随控制器名称之后的子路径当作请求的action名称来对待。所以,如果我们收到一个/Products/Categories的URL请求,routing规则会把“Categories”作为一个action的名称来对待,Categories() 方法就会被调用来处理这个请求。如果我们收到的是 /Products/Detail/5 URL请求,routing规则就会把“Detail"”当中action的名称,Detail() 方法就会被调用来处理请求,等等。
注:ASP.NET MVC框架并不要求你总是使用这个action命名约定模式。如果你想使用不同的URL映射模式,到 Global.asax文件中的ASP.NET Application类去做改动。
把URL参数映射到Controller的Action方法上
在Controller类中的action方法中可以用几个方法访问URL中的参数值。
Controller基类呈现了可以使用的Request 和Response对象。这些对象跟ASP.NET中你已经熟悉的HttpRequest/HttpResponse对象拥有完全一样的API结构。一个非常重要的区别是,这些对象现在是基于接口(interface)的,而不是封闭的类。具体来说,MVC 框架将发布System.Web.IHttpRequest和System.Web.IHttpResponse接口。这些对象是基于的接口的好处是,现在非常容易mock(模仿)它们,这样,就可以方便对控制器类的单元测试。在将来的博客贴子里,我将对此进行深入的讨论。
下面是一个如何在ProductsController类的Detail action方法中使用Request API来手工获取ID查询字符串值的例子:
ASP.NET MVC 框架还支持自动将进来的URL的参数值映射成action方法的参数。在默认情形下,如果你的action方法有个参数的话,MVC框架会检查进来的请求的数据,看是否有个同样名称的对应的HTTP请求值。如果有的话,它会自动将其作为参数传入你的action方法。
譬如,我们可以利用这个支持来重写我们的Detail action方法来,将其简化,象下面这样:
除了从请求的查询字符串/表单集合中映射参数值外,ASP.NET MVC框架还允许你使用MVC URL route映射基础设施在核心URL本身内嵌参数值(譬如,不是使用/Products/Detail?id=3,而是使用/Products/Detail/3 )。
当你创建一个新的MVC项目时,声明的默认的路径映射规则拥有这样的格式,“/[controller]/[action]/[id]”。这意味着,如果URL中在控制器名称和action名称之后还有任何子路径的话,在默认情形下,它将作为一个名为“id”的参数处理,会自动地作为一个方法参数传给我们的控制器action方法。
这意味着我们现在可以使用我们的Detail 方法来处理从URL路径(譬如/Products/Detail/3)中获取ID参数:
我可以对List action使用类似的方法,这样我们可以将分类名称作为URL的一部分传进来(譬如:/Products/List/Beverages)。为了使得代码容易阅读,我对routing规则做了一个小变动,这样不是把参数名定为“id”,对这个action,它被称作“category”。
下面是实现了完整URL routing和参数映射支持的ProductsController类的一个版本:
注意上面List action方法接受一个作为URL一部分的category参数,然后一个作为URL查询字符串一部分的可缺省的网页索引参数(我们将实现服务器端分页,将使用该参数值来表示我们应该显示对应分类数据的哪一页)。
我们的MVC 框架中的可缺省的参数是通过Controller Action方法上nullable的类型参数来处理的。因为我们List action的分页参数是个nullable的int,从语法上来说,即是int? ,如果这个参数存在于URL中,MVC框架会将其值传给对应方法,如果不存在,会传入null。参阅我以前的关于?? null coalescing operator帖子以了解如何操作象这样传入的nullable类型参数的一个有用的技巧/诀窍。
建造数据模型对象
至此,我们有了一个 ProductsController类,内含三个action方法,准备好处理进来的web请求了。下一步将是建造一些类,来帮我们操作数据库,从中获取处理这些请求所需的适当的数据。
在MVC世界里,“model(模型)”是负责保持状态的应用组件。在web应用中,这个状态一般都持久于数据库之中(譬如,我们也许有一个Product 对象,用来代表我们SQL数据库里Products表中的产品数据)。
ASP.NET MVC框架允许你为获取和管理你的模型,可以使用你想要的任何数据访问模式或框架。如果你要使用ADO.NET DataSets/DataReaders (或者建于它们之上的抽象),你可以那么做。如果你更喜欢使用象NHibernate, LLBLGen, WilsonORMapper, LINQ to SQL/LINQ to Entities这样的对象关系映射器(ORM),你也绝对可以那么做。
对我们的电子商务例程,我想用随 .NET 3.5 和 VS 2008发布的内置LINQ to SQL ORM 。你可以从我的还在撰写中的讨论LINQ to SQL 的博客系列中了解其中详情,特别是一定要阅读一下其中的第一部分,第二部分,第三部分,和第四部分的帖子。
从右击VS中的MVC web项目的“Models”子目录开始,选择“添加新项”,加一个 LINQ to SQL 模型。在LINQ to SQL ORM 设计器中,我将定义三个数据模型类,分别映射到SQL Server Northwind数据库中的Categories, Products, 和Suppliers 表(阅读我的LINQ to SQL 系列的第二部分学习该怎么做):
定义完LINQ to SQL 数据模型类之后,然后我还将添加一个新NorthwindDataContext部分类到我们的Models目录中:
在这个类中,我将定义几个辅助方法封装一些LINQ表达式,这些表达式是用来从数据库中获取独特的Category对象,获取指定分类的所有Product 对象,以及基于指定的ProductID获取单独的 Product对象:
这些辅助方法将方便我们在ProductsController类中干净利索地获取所需的数据模型对象 (而不用在Controller类中编写LINQ表达式):
至此,我们就有了为完成我们的ProductsController功能所需的所有的数据代码和对象。
完成ProductsController类的实现
基于MVC的应用中的控制器类负责处理到来的请求,处理用户输入和交互,并且基于这些输入和交互执行适当的应用逻辑(获取和更新储存在数据库中的模型数据等等)。
控制器一般不对请求生成特定的HTML响应。生成HTML响应的任务是为应用中的“视图”组件所拥有,这些视图是通过独立于控制器的单独的类或模板实现的。视图的目的是完全注重于封装表现层的逻辑,不应该包含任何应用逻辑或数据库数据获取的代码的(所有的应用逻辑应当为Controller来处理)。
在一个典型的MVC web流程中,控制器action方法负责处理进来的web请求,使用传入的参数值执行适当的应用逻辑代码,从数据库中获取或更新数据模型对象,然后选择使用一个“视图”来显示返回给浏览器的界面响应。作为选择适当的视图来显示的一部分,控制器会明确地以参数的形式向“视图”传入视图所需的所有的数据和变量,以使后者显示适当的响应:
你也许在想,象这样分开Controller和View有什么好处呢?为什么不把它们放在同一个类里呢?象这样分割应用的主要动机在于帮助你加强应用/数据逻辑与你的界面生成代码间的分离。这可以在隔离你的界面显示逻辑的情形下,极大地方便你单元测试你的应用/数据逻辑。它还有助于使得你的应用更好维护,因为它妨碍了你无意中把应用/数据逻辑加到你的视图模板里的可能。
在实现我们ProductsController类的三个控制器action方法时,我们将根据进来的URL参数值从数据库中获取适当的模型对象,然后选择一个“视图”组件来显示适当的HTML响应。我们将使用Controller基类的一个RenderView() 方法来指定我们想要使用的视图,以及明确地把我们要视图在显示响应时使用的特定数据传入该方法。
下面是我们的ProductsController实现的最终结果:
注意,我们的action方法的代码行数目很小(每个方法只有2行),部分原因是因为URL参数分析逻辑完全是由MVC框架为我们做的(给我们省了很多行代码),还有部分原因是因为产品浏览场景从业务逻辑的角度来说相当简单(涉及的action方法都是只读的显示场景)。
但总的来说,你经常会发现你有的都是些有时被称为“瘦控制器”的东西,即控制器方法充满了相当简短的action方法(少于10行代码)。这经常是好的迹象,表明你非常干净地封装了你的数据逻辑,也非常好地分隔了你的控制器逻辑。
单元测试ProductsController
你也许会感到惊奇,我们要做的下一步居然是测试我们的应用逻辑和功能。你也许会问,这怎么可能呢?我们还没有实现我们的视图呢,我们的应用目前并不显示一个HTML tag。其实呢,使得MVC方法有魅力的部分原因就是我们可以完全独立于视图/Html生成逻辑来测试Controller和Model 逻辑。在下面你将看到,我们甚至可以在创建视图前单元测试这些对象。
为单元测试我们在编写的ProductsController类,我们将往测试项目里加一个ProductsControllerTest类,这个测试项目是在我们使用Visual Studio创建我们的ASP.NET MVC应用时,默认添加到我们的解决方案里的:
然后我们将定义一个简单的单元测试,测试我们的ProductsController的 Detail action方法:
ASP.NET MVC 框架是特地设计来促成轻松的单元测试的。框架中的所有的核心API和契约都是接口,提供了大量的扩展点以促成轻松的对象注入和定制(包括使用象Windsor, StructureMap, Spring.NET, 和ObjectBuilder这样的IOC容器的能力)。开发人员将能够使用内置的mock类,或者使用任何.NET 类型mock框架来模拟他们自己的MVC相关对象的测试版本。
在上面的单元测试中,你可以看到一个例子,我们是如何在调用 Detail() action 方法之前,往我们的ProductsController里注入了一个伪(dummy)“ViewFactory”实现的。这么做的话,我们就覆盖了默认的ViewFactory,否则的话,默认的ViewFactory会创建和显示我们的视图。我们可以使用这个测试ViewFactory实现来做隔离,只对我们ProductController的Detail action的行为进行测试(而不必调用实际的视图来做测试)。注意我们是如何在Detail() action方法被调用之后,使用了三个 Assert 语句来核实该方法的正确的行为确实发生了(具体地说,该方法获取了正确的Product对象,然后将它传给了适当的视图)。
因为我们可以mock和模拟MVC框架中的任何对象(包括 IHttpRequest 和 IHttpResponse 对象),你不用再在web服务的环境里运行单元测试,我们可以在常规的类库里创建我们的ProductsController对象,然后对它直接测试。这可以极大地加快单元测试的运行速度,以及简化对它们的配置和运行。
如果我们使用 Visual Studio 2008 IDE,我们还可以轻易地跟踪我们运行测试的结果(这个功能现在已经成为VS 2008 专业版的一部分):
我想你会发现ASP.NET MVC 框架极大地方便了测试的编写,而且促成了非常好的TDD流程。
使用视图显示界面
我们完成了我们电子商务应用的产品浏览部分的应用+数据逻辑的实现和测试,现在我们需要实现相关的HTML界面。
我们将通过实现“视图”来实现,这些视图将使用我们ProductsController的action方法在调用RenderView() 方法时提供的跟视图有关的数据对象,来显示适当的界面:
在上面的代码例子里,RenderView方法的“Categories”参数表示我们要显示的视图名称,第二个参数是我们要传给视图对象并要视图对象据此显示适当HTML界面的分类对象的列表。
ASP.NET MVC框架支持使用任何模板引擎(包括象NVelocity, Brail,以及你自己想要编写的任何模板引擎)来帮助生成界面。在默认情形下, ASP.NET MVC 框架使用ASP.NET中现有的ASP.NET 页面 (.aspx), 母版页 (.master), 和用户控件 (.ascx) 。
我们将使用内置的ASP.NET 视图引擎来实现我们的电子商务应用的界面。
定义Site.Master文件
因为我们将要在网站上建造很多页面,我们先来定义一个母版页,用以封装整个网站公用的HTML布局/样式。我们将在我们项目的\Views\Shared 目录里创建一个名为“Site.Master”的文件:
我们可以引用一个外部的CSS样式文件来封装整个网站的所有样式,然后使用母版页来定义网站总的布局,以及指定我们要具体页面填充相关内容的内容placeholder 区域。在做的时候,我们也可以使用VS 2008 中的新设计器的所有的酷功能,包括HTML分割视图设计器,编著CSS和嵌套母版页支持等。
理解/Views目录结构
在默认情形下,当你使用Visual Studio创建新的ASP.NET MVC 项目时,它会在“Views”根目录下生成一个“Shared”子目录。这是存放应用中为多个控制器所共享的母版页,用户控件和视图的推荐使用的地点。
在建造为特定个别控制器所用的视图时,默认的 ASP.NET MVC 约定是,把它们存放在\Views 根目录的子目录里。在默认情形下,子目录的名字应该对应于控制器的名字。譬如,因为我们正编写的Controller类叫“ProductsController”,在默认情形下,我们将在\Views\Products 子目录里存放跟它相关的特定视图:
当我们在一个特定的Controller中调用 RenderView(string viewName)方法时,MVC框架会自动地首先在\Views\ControllerName 目录里寻找对应的.aspx 或 .ascx视图模板,如果它找不到适当的视图模板,然后它会在 \Views\Shared目录寻找。
创建一个Categories视图
我们可以在 Visual Studio 中 Products 目录上使用“添加新项”菜单选项,然后选择“MVC视图网页”项模板,为我们的ProductsController 创建一个“Categories”视图。这会生成一个新的.aspx 页面,我们可以将它跟我们的 Site.Master母版页相关联,来得到总的外观(就象母版页一样,你会得到即见即所得设计器的支持):
在使用MVC模式建造应用时,你要把你的视图代码尽可能地保持简洁,确认视图代码纯粹是用来显示界面。应用和数据获取逻辑应该只在Controller类里编写。然后Controller类就可以在调用RenderView 方法时选择把所需的数据对象传递给视图。譬如,在下面,我们的ProductsController类的 Categories action方法中,我们把 一个Category对象的List集合传给了Categories视图:
MVC视图页默认是从System.Web.Mvc.ViewPage 基类继承而来的,该基类提供了可为我们构建界面时所用的许多特定于MVC的辅助方法和属性。ViewPage的其中一个属性名叫“ViewData”,通过它,你可以访问Controller作为参数传给 RenderView()方法的特定于视图的数据对象。
从你的视图里,你可以后期绑定或以强类型的方式访问“ViewData”。如果你的视图是从ViewPage继承而来,那么ViewData属性是个后期绑定的字典。如果你的视图是从基于泛型的ViewPage<T>继承而来,其中T表示Controller传给视图的ViewData的数据对象的类型,那么ViewData属性就是强类型的,匹配你的Controller传入的数据的类型。
譬如,如下所示的我的Categories视图的后台类是从ViewPage<T>继承而来,我指明T为Category对象的一个List
这意味着在我的视图代码里操作ProductsController.Categories() 提供的List<Category> ViewData时,我将得到完整的类型安全, intellisense和编译时检查:
显示Categories视图:
如果你还记得本帖子最前面的截图的话,我们要在我们的 Categories 视图里显示产品分类列表:
我可以在我的Categories视图实现里用2种方式编写这个HTML界面生成代码:1) 在.aspx 文件里使用行内代码, 或者 2) 在.aspx 文件中使用服务器控件,然后在后台代码里使用数据绑定。
显示方法1:使用行内代码
目前的ASP.NET网页, 用户控件和母版页支持使用 <% %> 和 <%= %>的句法来在html 标识内嵌入显示代码。我们可以在Categories 视图里使用这个技巧,轻松地编写一个foreach循环,来生成HTML分类列表:
VS 2008在源码编辑器内为VB和C#提供完整的代码intellisense。这意味着,在对传入视图的Category模型对象操作时,我们将得到intellisense:
VS 2008还为行内代码提供了完整的调试器支持(允许我们在调试器对视图中的代码设置断点以及动态检查任何东西):
显示方法2:使用服务器端控件
ASP.NET网页,用户控件和母版页还提供对使用声明式服务器端控件封装HTML界面生成的支持。不是象上面那样使用行内代码,我们可以使用 .NET 3.5中新的<asp:listview> 控件来生成列表界面:
注意上面 ListView 控件封装了显示值列表的情形,还负责处理列表中没有任何东西的情形(<EmptyDataTemplate>省略了需要在标识中编写 if/else 语句的麻烦)。然后我们可以象下面这样,在后台代码里,将我们的分类对象绑定到listview控件上:
重要注意事项:在MVC世界里,我们只想要把显示代码放在我们视图的后台代码里,不包括任何应用或数据逻辑。注意上面我们只有把强类型的Category对象的ViewData集合赋值给ListView控件的逻辑。我们的ProductsController控制器类才是实际从数据库获取Category对象列表的责任者,不是视图。
我们视图模板的ListView服务器端控件版本然后就会生成跟上面行内代码版本完全一样的HTML。因为我们在页面里没有 <form runat="server">控件,ViewState,ID值以及其他的标识都不会生成,只有纯粹的CSS友好的HTML:
Html.ActionLink方法
你也许注意到的一件事情是,在上面视图代码片断中行内代码以及服务器端控件两个版本中对一个Html.ActionLink 方法的调用:
Html对象是 ViewPage 基类的一个辅助属性,ActionLink方法是它的一个辅助方法,它方便你动态地生成连回到控制器的action 方法的HTML超链接。如果你看一下上面生成的HTML输出图,你可以看到一些由该方法生成的一些HTML输出例子:
<a href="http://weblogs.asp.net/Products/List/Beverages">Beverages</a>
我使用的Html.ActionLink方法的签名是这样的:
string ActionLink(string text, object values);
第一个参数表示要显示的超链接的内容(譬如<a>这里是文字</a>),第二个参数是个匿名对象 ,它代表用以生成实际URL的一串值,你可以认为它是生成字典的一个比较干净的方式。我会在将来讨论URL routing引擎的博客帖子里仔细讨论这个参数的运用情形。但简而言之,你可以使用URL routing系统既处理进来的URL,也可以用它来生成你可以在返回的HTML输出的URL。如果我们的routing规则是象这样的:
/<controller>/<action>/<category>
那么在ProductController的Category视图里编写这样的代码时:
<%= Html.ActionLink("Click Me to See Beverages", new { action="List", category="Beverages" } %>
ActionLink方法就会使用你应用的URL映射规则,换进你的参数,生成这样的输出:
<a href="http://weblogs.asp.net/Products/List/Beverages">Click Me to See Beverages</a>
这方便了在你应用中生成URL和到你的控制器的AJAX回调。它也意味着你可以在一个地方更新你的URL routing规则,你整个应用中的代码会在对进来的URL的处理和外出的URL的生成过程中自动采用新的变化。
重要注意事项: 为加强可测试性,目前的MVC框架并不支持你视图中针对服务器端控件的postback事件,取而代之的是,ASP.NET MVC应用生成超链接和对控制器action的AJAX回调,然后只使用视图(以及其中的任何服务器端控件)显示输出。这有助于确保你的视图逻辑保持在最小限度,只注重于显示,以及你可以单元测试你的Controller类,独立于你的视图,核实所有的应用和数据逻辑行为。我在将来的帖子里会对此做更深入的讨论。
结语
这第一个贴子非常长,但希望它对新的ASP.NET MVC框架中所有不同的组件是如何组合在一起的,如何使用它打造常见的现实世界场景的应用提供了一个相当广泛的综览。 ASP.NET MVC的第一个公开预览版将在几个星期内发布,你将能够使用它来做我上面描述的一切。
虽然很多MVC固有的概念(特别是关注分离的观念)对该贴子的很多读者来说是比较新的,但希望本贴子展示了我们正在开发的ASP.NET MVC实现是如何很干净地嵌合到现有的ASP.NET, .NET, 和 Visual Studio框架中的。你可以使用.ASPX, .ASCX 和 .MASTER文件以及ASP.NET AJAX创建你的ASP.NET MVC 视图。今天ASP.NET中的非界面功能,譬如表单认证, Windows认证, 成员,角色, Url授权, 缓存, Session 状态, 用户信息,健康监测, 配置,编译,本地化以及 HttpModules/HttpHandlers 都是完全支持MVC模型的。
如果你不喜欢MVC模型,或者发现它对你的开发风格来说并不自然的话,你完全不必强用它的。它完全只是提供选项,并不替代现有的 WebForms Page Controller 模型。WebForms和MVC这2个模型在以后都会得到完全支持和改进。如果你想的话,你甚至可以建造一个应用,部分使用WebForms编写,部分使用MVC编写。
如果你喜欢上面贴子里的东西的话(或者感兴趣想进一步了解的话),留意一下我这段时间的博客。我将进一步讨论MVC概念,使用它们来进一步建造我们的电子商务应用,展示更多的MVC特性。
希望本文对你有所帮助,
Scott