2、核心问题还是要能解决“安全”“随时”“随地”和“快速”等问题,并承若数据足够的私有性(哪家Saas敢承若承担由于数据泄露所引起的损失)
3、基于富客户端和瘦客户端允分结合的Saas的补分:
1)、瘦客户端:如阿里巴巴的网站,并不断增加Ajax成份
2)、富客户端:优势,可离线和丰富操作等。一方面是IM工具(淘宝旺旺等),另一方面是WPF/Flex
值得关注! 阅读全文
2007-06-13 15:23 作者: 针式个人知识库管理【评论:2】【阅读:342】
看到csdn上n多人问同样的问题,ajax乱码等等的,想做个总结,不对的地方请各位指教。
我所说的环境是asp.net web应用,其他web开发应用一个道理。
开发国际1.首先你项目所有的东东(主要指各种文件,包括后台代码、资源文件等)采用utf-8文件编码,这一步解决了文件编码问题(确保你的文件真正应用了或转成了utf-8编码,用转换工具或vs的高级存储选项)
2.把你所有的web页面meta中指定charset为utf-8(可以为link、script同时指定charset),这样你从页面发出的请求(声明一点这个请求非ajax请求,ajax请求另作处理),如点击按钮产生的post请求等都是以utf-8传输内容的了
3.做了2的步骤之后,就要求服务器端晓得你的client发来的http请求默认编码的是utf-8的了,一旦它知道了,你在服务端取request中的参数就也不必要做单独的utf-8解码处理了,这个在asp.net中用web.config通知web server 的asp.net处理引擎,在其中system.web下加入如下配置:
4.解决ajax请求的编码问题,就是让ajax求不采用默认的编码传输数据,而是和我们的系统统一采用utf-8编码,这个要根据你使用的具体的js lib进行设置,prototype中默认用utf-8(如果没有的话,你可以用ajax的options选项加入encoding:'utf-8'),用dojo的话默认是ansi,各位可以按需设置。另外对于裸写ajax请求的用户你可以这样指定:
request.setRequestHeader('Content-type','application/x-www-form-urlencoded; charset=utf-8');
5.稍微要注意的另一点是,对于get请求(或凡涉及到url传递参数的),被传递的参数都要先经encodeURIComponent方法处理
就总结这五点,有问题地方再交流,本人有总结疏漏的地方请指正,之前我们项目中的多言语、ajax及普通请求乱码问题完全解决了
2007-06-13 15:23 作者: 针式个人知识库管理【评论:2】【阅读:342】
摘要
本期共有8篇文章:
- ASP.NET AJAX Control Toolkit版本更新
- 技巧和提示:ASP.NET AJAX 1.0和用户控件
- 创建自定义Provider
- 在Windows、Mac和Linux上的多种浏览器中测试你的站点
- 弹跳小球的动画性能测试——比较各种实现方法
- 调试ASP.NET客户端JavaScript脚本
- JavaScript困境
- Microsoft对决TestDriven.NET - 06 June 2007
[1] Updated Toolkit Release Now Available (ASP.NET AJAX Control Toolkit版本更新)
似乎自打ASP.NET AJAX发布了1.0版本之后,这部分的动向就越来越少了。众人都被SilverLight吸引了过去……不过沉浸了几个月之后,ASP.NET AJAX Control Toolkit却突然来了一次版本更新。
这次版本更新并没有什么破坏性的变化,修复了100多个Bug,并添加了一些丰富的功能,例如:
- VS设计器对TabContainer的支持。
- 能够与ASP.NET validatiors完美集成使用。
- 添加了更多的客户端事件。
- 在VS中自动生成一些服务器端方法。
- 脚本组合。
- 动态上下文支持。
对于第5项功能,将大大减少页面的加载时间。先看看以前版本吧:

现在就好多了:

[2] Tips and Tricks: ASP.NET AJAX 1.0 and User Controls (技巧和提示:ASP.NET AJAX 1.0和用户控件)
ASP.NET AJAX 1.0和用户控件一起使用的时候,往往会让开发者产生很多疑问。常见的有ScriptManager的位置,UpdatePanel的设定,加载用户控件的时机等等。这篇文章简要分析了这类常见问题,并给出了一些作者自己的观点,有需要的朋友不妨参考一下。
作者的另一篇文章《Tip and Tricks: ASP.NET 2.0 AJAX 1.0 Extensions and Master Pages》则讨论了ASP.NET AJAX 1.0和Master Page之间的关系,同样值得一看。
[3] Working with Custom Providers(创建自定义Provider)
ASP.NET 2.0中引入的一个非常重要的概念就是Provider模型,这种模型为我们开发者提供了非常强大的自定义扩展功能,让我们几乎可以随时及项目的需求任意定制某个复杂ASP.NET功能的具体实现流程。
不过创建自定义的Provider却似乎并不是件容易的事情,这篇文章就通过一个示例程序详细介绍了创建的过程。其中语言组织非常不错,行文也比较流畅。若你想提高一下自己的ASP.NET功底,那么花点时间看看这篇文章将会是个不错的主意。
与这篇文章相关的还有同一作者写的《Working with Custom Provider Controls》,这篇文章根据上一篇文章中的Provider编写了一些控件,非常有意思。
[4] browsershots.org - Test your site in a variety of browsers on Win, Mac, and Linux (在Windows、Mac和Linux上的多种浏览器中测试你的站点)
browsershots.org提供了一个免费的,在Windows、Mac和Linux上的多种浏览器中测试你的站点的服务。只要提交一个服务请求,该网站就会自动为你运行测试……非常有意思,也是非常强大的辅助工具。
下面是网站的一个截图:
[5] Bubblemark animation test (弹跳小球的动画性能测试——比较各种实现方法)
想知道各种富客户端应用解决方案的性能么?有“好事者”最近就是用各种RIA技术创建了同样的一个测试场景,并集中到了http://bubblemark.com/网站中:
小球将在方框中弹来弹去——很容易直观地看出各种实现方案的优劣之分。目前已经有了如下一些实现方案:
- DHTML
- Silverlight (JavaScript)
- Silverlight (CLR)
- Flash (Flex)
- Flash (Flex) with cacheAsBitmap
- WPF
- Java (Swing)
- Flex Apollo app
- HTML Apollo app
[6] Client Side Script Debugging in ASP.NET (调试ASP.NET客户端JavaScript脚本)
虽然这似乎不是什么新的技术了,不过似乎好多朋友根本不知道如何调试JavaScript。实际上,VS 2005本身已经提供了非常强大(虽然Bug不少)的JavaScript调试支持,可是很多朋友仍旧会看着IE左下角的黄色脚本异常提示图标发愣,不知道如何入手。
如果你也是其中的一员的话,那么这篇文章将会告诉你一些起步的知识。当然,仅仅是起步而已,并没有太过深入的分析,特别是文中没有涉及什么VS脚本调试器中的Bug问题,让人觉得很不爽……
这里为自己做个广告,在我的《ASP.NET AJAX程序设计 第III卷:高级内容》中,将会详细介绍有关客户端脚本调试的知识,敬请期待:)
[7] The JavaScript Dilemma (JavaScript困境)
JavaScript似乎一直就是个颇有争议的东西,ASP.NET MVP Rick Strahl最近也写了一篇长长的文章表达了一下自己的想法。不过他的语言似乎不是那么容易读懂,有兴趣的朋友就看看吧。
[8] Microsoft vs TestDriven.NET - 06 June 2007 (Microsoft对决TestDriven.NET - 06 June 2007)
前两天翻译了一篇有关Microsoft于TestDriven.NET 打架的故事(《TestDriven.NET和Visual Studio Express的纠纷往事》),TestDriven.NET的作者又有了一些新的想法和动向。
看看人家都要上法庭了,下面评论的各位网友还都是心平气和,没一个破口大骂的……让我不知说什么好……无奈?还是羡慕?
这次更新最主要的可能就是官方文档的更新,尤其是对页面的客户端页面生命周期与UpdatePanel客户端生命周期(事实上前者包含了后者)提供了详细的说明和举例。原本我想在3月29日的WebCast中详细讲解的内容,被官方文档覆盖了不少。官方文档越详细,像我这样的技术博客作者可以发挥的余地就小了,还好总是有能够努力的地方。
哎,我要重新想一下WebCast的内容了。不过我在WebCast里会提到一部分UpdatePanel的实现等等,这些属于高级话题。对于这方面有兴趣的朋友可以和我多多交流。:)
至于ScottGu还推荐的其他一些文章,可读性一般。说实话,这些“技术含量”我们绝对能够达到。还有一些文章博客园的朋友们也已经推荐过了,例如Cat Chen曾经推荐过的:How to Build a PageFlakes.com-like Home Page using ASP.NET AJAX。
其实我们完全有能力做的不比他们差,但是我们的确比他们差了。我们最大的弱势在哪里呢?我认为是氛围和语言。我们又该如何解决这样的问题呢?
Orcas主要是VS2005的发布以来的一些反映的Tip的完善,记得在2006年5月份中国微软的谭强来深圳,当时聊起VS2005的相关问题,我给他列了十条,好几条都在这个版本得到实现了,看来Orcas值得期待。还是贴几张图片看看就清楚这些功能是不是也是你所期待的。
在下午的最后一个Session见到Asp.net开发小组的几个成员,主要也是讨论Orcas中的这些功能。Orcas的Pro版本将包含单元测试功能,这个功能vs2005只有VSTS才有,对测试驱动开发的支持,MVC模式的Asp.net的默认实现等,没有透露具体的实现细节,你觉得会怎么设计,我现在的asp.net要做这么大的修改不是一件容易的事。下面贴一张今天出现的asp.net开发组成员照片。

1. windows/temp 目录添加 netword service 帐户;
2. IIS配置下 asp.net 目录添加 netword service 帐户 和 Internet 来宾 帐户;
3. IIS里检测.net framework 版本;
4. 应用程序池 .net framework 版本冲突导致出错的问题, 所以各站点创建各自的应用程序池;
5. 重新注册iis , 找到C:WINDOWSMicrosoft.NETFrameworkv2.0.50727(这里指的是指需要重新注册的framework目录), 运行代码: " aspnet_regiis -i " ;
.net2.0与1.1之比较
“虽然业界对Visual Studio 2005的期望值很高,但它正式推出后,依然远远超出业界的预期。以.NET Framework 2.0为基础的Visual Studio 2005包括微软5年来对.NET 1.0的所有修正。在1.0中还需花费大量时间编写代码的功能,在2.0几乎不需要再写代码或者只需短短几行代码就可以完成。更重要的是,.NET Framework 2.0增添了的不少新类,同时相当多的类被重写,并赋予新的功能,从某种角度来说,2.0更像一种新的语言,由于它的严重“超值”,引来不少开发人员得抱怨。除此以外,微软努力使Visual Studio 2005更适应团队开发,落实了生命周期管理和流程管理,整合了单元测试功能。在2000年我们震惊于.NET 1.0,今天Visual Studio 2005带来的无疑是第二次震撼。”--------天极开发者网络
一、asp.net 2.0的先进性。
asp.net2.0将成为下一代Windows应用程序的基础支柱并集成在Windows Vista之内。
<!--[if !supportLists]-->1、 <!--[endif]-->支持泛型
泛型就是将类型参数化,实现更加广泛的复用。由于减少了装箱和拆箱,泛型对于值类型的对象性能提升明显。
(1) 对于int这样的简单值类型,泛型能够提高2-5倍的速度。数据量越大,越明显。
(2) 对于复杂的值类型,泛型能够提高30%-300%。数据量越大,越明显。
(3) 对于引用(Reference)类型,泛型和传统的方式速度相当。
(4) 泛型是 C# 2.0 的最强大的功能。通过泛型可以定义类型安全的数据结构,而无须使用实际的数据类型。这能够显著提高性能并得到更高质量的代码,因为您可以重用数据处理算法,而无须复制类型特定的代码。
<!--[if !supportLists]-->2、 <!--[endif]-->微软的asp.net ajax(原来叫atlas)与asp.net2.0无缝集成
为了改善用户体验,我们应该在项目中尽可能使用ajax技术来减少页面刷新。
与 .NET 和 Java 平台下其它 AJAX 框架相比,微软的asp.net ajax框架最大的亮点就在于与 ASP.NET 现有机制的无缝融合。通过 VS.NET 集成开发环境,使用者可以在对 js 和 AJAX 不甚了解的情况下,以非常自然的方式使用到最先进的技术。此外直接在 js 一级提供 WebService 的调用支持,也大大降低了对 ws 技术的使用门槛。而 ASP.NET 中一直引以为豪的数据绑定等技术,也可以在 Altas 中无缝得到支持,让现有投资能够最大限度得到保护。从这些意义上来说,虽然 Altas 在 AJAX 理念上没有太多突破,但不失为一个强大且实用的 AJAX 框架,非常符合 MS 在技术运用上的一贯原则。
传统的 WEB 应用程序模型是这样工作的:用户的界面操作触发 HTTP 请求,服务器在接收到请求之后进行一些业务逻辑处理,如保存数据等,然后向客户端返回一个 HTML 页面。但这种方式并没有给予用户很好的应用体验,当服务器在处理数据的时候,用户则处于等待的状态,每一步操作都需要等待,太多的等待会使用户越来越没有耐心。而 Ajax 则大不相同,它通过 Ajax 引擎,使得应用过程很自然,操作很流畅,因为其只和服务器交换有用的数据,而页面显示等不必要的数据则不再重新加载,通过适当的Ajax应用达到更好的用户体验而且可以把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理,减轻服务器和带宽的负担。
ASP.NET AJAX是微软进军跨平台网络功能领域的作品,用于异步JavaScript的网络开发,可以让开发人员开发出更具互动行动网络应用,提高用户个性化水平。ASP.NET AJAX 1.0的主要功能有:异步客户端到服务器网络、服务器端ScriptManager和ScriptManagerProxy控件、客户端Trace类、Timer控件、Selector控件、JavaScript认证等等。
<!--[if !supportLists]-->3、 <!--[endif]-->使用ADO.NET2.0
(1)、新的索引引擎:
在 ADO.NET 2.0 中已经彻底重新编写了用于 DataTable 的索引引擎,并且使其能够更好地针对大型数据集进行伸缩。这会使基本的插入、更新和删除操作变得更加快速,从而使 Fill 和 Merge 操作变得更快。
(2)、流到缓存,缓存到流
对于 ADO.NET 2.0 中的 DataSet 和 DataTable 类的另一个主要增强是,提供了用来消耗 DataReader(将数据加载到 DataTable 中)以及在 DataTable 的内容之上公开 DataReader 的机制。
有时,我们具有(或收到)DataReader 形式的数据,但实际上是希望具有缓存 DataTable 形式的数据。通过新增的 Load 方法,我们可以获得现有的 DataReader,并使用它的内容来填充 DataTable。
有时,我们具有(或收到)缓存形式的数据 (DataTable),并且需要通过 DataReader 类型接口来访问它。通过新增的 GetTableReader 方法,我们可以获得现有的 DataTable,并通过 DataReader 接口和语义来访问它。
(3)、很多以前DataSet的方法,现在可以用DataTable直接使用了
大多数 .NET 开发人员都知道 DataTable 本身(没有封装在 DataSet 内部)极为有用,并会利用这一事实。但是,在某些情况下,我们无法通过 DataTable 完成我们希望完成的工作,除非我们首先获得它并将其强行转换为 DataSet。这方面的最突出并且通常令人痛苦的示例是在 DataTable 中读取和写入(加载和保存)XML 数据。在 ADO.NET 1.x 中,我们必须首先将 DataTable 添加到 DataSet 中,只有这样我们才能读取或写入 XML,这是因为完成该工作的方法只能在 DataSet 上使用!
ADO.NET 2.0 的目标之一是使独立的 DataTable 类比在 ADO.NET 1.x 中更为实用和有用。
DataTable 可单独序列化,并且可以在 Web 服务和远程处理方案中使用。
附:ADO.NET 2.0 中的新增 DataSet 功能
http://www.microsoft.com/china/MSDN/library/NetFramework/default.mspx?mfr=true
4、改进的ViewState
ViewState 在 ASP.NET 中有个重要的角色。如果使用恰当,它能够简化页面开发,改进用户与站点的交互。如果置之不理,它能够显著增加站点响应大小,在连接速度慢的情况下,使您的 响应时间更加缓慢。ASP.NET 2.0 的发布带来了 ViewState 机制的一些改进,这使得 ViewState 使用更简单,又不会防碍站点性能。这些改进包括:减少编码数量,采用控件状态从内容中分离出行为状态,以及智能集成数据绑定控件。
5、URL映射
使用这个特性我们可以不安全的浏览器地址映射成另一个我们设定的地址,避免出现安全问题。
<!--[if !supportLists]-->6、 <!--[endif]-->新增加不少的类,同时很多类被重写,或添加新功能
<!--[if !supportLists]-->1、 <!--[endif]-->串口操作
新增System.IO.Ports命名空间,提供了SerialPort类来实现串口操作的功能。
<!--[if !supportLists]-->2、 <!--[endif]-->压缩解压
新增System.IO.Compression命名空间,用来处理常用的文件压缩或解压。
<!--[if !supportLists]-->3、 <!--[endif]-->范型
新增System.Collections.Generic命名空间,提供范型支持。
4、网络处理功能增强
新增System.Net.NetworkInformation命名空间,包含了一大堆类型,里面有一个Ping类,就是来实现ping命令的功能。
5、使用FTP
在System.Net 中看到增加了FtpWebRequest和FtpWebResponse两个类,这次可以直接使用Ftp了,不需要再使用第三方的组件。
6、使用SmtpClient
在System.Net.Mail命名空间中提供了对邮件操作的支持。
7、使用多媒体
在System.Media命名空间中提供了一些处理声音的类,不过好像没有看到支持视频的,要使用还是要调用Media Player的组件。
<!--[if !supportLists]-->7、 <!--[endif]-->用户界面控制
asp.net2.0母版页面(Master Pages),可以实现统一的布局效果,可以对系统布局进行集中控制。
<!--[if !supportLists]-->二、 <!--[endif]-->开发环境比较
除了启动速度慢、占用系统资源较多这个缺点外,Visual Studio 2005与Visual Studio 2003相比在易用性,功能方面有了很大的提高。
<!--[if !supportLists]-->1、 <!--[endif]-->支持代码重构
<!--[if !supportLists]-->2、 <!--[endif]-->支持单元测试,自动生成单元测试代码
(1)对私有方法的单元进行测试
使用 Visual Studio 对公共方法进行单元测试,跟以前 NUnit 一样,都是引用需要的类,然后对公共方法进行测试。
(2)用户界面自动化测试
想必大家对类的单元测试已经比较熟悉,这里我们来看看它提供的另一项更为有趣的测试——用户界面自动化测试。事实上这个测试的本质仍是单元测试,单元测试的各种方法在用户界面测试中仍然可用。
而这些测试只需在需要进行测试的方法上简单地点击鼠标右键,在右键菜单中选择 “创建单元测试”,系统就自动产生了这个方法的单元测试代码。
3、类设计器
使用 Visual Studio 类设计器可以显现类和其他类型的结构,还可以通过可视化表示方法编辑它们的源代码。对类图的更改将直接反映在代码中,且对代码的更改会直接影响设计器的外观。设计器和代码之间的同步关系,使得可视化创建和配置复杂的 CLR 类型变得容易。
类设计器包含一些专门设计的功能,这些功能将有助于重构代码、方便地重命名标识符以及重载方法。您可以自动生成类和结构,并通过自动生成存根可以实现接口。
最后,类设计器也可作为通信工具使用,您可以使用它与同事共享代码库区域。类图可以打印成硬拷贝或另存为图像,以便在 HTML 页或 PowerPoint 演示文稿中显示。
<!--[if !supportLists]-->3、 <!--[endif]-->更多更好用的服务器控件
在ASP.NET 2.0中微软内置了更多控件,在1.x中需要程序员费尽心思才能完成的功能,在2.0中只需要简单的套用这些控件就能完成。
<!--[if !supportLists]-->4、 <!--[endif]-->开发和调试彻底摆脱了虚拟目录
1.x版本的asp.net必须信赖虚拟目录进行调试和运行,现在asp.net2.0版本自带一个 development web server进行调试,省去了配置虚拟目录的麻烦。
三、Visual Studio 2005 team suite介绍
Visual Studio 2005 Team Suite 是 Visual Studio 2005 Team System 的一个组成部分,可为软件开发核心团队中的每个成员提供最全面的、用于软件设计、开发和测试的工具集。此外,Team Suite 还为具有多方面专业技能的团队成员提供了极大的灵活性,使他们可以在同一个熟悉的 Visual Studio 开发环境中快速适应结构设计师、开发人员和测试人员的工作。Team Suite 还基于microsoft使用了多年的工具为您提供了用于创建世界一流软件的新功能。当将 Team Suite 与microsoft Visual Studio 2005 Team Foundation Server 一起使用时,Team Suite 可以更好地加强团队的沟通和协作,并可为项目的利益相关方提供有关软件开发过程的、前所未有的透明性。
VS2005采用软件开发生命周期,作为企业在选择信息系统发展方法论(System Development Methodology)时的标准流程,其特征是将开发流程区分为几个连续阶段(3个~20个不等),标示着不同的系统发展成果,实作时则配合专门的技术 角色(分析师、架构师、开发人员、测试人员与项目经理等),目的是容易管理、分层负责与确保软件质量。VS2005则在软件开发生命周期中定义出区分架构 师(Architect)、开发人员(Developer)、测试人员(Tester)与项目经理(Project Manager),并将软件依角色区分为3种版本:Team Architect、Team Developer、Team Tester等,项目经理的权责则包含在Excel或Project上,可与Team System整合。
此外,新的HTML设计器将提供:
- 分割界面(Split View)的支持 (同时将HTML源码和所见即所得设计模式打开的能力)
- 无比丰富的CSS支持 (CSS属性窗口,CSS继承图示器,CSS预览,以及CSS管理器)
- 极大改进的视图转换性能 (从源码模式转换成HTML设计模式将会瞬时完成)
- 对源码视图内控件设计器的支持 (属性构造器,事件接通(wire-up)以及向导将会在源码视图内正常工作)
- 更丰富的标尺(ruler)和布局支持 (更棒的是,它们的值将自动储存在外部的CSS文件中)
- 对内嵌母板页的设计器支持
下面是一张示范多个新功能的屏幕截图:

Visual Studio Orcas的2007年1月CTP已经可以下载了,下载地址是
http://www.microsoft.com/downloads/details.aspx?familyid=1ff0b35d-0c4a-40b4-915a-5331e11c39e6&displaylang=en。
奇怪的是,Visual Studio Orcas的这个CTP居然是用RAR格式压缩的,而不是微软自己的CAB。
另外,Internet Explorer Developer Toolbar也发布了 Beta 3版本,下载地址是http://www.microsoft.com/downloads/details.aspx?familyid=E59C3964-672D-4511-BB3E-2D5E1DB91038&displaylang=en
从文件的版本号来看,Visual Studio 2005 SP1看起来并未更新Visual C++相关的merge module,用Visual Studio 2005 SP1编译的C++应用程序或者DLL在没有安装Visual C++ 2005 SP1再发布文件vcredist.exe的计算机上无法加载。解决的一个办法是再发布vcredist.exe(包含在Visual Studio Professional和以上版本中,默认安装在C:Program FilesMicrosoft Visual Studio 8VCredist下)。
随着Office System 2007的发布,微软公司的新一代企业业务平台变得前所未有的强大。Office相关开发也正逐渐变得炙手可热。为了帮助开发者更好地了解并基于Office System 2007进行开发,微软公司将发布一系列有关Office System 2007的参考文档以及相关辅助软件。
微软公司发布了如下三个与Office System 2007相关的软件和参考文档:
[1] 2007 Office System Document: Compliance Features in the 2007 Microsoft Office System
这篇洋洋洒洒的67页的文档全面介绍了Office System 2007的适应性以及扩展性能力。每一个应用了Office System 2007的企业都将会有它自己的个性化、需要定制的需求。这份文档就将告诉我们Office System 2007开发者什么样的需求是能够实现的,应该怎样实现等相关内容。文档份为如下几大部分:
- Introduction
- An Overview of Regulatory Compliance
- The 2007 Microsoft Office System Products
- Compliance Capabilities in the 2007 Microsoft Office System
- Compliance Extensibility Opportunities
- Development Tools for Extending Office and Windows SharePoint Services
- Summary
- Appendix I: Resources
- Appendix II: References
如果你打算定制出一套自己的Office System 2007系统,那么这份文档绝对不容错过。
[2] 2007 Office System Document: Lists of Control IDs
Office System 2007的UI中引入了一个新东西——Ribbon。虽然对于这个Ribbon,使用者仁者见仁,众说纷纭,不过作为开发者,我们还是有必要赶上发展的脚步。Ribbon这个东西相关的开发也设计得独具匠心,具体内容就不详细说了,有兴趣的朋友可以先参考一下这篇MSDN文档:Customizing the Office (2007) Ribbon User Interface for Developers (Part 1 of 3) 。
微软公司发布的这个软件其实是一个自解压的压缩文件,解压后将得到24个Excel文件,其中分别列出了Office System 2007系列软件中使用的内建Ribbon的ID,方便我们开发时参考。
下图就显示了Word中内建的部分Ribbon的ID:
[3] 2007 Office System Sample: Open XML File Format Code Snippets for Visual Studio 2005
不得不承认,随着Office System 2007的发布,Office开发变得更加简化,提供的API也更加丰富。不过由于Office System 2007本身的复杂性,对于初学者来说,掌握Office System 2007开发仍旧不是一件容易的事情。甚至对于一些最常用功能的实现都无所适从。
微软公司发布的这个Visual Studio 2005的Code Snippets集合就提供了一系列关于Office System 2007开发中经常用到的功能的代码片断。关于Visual Studio 2005的Code Snippets,其实就是一系列常用的代码片断,可以看作是一种代码级别的复用。这里不再多谈Code Snippets,如果你还不是很了解这个强大功能,请参考这篇MSDN文章:How to: Manage Code Snippets。
下面就是在Visual Studio 2005中使用该Code Snippets时的界面:
如上图所示,选择了“Excel: Get sheet info”之后,Code Snippets将自动插入如下一大段代码:
public struct SheetInfo
{public string SheetName;
public string SheetType;
public SheetInfo(string SheetName, string SheetType)
{ this.SheetName = SheetName; this.SheetType = SheetType;}
}
public List<SheetInfo> XLGetSheetInfo(string fileName)
{ // Return a generic list containing info about all the sheets. const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
// Fill this collection with a list of all the sheets List<SheetInfo> sheets = new List<SheetInfo>(); using (Package xlPackage = Package.Open(fileName, FileMode.Open, FileAccess.Read)) { // Get the main document part (workbook.xml).foreach (System.IO.Packaging.PackageRelationship relationship in xlPackage.GetRelationshipsByType(documentRelationshipType))
{ // There should only be one document part in the package. Uri documentUri = PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative), relationship.TargetUri);
PackagePart documentPart = xlPackage.GetPart(documentUri);
// Load the contents of the workbook, which is all you // need to retrieve the names and types of the sheets: XmlDocument doc = new XmlDocument();doc.Load(documentPart.GetStream());
// Create a NamespaceManager to handle the default namespace, // and create a prefix for the default namespace: XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable); nsManager.AddNamespace("default", doc.DocumentElement.NamespaceURI); // Loop through all the nodes, retrieving the information // about each sheet:foreach (System.Xml.XmlNode node in doc.SelectNodes("//default:sheets/default:sheet", nsManager))
{string sheetName = string.Empty;
string sheetType = "worksheet";
sheetName = node.Attributes["name"].Value; XmlAttribute typeAttr = node.Attributes["type"];if (typeAttr != null)
{sheetType = typeAttr.Value;
}
sheets.Add(new SheetInfo(sheetName, sheetType));}
// There's only one document part. break;}
}
return sheets;}
我们既可以直接使用这些已经生成好了的功能,也可以通过查看代码了解、学习Office System 2007的常用操作。
微软公司昨天发布了一个Windows Communication Foundation (WCF)和Windows CardSpace的示例程序包,内容极为丰富,从最简单的Hello World到复杂的解决方案一应俱全。对于Windows Communication Foundation (WCF)和Windows CardSpace这两个新东西而言,这些示例程序无疑就是最好的学习资源。
这是部分目录截图:
顺便简单介绍一下这两个东西:
Windows Communication Foundation (WCF)(开发代号:Indigo)是微软公司在.NET 3.0下的SOA框架,它也在微软公司的规划中占有非常重要的位置。无论是在组织内部还是组织之间,应用程序通信都是现代软件的基本功能,.NET Framework 3.0 用WCF以SOA的方式提供了程序之间沟通的渠道。下面是官方网站上的介绍:
The Windows Communication Foundation (previously codenamed "Indigo") is Microsoft's unified framework for building secure, reliable, transacted, and interoperable distributed applications.
关于Windows Communication Foundation (WCF),还有如下资源也不错:
- Windows Communication Foundation官方网站: http://wcf.netfx3.com/
- Bruce Zhang的《WCF之旅》系列
- 这个PPT也不错,适合快速了解一下:http://wcf.netfx3.com/files/folders/6680/download.aspx
Windows CardSpace(开发代号:InfoCard)是微软公司新一代的统一数字身份标识控件,旨在解决现今网络上各种身份认证的复杂性、不安全性等问题。这是官方网站上的介绍:
Windows CardSpace enables users to provide their digital identities in a familiar, secure and easy way. In the physical world we use business cards, credit cards and membership cards. Online with CardSpace we use a variety of virtual cards to identify ourselves, each retrieving data from an identity provider. Don't struggle with usernames and passwords, just choose an information card!
ASP.NET 2.0 引入了一系列可以改善数据访问的新工具,包括几个数据源和数据绑定控件。新增种类的数据源控件可以消除 ASP.NET 1.x 中要求的大量重复性代码。例如,您可以很容易地将 SQL 语句或存储过程与数据源控件相关联,并且将它们绑定到数据绑定控件。更令人感到印象深刻的是,通过 ObjectDataSource 控件可以简化开发和减少代码,并且仍然可以在 n 层体系结构的不同层中抽象业务和数据访问逻辑。
在 .NET 问世以前,用传统的 ASP 生成数据网格通常需要编写大量的代码,以便在遍历 ADO 记录集的同时即时生成 HTML 表。ASP.NET 1.x 通过允许您将基于 XML 的 DataSet 绑定到 ASP.NET DataGrid 控件,从而使该类型的开发变得更加容易。这就减少了生成网格所必需的代码。但是,传统的 ASP 和 ASP.NET 1.x 都要求代码实现分页、排序、编辑和行选择功能。通过 ASP.NET 2.0 中的改进功能,可以显著减少这些代码的数量,以产生带有完整分页、排序和编辑功能并填充了数据的网格。
在这一期的 Data Points 中,我将首先演示通过 ASP.NET 2.0 并使用 SqlDataSource 和一些新的数据绑定控件开发 Web 应用程序是多么容易。请注意,我在此使用的是 Beta 1 版本。
大多数企业应用程序都是在多层体系结构之上生成的,该体系结构有一个用于存放业务逻辑的中间层,以及一个使用一个或多个后端数据库的数据访问层。我将讨论 ObjectDataSource 可以多么理想地与现有的多层组件集成。通过将 ObjectDataSource 控件链接到业务对象,您可以充分利用现有的多层体系结构来生成完善的 Web UI,并且能够显著减少代码。 ObjectDataSource 控件还包含一些特殊的属性,使您可以绑定到 ASP.NET 2.0 和 ADO.NET 2.0 中新近增强的强类型 DataSet 和数据组件。 ASP.NET 2.0 中的其他新功能和改进包括新增的双向绑定表达式、增强的缓存,以及几个新增的可以数据绑定到新的数据源控件的 ASP.NET 2.0 控件。
数据绑定控件
要使用数据源控件,必须具有一个用来将它们绑定到的数据绑定控件。在 ASP.NET 2.0 中有几个新的数据绑定控件,包括 GridView、DetailsView 和 FormView 控件。如果您喜欢 ASP.NET 1.x DataGrid 控件,那么您也会喜欢 ASP.NET 2.0 GridView 控件。GridView 在本质上类似于 DataGrid,因为它可以绑定到新的数据源控件,并且可以用来实现排序、编辑和分页 — 它们需要的代码都比 DataGrid 少得多(有关 GridView 的详细信息,请参阅 Dino Esposito 在 MSDN®Magazine 的 2004 年 8 月刊中发表的文章)。
要将 GridView 绑定到数据源控件,需要将 GridView 的 DataSourceID 属性设置为数据源控件的 ID。还可以设置 GridView 的其他几个属性来增强外观和用户交互(我将在稍后的示例中加以演示):
<asp:GridView ID="gvwOrders" Runat="server"
DataSourceID="sdsOrdersDataSource"
AutoGenerateColumns="True">
其他控件(例如,DropDownList)也可以绑定到数据源控件。例如,DropDownList 控件可以绑定到检索雇员列表的 SqlDataSource 控件。雇员的全名可以显示在 DropDownList 中,而 EmployeeID 可以作为控件的基础数据值字段绑定到该控件。以下示例定义了一个 DropDownList,它将显示可供选择的客户名称的列表。客户数据被绑定到一个名为 sdsCustomerDataSource 的 SqlDataSource 控件,该控件可获得客户的 CompanyName 和 CustomerID 字段的列表:
<asp:DropDownList ID="ddlCustomers" Runat="server" AutoPostBack="True"
DataSourceID="sdsCustomersDataSource"
DataTextField="CompanyName"
DataValueField="CustomerID">
</asp:DropDownList>
在 ASP.NET 2.0 中,将控件绑定到数据源控件非常简单,并且不需要任何处于代码隐藏中的代码。但是,如果您愿意,仍然可以编写代码以显式绑定到控件。实际上,数据绑定控件的数据源和 DataMember 属性与 ASP.NET 1.x 相比已经得到了改进。
数据源控件
在 ASP.NET 2.0 中有几个新的数据源控件,例如,SqlDataSource、ObjectDataSource、XmlDataSource、AccessDataSource 和 SiteMapDataSource(如图 1 所示)。它们全都可以用来从它们各自类型的数据源中检索数据,并且可以绑定到各种数据绑定控件。数据源控件减少了为检索和绑定数据甚至对数据进行排序、分页或编辑而需要编写的自定义代码的数量。
每个数据源控件都具有类似的属性,以便可以与其各自的数据源进行交互。生成 SiteMapDataSource 和 XmlDataSource 是为了检索分层数据,而生成其他数据源控件是为了检索带有列和行的基于集合的数据。
专门生成 AccessDataSource 以便从 Access 数据库中检索数据。SqlDataSource 听起来好像只能使用 SQL Server?,但实际情况不是这样的。它实际上可以用来从任何 OLE DB 或符合 ODBC 的数据源中检索数据。
命令类型和参数
SqlDataSource 控件具有四个命令属性,您可以设置这些属性以告诉 SqlDataSource 如何获得、插入、更新和删除它的数据。可以将 SelectCommand 属性设置为 SQL 语句或存储过程。在任何一种情况下,都可以根据需要传入参数。InsertCommand、UpdateCommand 和 DeleteCommand 属性用于告诉 SqlDataSource 使用哪些 SQL 语句(或存储过程)来修改基础数据库中的数据。图 2 中的代码示例显示了一个 SqlDataSource,它将它的 SelectCommand 和 UpdateCommand 属性设置为参数化的 SQL 语句。请注意,UpdateParameters 使用 Parameter 元素来指示要用于参数的字段的名称和数据类型。在将 GridView 绑定到该 SqlDataSource 以后,这些 UpdateParameters 值就被绑定到受影响行的具有相同名称的列。
您自己对此进行试验的最简单方式是,在 Visual Studio? 2005 中创建一个 Web 窗体,连接到服务器资源管理器窗口中的本地 SQL Server Northwind 数据库,然后将一个表拖到该 Web 窗体。这会自动创建一个 SqlDataSource 控件以及一个 GridView。Visual Studio 会自动将 SqlDataSource 控件的 ProviderName 和 ConnectionString 属性设置为 SQL Server Northwind 数据库。而且,所有四个命令属性都将被设置为适当的 SQL 语句。然后,您为编辑该 Web 窗体而必须完成的所有工作就是,使用智能标记来选中“Enable Editing”复选框(参见图 3)。

图 3 GridView设置
数据源控件还可以使用来自其他控件的参数。例如,数据源控件可以检索给定客户的所有订单。在这种情况下,CustomerID 可以是传递给 SqlDataSource 控件的 SelectCommand 属性的 SQL 语句或存储过程的参数。还可以从其他控件(例如,DropDownList)检索 CustomerID,并将其直接传递到 SqlDataSource 控件的 SQL SelectCommand 中。
您可以将控件的值直接链接到 SqlDataSource 控件的任一 SQL 语句(SelectCommand、InsertCommand、UpdateCommand 或 DeleteCommand)的参数,还可以指定究竟要将控件的哪个属性用于该参数。例如,如果您在上一个示例中不需要 DropDownList 的默认属性,而是需要它的 DataTextField,则可以将 ControlParameter 的 PropertyName 属性设置为 DataTextField。
除了 ControlParameter 以外,还可以将其他参数类型用于数据源控件。如果您要使用新的 ASP.NET 个性化功能,则可以使用 ProfileParameter 从配置文件对象中检索参数的值。接下来,还有几个从标准 Request 对象的集合中检索它们的数据的参数对象类型。例如,CookieParameter 可以用来从 Cookie 中检索参数的值。QueryStringParameter 从任意请求字符串变量中获得它的值,而 FormParameter 从 HTML 窗体的输入字段中获得它的值。最后,SessionParameter 可以用来从会话变量中检索它的值。这些类型的参数为数据源控件提供了多个有关如何设置它们的参数值的选项。
SqlDataSource 示例
既然我已经完成了概述,那么我将对使用 SqlDataSource 和 ObjectDataSource 来检索和修改数据进行一下对比。SqlDataSource 控件(它使用 ADO.NET 2.0 DbProviderFactory 对象)具有将它直接链接到 OLE DB 或 ODBC 数据源的属性。当加载包含链接到 SqlDataSource 的数据绑定控件的 ASP.NET 页时,SqlDataSource 直接与基础数据库进行通信。因而,SqlDataSourceData 源控件不与现有的业务对象集成。
为了查看 SqlDataSource 是如何操作的,让我们先观察一下 Orders_SDS.aspx 页(参见图 4)。有一个 DropDownList 控件,它绑定到一个从 Northwind 数据库中检索客户列表的 SqlDataSource 源控件。

图 4 通过 SqlDataSource 检索客户
还有另外一个名为 sdsOrdersDataSource 的 SqlDataSource,它用于检索选定客户的所有订单。图 5 中的代码(摘自 Orders_SDS.aspx — 它可在下载中得到)显示了两个 SqlDataSource 控件和这个 DropDownList。请注意,sdsOrdersDataSource SqlDataSource 控件使用 DropDownList 的选定值作为其存储过程的参数(prGet_Orders 的参数)。
ProviderName 和 ConnectionString 属性的组合告诉 SqlDataSource 控件从哪个数据存储中获得数据。尽管这些属性使 SqlDataSource 成为检索和修改数据的简单解决方案,但遗憾的是,它们在表示层的 ASPX 文件中公开了数据库连接字符串以及 SQL 语句或存储过程。这通常不是一个好主意。将该数据以加密形式存储在配置储存库(如配置文件或注册表)中要安全得多。
图 4 显示了编辑模式下的 Orders_SDS.aspx 页。分页由 GridView 自动实现(通过将 GridView AllowPaging 属性设置为 true,并将 PageSize 属性设置为期望的大小,如 10)。这将告诉网格将其中的行分页,并且在“下一页”或“上一页”链接被单击时自动重新加载网格和页。GridView 使用 TextBox 控件显示选定行的可编辑列。数据绑定列是通过 asp:BoundField 或 TemplateField 元素定义的。通过设置 DataField 属性,可以将 BoundField 绑定到 GridView 的关联数据源:
<asp:BoundField HeaderText="ShipCity" DataField="ShipCity"
SortExpression="ShipCity"></asp:BoundField>
这将告诉 GridView 控件,当它处于查看模式时,应该在 span 元素中显示 ShipCity 值。当 GridView 处于编辑模式时,选定行中的这一列将在适当的 HTML 元素中显示。在这种情况下,HTML 元素为 TextBox,因为它是一个字符串值。该元素是基于绑定列的数据类型选择的。例如,如果该列在 SQL Server 中被定义为位,则将使用 CheckBox 控件在编辑模式下显示该列。
TemplateField 元素在绑定列的行为方式方面提供了更大的灵活性。请观察以下摘自 Orders_SDS.aspx 页的代码示例:
<asp:TemplateField SortExpression="OrderDate" HeaderText="OrderDate">
<ItemTemplate>
<asp:Label ID="lblOrderDate_Item" Runat="server"
Text='<%# Bind("OrderDate", "{0:d}") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtOrderDate_Edit" Runat="server"
Text='<%# Bind("OrderDate", "{0:d}") %>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
当 GridView 处于查看模式时,它使用 TemplateColumn 在 Label 控件中显示 OrderDate 列;当 GridView 处于编辑模式时,它使用 TemplateColumn 在 TextBox 控件中显示 OrderDate 列。您还可以使用 FooterTemplate 来告诉 Template 列在页脚中以不同的方式显示该列。还可以使用 HeaderTemplate、AlternatingItemTemplate 甚至 InsertItemTemplate。还请注意 ASP.NET 2.0 中引入的简化的绑定语法。OrderDate 的值是通过调用 Bind 表达式并向它传递 GridView 的关联数据源中列的名称和一个可选的数据格式字符串表达式来设置的。在该示例中,我使用了表示短日期的数据格式字符串。这些属性都可以通过可借助于 Visual Studio 2005 中的新增智能标记功能访问的属性来轻松设置(参见图 6)。

图 6模板列属性
ObjectDataSource
GridView 和其他数据绑定控件的最出色的功能之一是,在设置了它们以后,只需更改单个属性,就可以将它们绑定到 ObjectDataSource 控件或 SqlDataSource 控件。例如,您必须完成的所有工作就是创建一个新的 ObjectDataSource 控件,并将 GridView 的 DataSourceID 属性更改为这个新的 ObjectDataSource 控件的 ID。
与 SqlDataSource 不同的是,ObjectDataSource 控件使您可以从 ASPX 页和表示层中抽象出特定于数据库的设置,并将它们移至多层体系结构中的较低层(参见图 7)。例如,SqlDataSource 控件的 ConnectionString、ProviderName 和 SelectCommand 属性在 ObjectDataSource 控件中不存在。相反,它们被替换为告诉 ObjectDataSource 控件实例化哪个业务类以及使用哪个方法来检索或修改数据的其他属性。

图 7 层
要设置 ObjectDataSource 控件以访问另一个层的业务类及其方法,必须首先将 ObjectDataSource 控件的 TypeName 属性设置为该业务类的名称(如 TypeName="MSDN2005Jan_BLL.Orders")。然后,将 SelectMethod 属性设置为该业务类中将用来检索数据源数据的方法的名称。该业务类的方法必须返回一个可枚举的列表,例如,集合、数组、DataSet 或 DataReader。为了让该方案能够工作,ObjectDataSource 必须能够执行指定的方法。如果它是静态方法,则不需要完成任何特殊的工作。如果该方法是实例方法,则 ObjectDataSource 必须能够创建该类的实例。要达到该目的,最简单的方法是将该业务类编写为包含默认的构造函数。另外,还可以处理 ObjectDataSource 的 ObjectCreating 事件,它使您可以用所需的任何构造函数来实例化该对象,然后将该对象实例传递给数据源控件。
图 8 中的代码示例(摘自同样包含在下载中的 Orders.aspx)显示了两个 ObjectDataSource 控件(它们替换了上一个示例中使用的两个 SqlDataSouce 控件)。odsOrdersDataSource 使用 MSDN2005Jan_BLL.Orders 类和它的 GetData 方法来检索它的订单列表。在该示例中,Orders 类中的 GetData 方法只是创建名为 OrdersDataSet 的强类型 DataSet 的实例及其相关的名为 OrdersTableAdapter 的适配器。然后,它调用 Fill 方法并返回强类型的 DataSet:
public OrdersDataSet GetData(string CustomerID)
{
OrdersDataSet oDs = new OrdersDataSet();
OrdersTableAdapter oDa = new OrdersTableAdapter();
oDa.Fill(oDs, CustomerID);
return oDs;
}
请注意,GetData 方法还接受由 ObjectDataSource 控件的 SelectParameter 属性传入的 CustomerID 参数。UpdateData 方法的参数也是从图 8中所示的 UpdateParameters 属性所指示的 ObjectDataSource 传入的。以下为 Orders 类的 UpdateData 方法的签名:
public void UpdateData(int OrderID, DateTime OrderDate,
string ShipCity, string ShipCountry)
UpdateData 方法的参数的名称和数据类型必须与 ObjectDataSource 控件中更新参数的名称和数据类型相匹配。数据源控件不能使用批处理更新,因此不能一次性地将多个行传递给更新方法。相反,必须将每个值作为单个参数传递给更新方法。除了 SelectMethod 和 UpdateMethod 属性以外,ObjectDataSource 控件还具有 DeleteMethod 和 InsertMethod 属性。
增强的强类型DataSet
上一个示例演示了如何将 GridView 绑定到 ObjectDataSource 控件以链接到业务层的类,因此您可以通过该类的方法来检索和更新数据。如果您具有现有的业务层逻辑和多层体系结构,则该示例可以很好地工作。它还可以调用 Web 服务客户端代理的方法,或其他任何遵循类和方法要求的引用类的方法。
我故意将上个示例的一个方面延迟到现在才加以讨论,那就是强类型 DataSet。使用 Visual Studio 2005 中的向导,您还可以直接在类型化的 DataSet 类中定义方法,以便选择、插入、更新和删除数据。因而,您可以避免直接在业务层或数据访问层中编写任何 ADO.NET 代码,而是使用向导直接将 ADO.NET 逻辑添加到类型化的 DataSet 中。
您不必检索类型化的 DataSet,但是在这种情况下它是有价值的 — 这要归功于它的一些新的增强功能。类型化的 DataSet 创建了一个默认的 Fill 方法,该方法被追加到类型化 DataSet 的定义中的 TableAdapter 类。可以将这一可选的 TableAdapter 类设置为存储连接字符串以及存储过程或 SQL 语句,以便在数据库中选择、更新、插入和删除记录。

图 9 Orders DataSet
类型化的 DataSet 还允许您创建自定义的方法,以便检索和修改数据。在 Orders DataSet(如图 9 所示)中,我基于 prGet_Orders 存储过程创建了一个类型化的 DataSet。然后,通过数据组件查询配置向导,我向 OrdersTableAdapter 中添加了两个自定义方法:GetData 和 UpdateData。这些方法是在与类型化 DataSet 的 XSD 相关联的类文件内部定义的;在该示例中,我的文件名为 OrdersDataSet.Designer.cs。如果您想了解详细信息,可以打开这个自动生成的文件(但是您不应当修改它,因为如果该文件被重新生成,则您的更改将被改写)并查看自定义的 GetData 和 Update 方法以及为类型化 DataSet 创建的所有标准代码。如果您运行示例页 Orders2.aspx,则它会直接绑定到上述自定义方法。这可以显著减少您为中间层手动编写的代码数量。
其他数据源控件细节
现在我们已经完成了讨论,如果您知道数据源控件还可以通过一系列属性来公开缓存功能,则可能会很感兴趣。通过将 EnableCaching 设置为 true 并将 CacheDuration 设置为很多秒,数据将在缓存中存储相应的时间。还可以将 CacheExpirationPolicy 属性设置为 Absolute 或 Sliding。Absolute 是默认值,它告诉缓存在加载后立即开始倒计时直至过期。Sliding 策略告诉缓存在缓存数据每次被访问时重置过期倒计时。在您要加载的数据不是非常容易改变的情况下,缓存技术可以帮助优化应用程序。例如,在加载省、市甚至产品类别的 DropDownList 的数据源控件中使用缓存是有好处的,因为这些数据不会频繁更改。
ObjectDataSource 控件包装了挂钩到业务对象以调用业务方法的代码。它还与数据绑定控件(例如,GridView)协同工作,以执行分页、排序以及在 ASP.NET 1.x 中必须手动编码的数据更改。
小结
ASP.NET 2.0 中的改进(尤其是在数据源和数据绑定控件领域中的改进)显著减少了产生带有完整分页、排序和编辑功能并填充了数据的网格所需的代码数量。尽管数据源控件消除了过去必须手动编写的大量代码,但您仍然可以编写代码以便与数据源控件进行交互。您不仅可以只通过指指点点来创建数据驱动的 Web 页,而且还可以编写代码来使用数据源控件的事件,例如,Selected、Selecting、Updated 或 Updating 事件。
简介
在 Microsoft ASP.NET 2.0 Framework 中,数据库访问得到了极大的简化。利用全新的 SqlDataSource 控件,您无需编写一行代码就可以选择、更新、插入和删除数据库数据。
生成简单的应用程序时,SqlDataSource 控件是一个很好的选择。如果您需要迅速生成一个使用户可以显示和编辑数据库记录的 Web 页,使用 SqlDataSource 控件在几分钟之内就能完成此工作。
例如,我自己就曾计时生成了这么一个页面。通过结合使用 SqlDataSource 控件与 GridView 控件,我在 1 分 15秒 内就能生成一个用于显示 Northwind Products 数据库表的内容的页面。就有这么快!
但是,SqlDataSource 控件存在一个问题。如果您使用 SqlDataSource 控件,那您就是在做不太妙的事情。SqlDataSource 控件的缺点在于它迫使您将用户界面层与业务逻辑层混合在一起。任何应用程序架构师都会告诉您:混合多个层的行为是不可取的。
生成严格意义上的多层 Web 应用程序时,您应该具有清晰的用户界面层、业务逻辑层和数据访问层。仅仅由于 SqlDataSource 控件的强制而在用户界面层引用 SQL 语句或存储过程是完全错误的。
那么为什么您要关心这些东西呢?不错,在很多情况下,您不必在意。如果您正在创建一个简单的 Web 应用程序,完全可以使用 SqlDataSource 控件。例如,如果您需要生成一个由单独页面组成的应用程序来显示数据库的表的内容,那么将应用程序划分为多个应用程序层就很不明智。
遗憾的是(如果您已经为此“交过学费”,则会感到幸运),并非所有的 Web 应用程序都很简单。应用程序达到一定的复杂程度之后,如果将其划分为多个应用程序层,则生成和维护它们就更轻松。
将应用程序划分为多个应用程序层有很多优点。如果您有一个清晰的业务逻辑层,就能够创建一个可以从多个页面调用的方法库。换句话说,创建一个清晰的业务逻辑层提升了代码重用。此外,创建清晰而独立的应用程序层使得应用程序更易于修改。例如,清晰的层次使您无需修改数据访问代码就可以修改用户界面。
如果您需要使用 ASP.NET Framework 生成多层 Web 应用程序,那么您可以使用 ASP.NET 2.0 Framework 所引入的另一个新控件:ObjectDataSource 控件ObjectDataSource 控件使您可将诸如 GridView 和 DropDownList 这样的用户界面控件绑定到一个中间层组件。
这篇文章的主题就是 ObjectDataSource 控件。在这篇文章中,您将学习如何使用此控件来显示和编辑数据库数据。我们还将讨论如何结合使用 ObjectDataSource 控件和 SqlDataSource 控件以简化数据库访问。
使用 ObjectDataSource 控件显示数据
我们在这里设想您需要创建一个用于显示 Products 数据库表的内容的 Web 页面。再进一步设想您的某个现有业务组件包含了一种用于检索此数据的方法。
例如,清单 1 中的组件包含了一个名为 GetProducts 的方法,此方法返回一个 DataReader 来表示 Products 数据库表的内容。
清单 1: ProductInfo.cs (C#)
using System;
using System.Data;
using System.Data.SqlClient;
public class ProductInfo
{
const string conString =
"Server=localhost;Trusted_Connection=true;Database=Northwind";
public static SqlDataReader GetProducts()
{
SqlConnection con = new SqlConnection(conString);
string selectString = "SELECT * FROM Products";
SqlCommand cmd = new SqlCommand(selectString, con);
con.Open();
SqlDataReader dtr =
cmd.ExecuteReader(CommandBehavior.CloseConnection);
return dtr;
}
}
清单 1: ProductInfo.vb (Visual Basic .NET)
Imports System.Data
Imports System.Data.SqlClient
Public Class ProductInfo
Const conString As String = _
"Server=localhost;Trusted_Connection=true;Database=Northwind"
Public Function GetProducts() As SqlDataReader
Dim con As New SqlConnection(conString)
Dim selectString As String = "SELECT * FROM Products"
Dim cmd As New SqlCommand(selectString, con)
con.Open()
Dim dtr As SqlDataReader = _
cmd.ExecuteReader(CommandBehavior.CloseConnection)
Return dtr
End Function
End Class
如果您将清单 1 中包含的这个类添加到应用程序的 Code 目录中,那么 ASP.NET Framework 将自动编译这个类。换句话说,只要向 Code 目录添加了这个类,就可以立即在 ASP.NET 页中使用它。
我们将使用 GridView 控件(在 ASP.NET 2.0 Framework 中替换了 DataGrid 控件)来显示由 GetProducts 方法返回的数据库记录。清单 2 中的 ASP.NET 页包含了一个绑定到 ObjectDataSource 控件的 GridView。
清单 2: ShowProducts.aspx
<html>
<head>
<title>Show Products</title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView
ID="GridView1"
DataSourceID="ObjectDataSource1"
Runat="Server" />
<asp:ObjectDataSource
ID="ObjectDataSource1"
TypeName="ProductInfo"
SelectMethod="GetProducts"
Runat="Server" />
</form>
</body>
</html>
清单 2 中声明的 ObjectDataSource 控件包含两个重要的属性。TypeName 属性指示类名,而 SelectMethod 属性指示在选择数据时要在此类上调用的方法名。
在清单 2 中,ObjectDataSource 控件用于调用 ProductInfo 类上的 GetProducts 方法。由于 GridView 控件绑定到了 ObjectDataSource 控件上,因此通过 GridView 控件的 DataSourceID 属性,GridView 控件即可显示产品列表(请参见图 1)。

图 1. 使用 ObjectDataSource 控件显示产品
您可以结合使用 ObjectDataSource 控件与任何标准的 ASP.NET 数据绑定控件(例如,GridView、DropDownList、TreeView 和 Repeater 控件)。ObjectDataSource 控件使您能够将任何标准控件绑定到组件。
SelectMethod 可以引用静态方法(在 Visual Basic .NET 中共享)或实例方法。如果您使用的是实例方法,则 ObjectDataSource 控件在调用这个方法前,会自动创建此组件的一个实例。在完成方法调用后,将自动销毁此组件。
结合使用参数与 ObjectDataSource 控件
您可以将参数与使用 ObjectDataSource 控件调用的方法一起使用。当您调用某方法时,如果需要将某些值(例如,控件属性或查询字符串的值)传递给此方法,则这种方式就非常有用。
在前一节中,我们使用 ObjectDataSource 控件创建了一个页面,用于显示来自 Products 数据库表的所有记录。在本节中,我们将修改此页面,以便允许用户从 DropDownList 控件(请参见图 2)选择产品类别。

图 2. 从 DropDownList 选择产品类别
清单 3 包含了修改后的 ProductInfo 组件。
清单 3: ProductInfo2.cs (C#)
using System;
using System.Data;
using System.Data.SqlClient;
public class ProductInfo2
{
const string conString =
"Server=localhost;Trusted_Connection=true;Database=Northwind";
public SqlDataReader GetProducts(string category)
{
SqlConnection con = new SqlConnection(conString);
string selectString = "SELECT Products.* " +
"FROM Products INNER JOIN Categories " +
"ON Products.CategoryID=Categories.CategoryId " +
"WHERE CategoryName=@CategoryName";
SqlCommand cmd = new SqlCommand(selectString, con);
cmd.Parameters.AddWithValue("@CategoryName", category);
con.Open();
SqlDataReader dtr =
cmd.ExecuteReader(CommandBehavior.CloseConnection);
return dtr;
}
}
清单 3: ProductInfo2.vb (Visual Basic .NET)
Imports System.Data
Imports System.Data.SqlClient
Public Class ProductInfo2
Const conString As String = _
"Server=localhost;Trusted_Connection=true;Database=Northwind"
Public Function GetProducts(ByVal category As String) _
As SqlDataReader
Dim con As New SqlConnection(conString)
Dim selectString As String = "SELECT Products.* " &
"FROM Products INNER JOIN Categories " & _
"ON Products.CategoryID=Categories.CategoryId " & _
"WHERE CategoryName=@CategoryName"
Dim cmd As New SqlCommand(selectString, con)
cmd.Parameters.AddWithValue("@CategoryName", category)
con.Open()
Dim dtr As SqlDataReader = _
cmd.ExecuteReader(CommandBehavior.CloseConnection)
Return dtr
End Function
End Class
清单 3 中经过修改的 ProductInfo 组件包含了一个经过修改的 GetProducts 方法,此方法包含了一个用于类别名的参数。这个参数用于限制从数据库返回的产品。
清单 4 包含了 DropDownList、GridView 和ObjectDataSource 控件,使您可以选择要显示的不同类别的产品。
清单 4: ShowProducts2.aspx
<html>
<head>
<title>Show Products</title>
</head>
<body>
<form id="form1" runat="server">
<asp:DropDownList
id="DropCategories"
AutoPostBack="true"
Runat="Server">
<asp:ListItem Value="Beverages" />
<asp:ListItem Value="Seafood" />
</asp:DropDownList>
<br /><br />
<asp:GridView
ID="GridView1"
DataSourceID="ObjectDataSource1"
Runat="Server" />
<asp:ObjectDataSource
ID="ObjectDataSource1"
TypeName="ProductInfo2"
SelectMethod="GetProducts"
Runat="Server">
<SelectParameters>
<asp:ControlParameter
Name="category"
ControlID="DropCategories" />
</SelectParameters>
</asp:ObjectDataSource>
</form>
</body>
</html>
从清单 4 的 DropDownList 控件选择新类别时,GridView 控件将自动地只显示来自选定类别的产品。
请注意,清单 4 中的 ObjectDataSource 控件包含了一个 SelectParameters 元素。这个元素列出了调用由 ObjectDataSource 控件的 SelectMethod 属性指定的方法时使用的所有参数。在本例中,SelectedParameters 元素包含了一个名为 category 的单个参数。这个参数表示来自 DropCategoriesDropDownList 控件的 SelectedValue 属性的值。
使用 ObjectDataSource 控件编辑数据
ObjectDataSource 控件包含 4 个重要属性:SelectMethod 属性、UpdateMethod 属性、InsertMethod 属性和 DeleteMethod 属性。综合利用这些属性,您能够指定执行标准数据库操作所需的所有方法。
例如,您可以使用 ObjectDataSource 控件来编辑数据库数据。在清单 5 中,修改后的 ProductInfo 类包含了一个新的 UpdateProduct 和 DeleteProduct 方法。
清单 5: ProductInfo3.cs (C#)
using System;
using System.Data;
using System.Data.SqlClient;
public class ProductInfo3
{
const string conString =
"Server=localhost;Trusted_Connection=true;Database=Northwind";
public static SqlDataReader GetProducts()
{
SqlConnection con = new SqlConnection(conString);
string selectString = "SELECT ProductId,ProductName, " +
"UnitPrice FROM Products ORDER BY ProductId";
SqlCommand cmd = new SqlCommand(selectString, con);
con.Open();
SqlDataReader dtr =
cmd.ExecuteReader(CommandBehavior.CloseConnection);
return dtr;
}
public static void UpdateProduct(int original_productId,
string productName, decimal unitPrice)
{
SqlConnection con = new SqlConnection(conString);
string updateString = "UPDATE Products SET " +
"ProductName=@ProductName,UnitPrice=@UnitPrice " +
"WHERE ProductID=@ProductID";
SqlCommand cmd = new SqlCommand(updateString, con);
cmd.Parameters.AddWithValue("@ProductName", productName);
cmd.Parameters.AddWithValue("@UnitPrice", unitPrice);
cmd.Parameters.AddWithValue("@ProductId", original_productId);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
public static void DeleteProduct(int original_productId)
{
SqlConnection con = new SqlConnection(conString);
string deleteString = "DELETE Products " +
"WHERE ProductID=@ProductID";
SqlCommand cmd = new SqlCommand(deleteString, con);
cmd.Parameters.AddWithValue("@ProductId", original_productId);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
清单 5: ProductInfo3.vb (Visual Basic .NET)
Imports System.Data
Imports System.Data.SqlClient
Public Class ProductInfo3
Const conString As String = _
"Server=localhost;Trusted_Connection=true;Database=Northwind"
Public Shared Function GetProducts() As SqlDataReader
Dim con As New SqlConnection(conString)
Dim selectString As String = "SELECT ProductId, " & _
"ProductName,UnitPrice FROM Products ORDER BY ProductId"
Dim cmd As New SqlCommand(selectString, con)
con.Open()
Dim dtr As SqlDataReader = _
cmd.ExecuteReader(CommandBehavior.CloseConnection)
Return dtr
End Function
Public Shared Sub UpdateProduct(ByVal original_productId _
As Integer, ByVal productName As String, _
ByVal unitPrice As Decimal)
Dim con As New SqlConnection(conString)
Dim updateString As String = "UPDATE Products " & _
"SET ProductName=@ProductName,UnitPrice=@UnitPrice " & _
"WHERE ProductID=@ProductID"
Dim cmd As New SqlCommand(updateString, con)
cmd.Parameters.AddWithValue("@ProductName", productName)
cmd.Parameters.AddWithValue("@UnitPrice", unitPrice)
cmd.Parameters.AddWithValue("@ProductId", original_productId)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Sub
Public Shared Sub DeleteProduct(ByVal original_productId _
As Integer)
Dim con As New SqlConnection(conString)
Dim deleteString As String = "DELETE Products " & _
"WHERE ProductID=@ProductID"
Dim cmd As New SqlCommand(deleteString, con)
cmd.Parameters.AddWithValue("@ProductId", original_productId)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Sub
End Class
您可以将这个修改过的 ProductInfo 类与清单 6 中包含的ObjectDataSource 控件一起使用,以编辑 Products 数据库表的内容。
清单 6: ShowProducts3.aspx
<html>
<head>
<title>Show Products</title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView
ID="GridView1"
DataSourceID="ObjectDataSource1"
DataKeyNames="ProductId"
AutoGenerateColumns="false"
AutoGenerateEditButton="true"
AutoGenerateDeleteButton="true"
Runat="Server">
<Columns>
<asp:BoundField
DataField="ProductName"/>
<asp:BoundField
DataField="UnitPrice"
DataFormatString="{0:c}"/>
</Columns>
</asp:GridView>
<asp:ObjectDataSource
ID="ObjectDataSource1"
TypeName="ProductInfo3"
SelectMethod="GetProducts"
UpdateMethod="UpdateProduct"
DeleteMethod="DeleteProduct"
Runat="Server">
<UpdateParameters>
<asp:Parameter
Name="original_productId"
Type="Int32" />
<asp:Parameter
Name="productName" />
<asp:Parameter
Name="unitPrice"
Type="Decimal"/>
</UpdateParameters>
</asp:ObjectDataSource>
</form>
</body>
</html>
在清单 6 中,GridView 控件显示了ProductName 和 UnitPrice 这两个列的值。由于 GridView 控件的 AutoGenerateEditButton 和 AutoGenerateDeleteButton 属性均设置为值 True,GridView 将自动生成用于编辑和删除产品行的用户界面(请参见图 3)。

图 3. 使用 ObjectDataSource 控件编辑数据
当您单击 Update 链接更新产品时,ObjectDataSource 控件将调用 UpdateProduct 方法。请注意,ObjectDataSource 控件在其 UpdateParameters 元素中列出了传递给 UpdateProduct 方法的参数。
有一个参数需要额外进行讨论。我们需要将被更新的行的 ProductID 列的值传递给 UpdateProduct 方法由于没有在 GridView 中显示 ProductID 列,我们必须将 ProductID 列分配给 GridView 控件的 DataKeyNames 属性。这个列的名称变为 original_productId,而不是 productId,因为我们正在向 update 方法传递 ProductID 列的未编辑版本。
如果您单击 Delete 链接,ObjectDataSource 控件将调用 DeleteProduct 方法。由于 GridView 控件的 DataKeyNames 属性具有值 ProductId,因此会再次将一个名为 original_productId 的参数自动传递给 DeleteProduct 方法。
结合使用 ObjectDataSource 控件和 SqlDataSource 控件
到目前为止,我们已经将 ObjectDataSource 控件与使用 SqlDataReader 对象的组件一起使用,以便检索数据库数据。这里还有另一种选择。即不在组件内使用 SqlDataReader 或 DataSet 等 ADO.NET 对象,而是在组件中使用 SqlDataSource 控件。
您可以在组件中使用 SqlDataSource 控件的这一事实似乎很奇怪。通常,您不在组件中使用控件,因为控件一般具有可视化表示形式,而且控件参与页面执行生命周期。而 DataSource 控件在这一点上有些特殊。
如果您希望简化组件中的数据库访问代码,您可以在此组件中使用 SqlDataSource 控件。清单 7 展示了这种方式。
清单 7: ProductInfo4.cs (C#)
using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
public class ProductInfo4
{
const string conString =
"Server=localhost;Trusted_Connection=true;Database=Northwind";
public static IEnumerable GetProducts()
{
string selectString = "SELECT * FROM Products";
SqlDataSource dsrc = new SqlDataSource(conString,
selectString);
dsrc.DataSourceMode = SqlDataSourceMode.DataSet;
return dsrc.Select(DataSourceSelectArguments.Empty);
}
}
清单 7: ProductInfo4.vb (Visual Basic .NET)
Imports System.Collections
Imports System.Web.UI
Imports System.Web.UI.WebControls
Public Class ProductInfo4
Const conString As String = _
"Server=localhost;Trusted_Connection=true;Database=Northwind"
Public Shared Function GetProducts() As IEnumerable
Dim selectString As String = "SELECT * FROM Products"
Dim dsrc As New SqlDataSource(conString, selectString)
dsrc.DataSourceMode = SqlDataSourceMode.DataSet
Return dsrc.Select(DataSourceSelectArguments.Empty)
End Function
End Class
在清单 7 中,我们实例化了 SqlDataSource 控件的一个新实例。SqlDataSource 的构造函数接受了一个用于数据库连接字符串的参数和一个用于与 select 命令一起使用的命令文本的参数。接着,将 DataSourceMode 属性的值设为 DataSet(这里的另一个选项是 DataReader)。最后,在 SqlDataSource 控件的实例上调用 Select 方法,并返回表示来自 Products 数据库表的所有记录的 DataView。
您可以将清单 7 中的 ProductInfo 类与清单 8 中包含的 ObjectDataSource 控件一起使用:
清单 8: ShowProducts4.aspx
<html>
<head>
<title>Show Products</title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView
ID="GridView1"
DataSourceID="ObjectDataSource1"
Runat="Server" />
<asp:ObjectDataSource
ID="ObjectDataSource1"
TypeName="ProductInfo4"
SelectMethod="GetProducts"
Runat="Server" />
</form>
</body>
</html>
在清单 8 中,GridView 控件绑定到了 ObjectDataSource 控件上。而 ObjectDataSource 控件又调用了 ProductInfo4 类的 GetProducts 方法,以检索由 GridView 显示的数据。最后,GetProducts 方法使用 SqlDataSource 控件检索数据库数据。
小结
ASP.NET 2.0 Framework 极大地简化了数据库访问,使您可以更轻松地生成简单和复杂的 ASP.NET 应用程序。如果您需要生成一个简单的数据库驱动 Web 应用程序,那么您可以使用新的 SqlDataSource 控件。如果您需要生成一个更为复杂的应用程序或示例,您可以在传统的 3 层应用程序中使用 ObjectDataSource 控件。
ObjectDataSource 控件使您能够继续在数据驱动页面中使用中间层组件。其主要优势在于使您无需编写任何代码即可绑定到一个组件,从而极大简化了您的用户界面。使用 ObjectDataSource 控件,我可以在 3 分钟 20 秒的时间内生成一个可以显示 Product 数据库表的组件和页面。尽管这种方式花的时间比使用 SqlDataSource 控件长,但我感觉这样做时页面的体系结构要好得多。
先看一个现象:
如果你有这样的一个WebService 方法:
public void myTest(System.Collections.Specialized.NameValueCollection col)
{
.....
}
那你在请求这个WebService 方法的时候,会收到如下异常:
To be XML serializable, types which inherit from ICollection must have an implementation of Add(System.String) at all levels of their inheritance hierarchy. System.Collections.Specialized.NameValueCollection does not implement Add(System.String).
详细的错误发生点如下:
[InvalidOperationException: To be XML serializable, types which inherit from ICollection must have an implementation of Add(System.String) at all levels of their inheritance hierarchy.
System.Collections.Specialized.NameValueCollection does not implement Add(System.String).]
System.Xml.Serialization.TypeScope.GetDefaultIndexer(Type type, String memberInfo) +849
System.Xml.Serialization.TypeScope.ImportTypeDesc(Type type, MemberInfo memberInfo, Boolean directReference) +857
System.Xml.Serialization.TypeScope.GetTypeDesc(Type type, MemberInfo source, Boolean directReference, Boolean throwOnError) +135
System.Xml.Serialization.XmlReflectionImporter.ImportMemberMapping(XmlReflec tionMember xmlReflectionMember, String ns, XmlReflectionMember[] xmlReflectionMembers, Boolean rpc, Boolean openModel) +78
System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(XmlRefle ctionMember[] xmlReflectionMembers, String ns, Boolean hasWrapperElement, Boolean rpc, Boolean openModel) +280
这是因为对 ICollection 接口的类进行序列化的一些特殊要求:
XmlSerializer 可以以不同方式处理实现 IEnumerable 或 ICollection 的类,条件是 这些类满足某些要求,如下所示。
1、实现 IEnumerable 的类必须实现带单个参数的公共 Add 方法。Add 方法的参数必须与 从 GetEnumerator 方法返回的 IEnumerator.Current 属性所返回的类型一致(多态) 。
2、除实现 IEnumerable 外还实现 ICollection 的类(如 CollectionBase)必须有一个 值为整数的公共 Item 索引属性(在 C# 中为索引器),并且必须有一个整数类型的公 共 Count 属性。传递给 Add 方法的参数必须与从 Item 属性返回的类型相同或与该类 型的某个基的类型相同。
3、对于实现 ICollection 的类,要序列化的值将从索引的 Item 属性检索,而不是通过 调用 GetEnumerator 来检索。另外,除返回另一个集合类(实现 ICollection 的集合 类)的公共字段之外,将不序列化其他公共字段和属性。
ICollection 接口的类要可以被序列化,该类必须包含 Add 方法和要序列化的 Item 属性(C# 索引器)。
上面的WebService 例子出现异常是因为:
NameValueCollection 并不直接实现 ICollection 接口。相反,NameValueCollection 扩展 NameObjectCollectionBase。这样,就会实现 ICollection 接口,并且在 NameValueCollection 类中不实现重载 Add(system.string) 方法。
在使用 XMLSerializer 时,XmlSerializer 尝试将 NameValueCollection 序列化或反序列化 为一般 ICollection。因此,它查找默认的 Add(System.String)。如果没有 Add(system.String) 方法,就会发生异常。
参考资料:
PRB:使用 XmlSerializer 序列化 NameValueCollection 对象时出 现“System.InvalidOperationException”错误
http://support.microsoft.com/default.aspx/kb/814187/zh-cn?spid=548&sid=304
序列化实现 ICollection 接口的类
http://msdn2.microsoft.com/zh-cn/library/58a18dwa.aspx
http://www.codecomments.com/archive321-2006-2-823224.html
http://www.experts-exchange.com/Programming/Programming_Languages/C_Sharp/Q_ 21585935.html
AJAXWorld杂志主编 Dion Hinchcliffe 不久前发表了《你需要知道的有关AJAX的七件事情(Seven Things You Need to Know About AJAX)》一文。大意如下,
1。浏览器并不适合AJAX。第一个认真的AJAX项目才开始一周,你会发现Ajax 几乎已把浏览器推向其极限。事实是,没有强有力的第三方开发工具,清晰地设计任何规模的 Javascript 软件都需要训练有素和艰苦努力才成。在多个浏览器里调试Ajax应用麻烦透顶,想要做些认真的后台或多线程更需要你使出浑身解数,特别是你想结合那些用了数目有限的计时器的其他的组件。好消息是,简单的AJAX,(譬如点缀些DHTML),比大规模的AJAX要轻松得多了。但做好准备,一旦你的应用规模加倍,随时扩大开发和测试的努力。
2。你不需要你想象中的那么多 Web 服务。我原以为走Ajax这条路需要开发许多新的Web 服务来提供数据和存储。事实上,我发现许许多多项目满足于HTML scraping或使用老式的HTTP POST。这使得尝试 Ajax 开发容易之极,可以重用任何现有的后端HTTP服务,而不是转向SOAP或REST/WOA等复杂的服务。虽然这大概会导致糟糕的架构级的选择,但这也使逐步转化到Ajax 毫不费力,简直自然之极,虽然因此造成的以后的头痛大概是难以避免的。
3。Ajax比传统Web设计和开发更棘手。HTML用户界面规范的丢失,几乎无限制的隐藏功能的可能性,编程手法创建页面元素,以及Ajax 方式的其他固有的特性把我们所知的Web设计和开发方式都扔出门外去了。 Web 设计师必须深刻理解DOM,Javascript和CSS的能力,对浏览器如何显示图像,如何布局,以及显示各种元素要有深刻理解。开发人员发现测试既困难又枯燥。虽然工具在不断地,全面地改进,但要让整个工业积累出行之有效的最佳实践,模式和实用知识,要花几年时间呢。在此要高度赞扬一下象雅虎的Bill Scott这样的业界人士,赞赏他们通过推动类似雅虎UI设计模式库这样的东西,尝试解决这里提到的许多问题,极大地推进了业界的最高工艺水平。结论是,Ajax开发,起码是目前,与传统的Web开发相比要花更多的时间,同时要求更高的技能。
4。Ajax 工具和组件仍在涌现,现今还没有明显的领先者。虽然Dojo火爆出场,但竞争远未结束。譬如,Dojo框架本身的版本还是0.3 (注:Dojo 0.4已发行)。紧随其后的种种工具,框架和组件库还有很多。虽然OpenAjax 旨在使得众多产品相互合作,大多数的开发人员只会掌握这其中的2-3个,然后就一直用这几个产品了。在目前的情形下,过早定死在某个特定的产品,一般来说不是个好主意。创新,竞争,和市场的领先地位此起彼伏,尚无定数。同时,一定要去看一下script.aculo.us,Prototype,Google Web Toolkit,Yahoo! UI Library, JackBe,Zapatec,Bindows, Nexaweb,General Interface,Backbase,ActiveWidgets,以及 微软的Atlas。
5。优秀的Ajax 程序员很是难找。Zimbra的Scott Dietzen最近感慨找到好的Ajax人才之难。但参考上述第3点,建造复杂的Ajax 应用要求的计算机技能要远比Web设计技能多得多。我发现有经验的程序员不太喜欢Javascript编程和调试。这种情形不会持久,但也要过几年才行。
6。必须积极地对付浏览器模型对Ajax的限制。虽然最后的结果会非常值得 ,但象任何技术, Ajax远非完美,它也有几个弱点。一个是它会违反现有的Web模型,譬如,加书签,后退按钮等等。幸运的是, 象Brad Neuberg这样的有识之士对此类问题已有方案,只要你愿意花力气,理解恢复此类功能的重要性。Ajax 也缺乏桌面软件的的很多强处,譬如能离线运行,访问本地硬盘存储等,但Flash 的本地存储和即将发行的Apollo平台能应付这类问题。
7。Ajax 只是成功RIA策略的一个因素。如果你想让你的在线应用实现范围很广的功能,那么你必须将类似Flex,OpenLaszlo, 以及WPF/E等这样的RIA平台放在考虑范围之内,特别是在想支持象音像这样丰富的媒体的情形下,而Ajax对此几乎无能为力。Ajax 会日益对这些平台造成威胁,特别是在后端服务器提供对服务器端push,Web 服务,企业环境等支持的情形下。
I'd classify the Microsoft Ajax Library as having:
- Moderate DOM Traversal, only basic get by ID - no apparent DOM creation methods.
- Acceptable DOM Events.
- Good Ajax Support.
- No Animation Support.(注:其实ASP.NET AJAX有动画支持)
....Even with just the better DOM support the library would already be ahead of Prototype in directly useful functionality....
Brad Abrams还指出了几个有意思的地方,
- 基本的 XmlHttp 抽象和 JavaScript 语言扩展大家都做得差不多了,有区别也不是很大。真正的竞争将在UI widgets层次上展开,有意思的是,这些UI widgets 是不大容易从一个框架移植到另一个框架的,在接下来的6个月至1年内,框架的与众不同之处将渐渐展现出来。
- 有人指出“Better is Simpler”,应该是指AJAX的易用性,surface area小,而且更加直观。
- 在客户端和服务器端之间的平衡。AJAX 模型把焦点从一个项目UI模型转移到更着重于应用层次服务的集成。ASP.NET 和Atlas的结合是绝配。
- 性能随应用场景而变,没有绝对的答案,应该测量的是用户对性能的感觉(user perception of performance),而不是raw throughput。
- 在用户点击提交按钮前把数据传回服务器,不纯是一个技术性的问题,而是用户的感知模型的问题,因为用户根据以往体验的理解是,在点击提交前,数据是不应该记录的。
说到在SharePoint Server中整合其他应用系统,其实是一个挺复杂的问题,需要考量多方面的问题,并在各种选项中做出最佳的选择。在这里,将SharePoint Server在整合这方面的方法比较系统的描述一下,希望对大家有帮助。这里面说的SharePoint Server是泛指,并不针对特定的SharePoint Portal Server 2003或Office SharePoint Server 2007。
看到这里,可能会有朋友问了,整合应用系统?这不是BizTalk Server应该干的活吗?是的,EAI(企业应用集成)正是BizTalk Server的强项。但是首先,BizTalk Server更擅长的在应用层对各个应用和系统进行整合,也就是说,BizTalk Server和各个系统打交道的方式大多数是通过这些系统的各种API,而在很多场合我们除了在应用层需要对各个系统进行整合之外,我们还希望在界面上对各个应用也能有整合,也即展现层的整合,展现层的整合能够让用户在一个统一的界面上访问和操作多个应用系统,看到各个系统中的信息。对于展现层的整合,我们同样需要有一个基于Web的平台来干这个,而这就是SharePoint Server的强项了。
其次,很多时候我们可能不一定需要BizTalk Server这样的“重型武器”,在文章的后面我们会看到,只有在某些复杂的场合,更确切的说,是客户已经有了较多的应用,而且各个应用间的确有互联、整合、集成的需求,才有BizTalk Server的用武之地。
一般,我们将SharePoint Server的应用整合方式分为下面的四种(下面的图片摘自PPT,所以非常抱歉比较大):
第一种:基于Web界面的整合
这种方式简单来说,就是直接把其他系统的Web界面直接拿过来,放到SharePoint Server的页面上去,让用户可以在SharePoint这一个界面里面能够访问到其他系统。
这种方式是几种整合方式中最简单的一种,但是简单并不意味着不实用,有的时候,基于Web界面的整合可能就是最好,也是最省事的方法。使用这个方法有一个先决条件,就是要整合的应用必须有Web展现,否则就无从谈起了,幸好现在是一个Web大行其道的年代,几乎大部分企业应用系统都是通过Web方式展现给客户的。
SharePoint Portal Server 2003中已经提供了两个现成的Web Part,来帮助我们完成基于Web界面的整合。第一个是网页查看器Web Part,给它一个URL,它能把指定的页面以IFrame的方式直接嵌到SharePoint页面中。另外一个是网页截取器Web Part,它能让我们指定一个网页中的一个部分,然后它会自动把这个部分截取下来,显示在SharePoint页面中,而且我们还能指定一个更新周期,这个Web Part会隔一段时间就检测指定的网页是否发生的变化,然后更新要显示的网页部分块。
当然,除了使用SharePoint自带的Web Part之外,我们还可以用自己的方式,来进行这种进行Web界面的整合。只要你的方法基本原理是将另外一个应用系统的Web界面弄到SharePoint里面,那么就应该属于这第一种方法。
使用基于Web界面的整合可能遇到的一大挑战就是单点登录(SSO),因为要整合的那个Web应用很可能是需要登录后才能访问的,而用户显然不希望在SharePoint里面查看另外一个应用系统的信息时,还需要再登录一次,所以我们需要帮助用户来自动完成这个登录过程。
第二种:基于数据源的整合
由于某种原因,比如要整合的系统根本就没有Web展现,或者SSO不好做,难以整合,同时用户也只需要能够在SharePoint里面看到那个系统里面的数据而已,并不需要做什么交互操作(比如,客户只需要看到上个月的销售数据报表,或者客户信息表),而且我们也可以直接访问到要整合的系统的数据库,那么用这第二种方法也许是一个不错的主意。
基于数据源的整合,就是直接去连接要整合系统的数据库,然后利用某些Web Part将一个表、或者多个表的数据直接展现出来。SharePoint提供了现成了Web Part,允许我们使用ODBC方式去连接任何数据库,然后把数据展现在SharePoint页面上。当然,自己做一个定制的展现数据库数据的Web Part也并不是一件难事。
这种方法的一个重要好处是,你根本不需要考虑那个应用系统是怎么做的、如何做的、接口是什么,只要你能访问到它的数据库,就能搞定。
基于数据源的整合有一个重要的前提条件,就是你知道要整合的系统数据库在哪、如何访问,以及了解它的数据库结构(数据字典),就是说,你要清楚的知道,应该将哪个Database的哪个Table的哪些Field的数据展现出来,才是客户想看到的数据。
第三种:点对点的整合
点对点的整合是指,让开发人员开发出定制的Web Part,在Web Part的代码里面,访问要整合的系统的特定的API(可能是各种类型的,比如Web Service,或者对象模型),以在Web Part里面来完成某件任务。由于可能需要针对每一个应用系统,甚至应用系统中的每一项功能,来开发出一个对应的Web Part,所以这种方法被成为点对点的方法。
点对点整合可以带来最大的灵活性和最大的功能性,因为只要其他的应用系统带有相应的接口,我们就可以在Web Part里面完成任意的功能:从其他应用系统中获取数据、与其他应用系统进行交互操作,等等。
但这种方法也有自己的前提。首先,要整合的应用系统必须有相应的接口,如果面对一个根本就没有考虑过被第三方访问,根本没有设计任何API的应用,那就没法子了(这种类型的应用系统并不少见!)。其次,如果有API,Web Part开发人员还需要了解这些API,知道怎么调用,调用哪个才是自己需要的,有很多应用系统是非常复杂的,提供了庞大繁杂的API,如果不熟悉这些应用系统的接口,学习成本还是不小的。
点对点整合的一个典型例子就是专门访问SAP系统的SAP iView Web Part Toolkit,另外,对于如何将SAP整合到SharePoint里面,这个网站是非常有价值的:www.microsoft-sap.com/interop.aspx。
第四种:应用集成方式的整合
终于,在面对最复杂的场景,我们要用上BizTalk Server这样的EAI服务器了。如果我们需要整合多个系统,比如在一个Web Part里面能够操作多个系统按照某个流程完成某项任务,那么使用这种整合方式应该是最合适的了。
在这种方式里面,我们需要有一台专门的应用集成与整合服务器,通过它与各个应用系统打交道,在它上面完成业务流程的编制和创建,然后通过在Web Part中调用这个应用集成与整合服务器的接口,来完成整合功能。
OK,现在,我就将最常见的四种整合方式介绍完了,最后,我想让大家了解一下Office SharePoint Server 2007中提供的一个新的,用于进行应用整合的组件:Business Data Catalog。

