Workflow Foundation的问题确实很多,差点把我邮箱爆了,我无法解决所有问题,也无法一一回复。其实网上还有很多资料可以去查找,你可以到http://wf.netfx3.com/学习下载Sample,也可以下载最新的WIndows Vista SDK(内含.netfx3.0 SDK),看本《Essential Windows Workflow Foundation》,或者到 Architecture Journal 去下载06年7期“工作流主题”的杂志,最后有问题解决不了一定要到http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=122&SiteID=1这个Workflow官方论坛或者 SharePoint-Workflow http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=1207&SiteID=1 去问,会得到wf相关开发者的回答的。下面从那论坛摘几个比较常见的问题:
- 复杂的审批问题:比较简单的审批问题就是让一个人专门进行审批,如果他批准则通过,拒绝则结束。但是现实中都是复杂的流程,但再复杂的流程也都可以拆分成简单的流程,所以,当很多人都想知道Workflow Foundation是否可以满足他们的工作流场景时,我都会说99%都可以。呵呵,当然具体实施碰到的风险因素按具体项目具体分析了。言归正传,复杂的审批流程一般可以归纳成下面3类:(假设给5个人同时分配一项审批任务)
- 领导一票制:5个人中的那个大老板批准或否决了,则该审批任务不管其他人如何,均按领导意思继续下面流程。
- 全票制:当且仅当5个人都批准或都否决,该审批才会结束并继续下面流程。
- 票数权衡制:5个人中3个人批准则当作批准,或者3个人否则则当否决处理继续下面流程。可以理解为超过50%,或者根据人员角色按一定的权重去处理后,按最终既定标准权重处理流程。
- 实现方法可以参考:
- State-Machine Workflow中的Parallel并行问题:
- Load Balanced负载均衡下的Workflow:
- Workflow 的版本问题:
- 从web.config中获取WorkflowRuntime实例:http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1200209&SiteID=1
- Tracking:http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1188418&SiteID=1
97年在BBS上文豪挥笔,98年Mud边武侠风云,99年OICQ里风花雪月,看着html大普及,asp搅动动态网站……一晃10年过去了。盖茨把他的口号从“A PC on every desk and in every home”进化成“Empower people through great software any time, any place, and on any device”,似乎也预示网络时代的到来。如今,单就web应用这块来说,技术层面的flash、ajax、wpf/e曾出不穷,概念层面的blog, wiki, tag, podcast, videocast等日新月异,呵呵,看得眼花缭乱。不过,在这么一个发展的历程里,也总是能找到几条发展方向,我简称之为三化。
- 用户体验个性化(体验):对于普通用户来说,他只care体验,包括UI和Function。
- 技术体系标准化(标准):对于平台商来说,他们应该会更care标准,许多专利都出自并握在他们手里。
- 应用领域普及化(随时随地任何设备上享受任何服务):对于应用服务供应商,他们应该care互连互通,这可是他们吸引最大群体用户,创造最大利润的根源。
每个方向上都会因为各种利益而出现各种技术或理念,反过来各种技术和理念也基本都在这三个方向里进行验证决定其生死。
6、ECM Starter Kits 虽然是 for Beta2TR,但完全可以正常跑在正式版里,当然前提是对里面的个别打不开或跑不起来的项目进行一点修改。
- CustomSignatures项目:把相关的 CorrelationToken 由 SignatureWorkflow 改为 SignaturesWorkflow。出现这种现象也不知道该说微软什么了,估计是赶时间推出这个 Sample。
- ModificationSample项目:跑到 Workflow1.cs 代码里,找到 updateTask1 代码段,把相关 updateTask1.AssignedTo 等等都在中间加个 TaskProperties 属性,变成 updateTask1.TaskProperties.AssignedTo 这类的。
- 其他如果还有问题,可以具体看,要么注释,要么做修改,不影响整体代码可读性,大部分也都在正式版里运行正常。
7、我有这么一个场景,我一进去编辑 Task Form 时,该 Task Form 前面列出这条记录的Title等基本字段值,然后下面有“同意”或“下一步”的按钮,还有“拒绝”或“取消”的按钮。我点“同意”或“下一步”不要立马提交,而是转到显示另外一个Form让我填同意后需要处理的一些表单数据。如果我按“拒绝”或“取消”也转到显示另一个Form让我填不同意时要录入的另外一些信息。
这个应用只要你用过InfoPath的视图,就立刻知道怎么实施了。InfoPath的一个表单是允许多个视图的,所以你大可以把包含“同意”和“拒绝”的两个按钮的 Form 当作第一个默认视图,同时再增加一个同意后的视图和一个拒绝后的视图,然后制定这两个按钮的规则(Action里有switch view的这项),点同意就显示同意的视图,点不同意就显示不同意的视图,同时把同意或拒绝的状态值赋值给数据源中某个字段,这样就完全达到了上面的效果。
扩展下思路:你可以用radiobutton排出一队的选项,因为 radiobutton 绑定着一个字段,所以可以判断当用户选定哪个项时来决定我要显示哪个视图。比如,我有“全部公开”、“部分公开”和“不予公开”三个项,我选“全部公开”然后按下一步,就可以跑到全部公开的视图里填写一份政府公文,输入xxxx年xx号和备注后,按提交就完成这个步骤了;以此类推。
额外提下InfoPath,我们知道 InfoPath Form 不用编码本身就可以有一定规则流程的,这些动作包括常用的对输入数据的校验、根据某种条件进行某种动作、执行一些Action等。所以,你可以直接在表单里设置诸如必填字段、进行自动计算、动态增加节点数据、根据输入数据动态调整表单表现或设置数据源字段、根据一定规则执行一定操作等等,而大部分这些操作在发布到 MOSS 中进行 Web 显示时,还是可以正常使用的,使得数据收集这块变得异常方便快捷。
8、MOSS的Workflow历史记录在哪里?
你可以通过右键菜单中的Workflow菜单进去查看该条记录的工作流情况,有工作流的已经运行过的步骤产生的Task链接,也有每步的动作列表。如果想看所有Workflow的历史列表,可以访问 http://服务器/Lists/Workflow%20History 查看,不过估计那些数据不是人能看懂的。但至少可以保证,工作流从头到尾所有的业务数据和流程数据都是存在的,都可以提供给你去查到你所要的历史痕迹的。
如果你还熟悉Workflow Foundation的 TrackingService,你用了其Sample的 WorkflowMonitor 打算来跟踪查看 MOSS 的 Workflow 时,sorry,结果是无法运行,无法跟踪,无法查看。Why?没错,WorkflowMonitor可以利用Workflow Foundation的TrackingService跟踪监控Workflow,但是 MOSS 的 Workflow 却没有使用 Workflow Foundation 默认的 TrackingService(这个实在让人费解,不知出于什么目的),所以如果你要Monitor,那可以考虑为 MOSS 写一个 WPF Application 的 Workflow Monitor,相信这个 idea 应该还是不错的:-) 那MOSS怎么做历史跟踪,打开Reflector看看 Microsoft.SharePoint.WorkflowActions.dll里的相关类,也许就清楚了。
9、差不多了,这个 InfoPath + Workflow + MOSS 的主题就到此为止,这个主题仅仅是当作辅助参考。最后看了choral 的《如何配置Windows SharePoint Services 3.0的搜索》的文章的后面评论中,有人评论说 MOSS 不值得关注,而我则反过来想告诉大家一句话:请重视或正视MOSS!微软平台上的企业应用开发商/开发人员都必须重视这个产品,而微软的对手们也必须正视这个产品。也许答案在这张图里。

5、接上贴补充下一些内容。
- 如何看InfoPath表单是否发布成功:打开SharePoint 3.0管理中心,在应用程序管理有 InfoPath Form Services 一节,进入“Manage Form Template”就可以看到你所有发布的表单。其中看状态 Status 栏,如果为 Ready,则表示该表单已经准备好可以使用了;如果为 Installing,那就是有可能因为前面罗列的各种原因造成表单模板还无法正常发布,这时候你就要检查了。另外,你可以通过URL访问已经发布的表单,地址为类似 http://服务器/_layouts/formserver.aspx?XsnLocation=urn:schemas-microsoft-com:office:infopath:ReviewTaskForm:-myXSD-2005-11-22T23-52-35,后面 XsnLocation=跟上表单的 ID(URN)即可。
- 前面提过,在MOSS中,每个Workflow都是作为一个Feature存在,然后具体使用时再关联到某个List/Library中然后创建Workflow实例运行的。在一个Workflow生命周期里,业务数据自然主要就是List/Library中的记录数据SPListItem/SPFile,再辅之任务列表数据;而Workflow过程中需要的一些流程状态数据则被WF提供的服务持久化(术语好像叫“钝化”之类的)起来,供Workflow被启用时再度激活,从而顺利继续工作流的运作。
- 关于 Task。一开始很多要问为什么(是/要) Task?因为在 MOSS 2007 的 Workflow 中,对于业务流程中人的部分,即工作流中人为参与的部分主要是通过“任务 Task”形式实现的。即要某人来审批或添加些数据时,就在Task列表中创建分配一个 Task 给他,然后这个人过来编辑 Task,完成人为数据的录入采集,使得工作流继续运行。
- 上贴有提到如果不小心用VSTA打开产生后部C#/VB.NET代码后,发布时变成了需要经过管理员审核才能使用。为什么会这样?这类表单和其他表单还有什么区别吗?答案就在《Office Forms Server 简介》。
- SharePoint Desginer 2007 的工作流设计不支持 InfoPath 表单形式吗?是的,很遗憾,SPD2007只支持 ASPX Form形式的 Task Form。所以如果要在 MOSS 2007 里开发 InfoPath + Workflow,还得用前面说过的方法。当然,前面的方法也支持 ASPX Form形式,详细可看 ECM Starter Kits中很经典的 ASPX Form 范例 —— CollectFeedback 示例。
- 为什么 Workflow.xml 中的 AssociationUrl="_layouts/CstWrkflIP.aspx" 和 InstantiationUrl="_layouts/IniWrkflIP.aspx" 不能换成其他页面?这些页面可以理解为 InfoPath Form 的 Host Page(实际是这些页面内部嵌入了显示InfoPath Form的WebPart),InfoPath Form Services处理 InfoPath Form后通过这些 xxxIP.aspx 的页面把 InfoPath Form表单以 Web Page形式呈现出来。所以,不能改变成其它页面,否则无法正常显示 InfoPath Form。
- 不太明白 ItemMetadata.xml 作用,或者说把SPListItem数据传给InfoPath Form并和InfoPath控件绑定显示出来的过程是怎样的?这个一开始确实比较费解。首先根据 SDK 操作一遍后,此时 ItemMetadata.xml 已经作为辅助数据源和资源文件保存在 InfoPath Form里了。记得,此时最好把 ItemMetadata.xml 理解为 InfoPath Form 的“数据源”!然后传递过程是这样的:
- 把准备传递给 Task InfoPath Form 的 SPListItem 字段值取出来赋值为 SPWorkflowTaskProperties.ExtendedProperties["表单字段名"]。
- 任务表单接受这些值,然后组织成一份 xml ,也就是你看到的 ItemMetadata.xml:<z:row xmlns:z="#RowsetSchema" ... />。
- InfoPath Form接收这份 xml 数据,因为InfoPath Form中的控件已经绑定过相应的辅助数据源 ItemMetadata.xml 的 ows_字段名,所以可以顺利的从含有数据的 ItemMetadata.xml 数据源中抽取值显示在表单里。
6、先这样吧。总体感觉似乎人们最多问题的居然是 InfoPath!InfoPath、InfoPath还是InfoPath。其实InfoPath并不难,严格说起来个人觉得和Excel差不多(当然要玩深下去,那可深不见底,但常用功能都很简单的),可能是因为不常用原因吧,可惜了这个产品。给几个 InfoPath 站点给大伙看看:
在MOSS 2007种利用InfoPath 2007结合Workflow Foundation可以高效的做出非常强大的工作流应用。因为在SDK中这部分的内容有点不流畅,读起来比较费劲。所以我想以我的一点小经验和大家Share下,希望能少走点弯路,然后再结合 SDK 、ECM Starter Kits 和 WSS Workflow StarterKits 快速掌握这个非常棒的功能。
1、我要创建用于 MOSS 的 Workflow 项目。
请下载 WSS Workflow StarterKits,安装后将有个"SharePoint Server"的组,内有 SharePoint Sequential Workflow Library 和 SharePoint State Machine Workflow Library 两个项目模板。利用这两个模板创建的项目,对 Workflow 的开发、部署都很方便。
- 项目用到的 Microsoft.Office.Workflow.Tasks.dll、Microsoft.SharePoint.dll 和 Microsoft.SharePoint.WorkflowActions.dll 均在装有MOSS 2007的机器的 C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI\ 目录下。其中开发时主要注意记得在VS2005工具箱里注册 microsoft.sharepoint.WorkflowActions.dll,就可以从工具箱里拖拉出 MOSS 特有的 Workflow 控件了。
- Feature.xml:在 MOSS 中, Workflow 是作为 MOSS 的 Feature 存在的,具体使用时再关联到具体某个 List 或 Library 中并创建实例运作的。因为 Feature.xml 文件就是安装部署时候要把生成的项目 dll 文件作为 Feature 注册到 MOSS 中的描述文件了。刚打开时是空的,只是一些提示,按提示插入 Feature 的 Snippets,就有一段 xml 代码插入。其中 GUID 可通过 VS2005 菜单 Tools 下的 Create GUID 创建一个新的 GUID 填入;中间有个 <ElementManifest Location="workflow.xml" /> 节点用于关联工作流 xml 描述文件。
- Workflow.xml:工作流描述文件。其中有工作流名字Name(该名字在添加 Workflow 关联具体列表或文档库时显示在工作流列表中);GUID(同样通过 Create GUID 生成填入);CodeBesideClass和CodeBesideAssembly对应工作流类全名和程序集全称(项目如进行签名,此处需明确PublickToken,同时把 install.bat 中 gacutil 部分反注释掉);TaskListContentTypeId为工作流使用到的任务列表的 ContentType ID,默认为 Workflow Tasks 的 ContentTypeID,一般不需要修改;AssociationUrl、InstantiationUrl和ModificationUrl一般也不用改,默认创建即是用于呈现 InfoPath 的页面,其中 AssociationUrl 为用来关联 Workflow 和列表或文档库,并设置工作流运行参数的页面;InstantiationUrl为用于当手动启用工作流时呈现给用户的初始化页面。Association_FormURN 和 Instantiation_FormURN 等以 _FormURN 结尾的节点都存放其相应的 InfoPath Form 的 ID(该 ID 可通过设计 InfoPath Form时,打开“文件->属性”窗口即可看到该 InfoPath Form 的 ID)。关于 TaskForm 下面解释。
- install.bat:用于安装部署Workflow的批处理文件。根据具体情况注释或反注释命令行,同时配置MOSS地址即可。
- Workflow1.cs:工作流设计和代码。
2、我的 InfoPath 表单模版无法正常发布,或者发布后状态为“Installing”而不是“Ready”。
请检查以下几个环节,一般无法正常发布都有可能是以下原因造成。
- 首先检查表单模版是否与浏览器兼容。设计表单模版状态下,打开 InfoPath 菜单“工具-->检查设计方案”,然后再在右边任务窗格中点“更改兼容性设置”弹出表单选项,把“浏览器兼容性”组里的“设计一个可在浏览器或 InfoPath 中打开的表单模版”勾起来,然后进行检查。
- 如果表单发布用于 Web Access,可同样打开“表单选项”,在“安全和信任”中把“安全级别”调整为“域”级别。
- 确认所有的表单最好都不曾发布过。判断依据,把.xsn表单模版文件拷贝到其他地方,打开右键“设计”打开它,如果出现警告错误框提示“此表单已经发布到一个位置,但后来被保存或移动到了另外一个位置。如果确保基于此模板的表单正常工作,请重新发布表单”,那就说明该表单已经发布过,否则则没发布过。没发布过的表单模板,每次保存表单模板时均提示是“发布”还是“保存”,一概“保存”。
- 如果该 InfoPath 表单有后部 C#或VB.NET代码,即不小心用 VSTA 打开过,那么发布时会要求必须经过管理员审核,也会造成无法正常发布表单。可在“表单选项”窗口中“编程”里,点击“删除代码”即可。
- InfoPath 2007是中文版本,但发布到英文版本的 MOSS 中时也会出现发布异常。同样在“表单选项”窗口中“浏览器”里,选择表单语言为“英语(美国)”即可。
3、我在 MOSS 列表中设置 Workflow 为新增一条记录 A 时就自动启动,同时给审批者创建一条任务,该任务用了我自己定义的任务 InfoPath 表单,但该 InfoPath 任务表单中有几个字段是要读取记录A中字段值来显示的。
这个问题的实质就是要把某条具体 ListItem 中的字段值传递给 Task 表单(该表单为 InfoPath 表单),然后再通过Task表单显示出来。这里头有三个子问题:怎样获取和当前Workflow相关的 ListItem、通过怎样方式把值传递给 Task表单、Task 表单最后又怎么呈现。
- 怎样获取和当前Workflow相关的ListItem:通过SPWorkflowActivationProperties.Item来获取当前 SPListItem。
- 通过怎样方式传递给 Task 表单。请查看《How to:Access Workflow Task form Data》。例如 taskProperties.ExtendedProperties["ApplyNo"] = this.ApplyNo;。
- Task表单最后怎么呈现。察看《Creating the WOrkflow Task Edit Form》的第4、5、6点。主要是要选择绑定 ows_ 字段时,默认是没有 ows_ 字段的“主”数据源,你必须选择“ItemMetadata (辅助)”数据源才能看到ows_字段。
具体范例可以查看 ECMStarterKits中 HelloWorld 经典示例。结合上面注意的几点。
4、我现在已经在 Workflow.xml 里配置了一个 Task Form了(有类似这么一个节点<Task0_FormURN>urn:schemas-microsoft-com:office:infopath:ReviewTaskForm:-myXSD-2005-11-22T23-52-35</Task0_FormURN>),这个 Task Form是我第一个 Task 用到的,但我还有第二步,第三步,每个步骤都会建一个任务,我的每个任务都要对应不同的 Task Form 来收集每个阶段的用户录入的数据来运作工作流的。怎么加第二个任务表单?
根据 SDK 《Windows Task Form〉,无疑,增加第二个Task Form的第一步就是在把设计好的第2步用到的 InfoPath 表单模板的 ID(URN) 配置起来。即在<Task0_FormURN>节点下增加类似这么一个节点:<Task1_FormURN>urn:schemas-microsoft-com:office:infopath:MultiStage-Initiation:-myXSD-2006-04-28T22-44-03</Task1_FormURN>。
真正核心的问题来了,怎么让第2个任务表单<Task1_FormURN>和实际工作流中分配的第2条任务关联起来?好,关键就在 SPWorkflowTaskProperties.TaskType 这个属性。TaskType = 0 时就表示这是第一个任务请用第一个任务表单,TaskType=1时就表示这是第二个任务请用第二个任务表单。就是这么简单。:)
你可以打开 ECM StarterKits中的 MultiStage 示例,这个示例是比较实用的例子,务必研读。打开示例中的 WorkflowTask.cs,找个GetTaskCreationProperties()方法。修改如下:
public SPWorkflowTaskProperties GetTaskCreationProperties(int taskType)
{
SPWorkflowTaskProperties properties = new SPWorkflowTaskProperties();
properties.AssignedTo = this.Participants[0].AccountId;
properties.Title = this.TaskTitle;
properties.Description = this.TaskInstructions;
properties.SendEmailNotification = true;
properties.TaskType = taskType;
properties.DueDate = (DateTime)this.dueDate;
return properties;
}
然后再打开 Workflow1.cs 代码,搜索到这么一行代码 activity.TaskCreationProperties = this.activeTask.GetTaskCreationProperties(); 改为:
activity.TaskCreationProperties = this.activeTask.GetTaskCreationProperties(this.completedStages);
至此,这个 MultiStage 例子就更智能化了。你在增加工作流步骤外,还可以方便控制每个步骤任务用到的 InfoPath 表单了,而不是都用同一个表单。
5、先到这里吧。最后推荐几篇经典文章:
阅读前,可以先参考 MediaElement 的一译文。实现该例子一定要安装 WPF/E和SDK。
1、新建一个WPF/E Javascript Application。

2、修改 plugin.xaml,增加 MediaElement 元素(红色粗体部分)
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="javascript:root_Loaded">
<Canvas x:Name="button">
<Rectangle Stroke="#FF8E8E8E" StrokeThickness="2" RadiusX="2" RadiusY="2" Height="23" Width="75">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0.5,2.109" EndPoint="0.5,-1.109">
<GradientStop x:Name="gradientStop1" Color="#FFFF9E00" Offset="1"/>
<GradientStop x:Name="gradientStop2" Color="#FFEAEAEA" Offset="0.218"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock Canvas.Top="3" Canvas.Left="13" FontSize="12" Foreground="#FF5A5A5A" Text="Click Me" />
</Canvas>
<Canvas x:Name="video">
<MediaElement x:Name="mediaElement" Canvas.Top="0" Canvas.Left="0" Height="400" Width="400" />
</Canvas>
</Canvas>
3、增加一个新的.aspx页面,命名为WebForm1.aspx。把default.html里源html代码复制粘贴到WebForm1.aspx里(只保留第一行Page指令)。完成后WebForm1.aspx为:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WPFEJSApplication1.WebForm1" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Untitled Page</title>
<script type="text/javascript" src="js/aghost.js"></script>
<script type="text/javascript" src="js/eventhandlers.js"></script>
</head>
<body>
<form>
<div id="wpfeControl1Host" >
<script type="text/javascript">
new agHost("wpfeControl1Host", // hostElementID (HTML element to put WPF/E control into)
"wpfeControl1", // ID of the WPF/E ActiveX control we create
"400", // Width
"400", // Height
"white", // Background color
null, // SourceElement (name of script tag containing xaml)
"plugin.xaml", // Source file
"false", // IsWindowless
"30", // MaxFrameRate
null // OnError handler
);
</script>
</div>
</form>
</body>
</html>
4、在WebForm1.aspx的<head>里增加播放媒体的脚本:
<script>
function playMedia()
{
var wpfeControl = document.getElementById("wpfeControl1");
var mediaElement = wpfeControl.findName("mediaElement");
mediaElement.source = '<%=Request["src"]%>';
mediaElement.width = 400;
mediaElement.height = 400;
mediaElement.play();
}
</script>
5、打开js目录里的eventhandlers.js,在handleMouseUp方法最后增加开始播放的脚本:
function handleMouseUp(sender, eventArgs) {
var gradientStop1 = sender.findName("gradientStop1");
var gradientStop2 = sender.findName("gradientStop2");
gradientStop1.offset = 1;
gradientStop2.offset = .403;
alert("Clicked");
playMedia();
}
6、设置WebForm1.aspx为起始页,按F5调试运行。在打开的IE中重新输入url为http://你的Web服务器/WebForm1.aspx?src=http://localhost/test.wmv 。后面跟的 src= 参数为你所要播放的媒体文件的地址。至此,效果图如下。你按Click Me后,弹出"Clicked"对话框,按确定后开始播放媒体文件。

你可以在网页中嵌入上述代码(或用iframe)页面,并指定媒体文件地址实现页面嵌入播放指定媒体的功能。当然,你还可以扩展使之像一个web mediaplayer或一个web电影院。
在前面发表的一篇〈GridView中显示数据库里的图片〉里提到ASP.NET 2.0里提供的几个Starter Kits fot VS2005,于是有人MSN问,几个Starter Kits应用程序均以“.VSI”扩展名的文件提供,这是个什么样的扩展名?为什么我们可以直接安装,并可以把Starter Kits应用程序项目直接嵌入VS2005中的新建项目模版里?
确实是个有趣的问题。VSI,如果我没理解错的话,应该是Visual Studio Installer的缩写。那么,.VSI文件到底如何实现在VS2005里嵌入项目模版的呢?这个要从VS2005提供的“Export Template”说起了。Export Template项在File菜单里。我们动手从一个例子看起吧。
1、新建一个ASP.NET Web Site。并编写你打算作为日后模版项目里固有功能的代码,也可以放置任何文件夹和文件,比如图片等。这个Web Site在后面将成为VS2005里的一个项目模版,类似Starter Kits里的那几个示例。下面是演示项目的一张图片,供一会与利用该模版新建的项目对比,看是否完全一致。

2、保存项目。然后在File菜单中选择“Export Template”,弹出如下对话框。我们选择第一项“Project template”。最下面的模版类型选择“Visual C#”,表示创建的是C#的ASP.NET Web Site模版。当然你可以依照你喜好选择VB.NET。

3、选择下一步Next。进一步设置模版图标、模版名称、说明等。这些基本属性信息将作在VS2005里显示给用户看。

4、按“Finish”结束导出过程。同时如果你选择“自动嵌入Vs2005”,按Finish后,你在新建WebSite项目的窗口里,就可以看到你刚才所创建的项目模版,如下图。如果你选择最下面的“Display an explorer......”还会自动帮你打开输出目录。在选择利用这个WebSite1项目模版创建的项目,将自动包含第一张图里所列的所有文件夹和文件和所有代码等,即完全是第一张图项目的克隆版本。

至此,完成了Starter Kits里最终一样的效果。但是.VSI的疑问还是没有解开。别急,其实我们已经快解开这个VSI疑团了。现在,进一步再看刚才我们导出的项目模版文件WebSite1.zip,默认在C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\My Exported Templates目录下。我们发现刚才导出的文件居然是个.ZIP的压缩文件,于是很自然想到解压缩看下里面有些什么东西。解压缩后发现除了原本项目里所有的文件夹和文件外,还多了一个模版图标__TemplateIcon.ico和一个名为MyTemplate.vstemplate的文件。利用记事本打开MyTemplate.vstemplate,里面内容为一份描述这个项目模版信息的XML数据文档。(文档内容略)。
正是这份XML文档让我有了一个想法,即利用UltraEdit打开StarterKits里的TimeTracker.VSI文件察看内部结构,发现果然是个ZIP压缩包文件。于是将StarterKits里的TimeTracker.vsi改名为TimeTracker.ZIP,顺利对TimeTracker.ZIP进行解压缩。TimerTracker压缩包里除了一个跟我们上面制作过程一样格式的ZIP文件外,还包含了一个TimeTracker.vscontent的文件。再用记事本打开这个vscontent文件,真相大白:
<?xml version="1.0" encoding="utf-8" ?>
<VSContent xmlns="http://schemas.microsoft.com/developer/vscontent/2005">
<Content>
<FileName>TimeTrackerCS.zip</FileName>
<DisplayName>Time Tracker Starter Kit (C#)</DisplayName>
<Description>Starter Kit for Web project (General category)</Description>
<FileContentType>VSTemplate</FileContentType>
<ContentVersion>1.0</ContentVersion>
<Attributes>
<Attribute name="TemplateType" value="Project"></Attribute>
<Attribute name="ProjectType" value="Visual Web Developer"></Attribute>
<Attribute name="ProjectSubType" value="CSharp"></Attribute>
</Attributes>
</Content>
</VSContent>
原来.VSI文件内部只有两个文件:一份用于描述文件信息的XML文件和一个利用Export Template导出的ZIP压缩包。
了解了VSI内部结构后,我把TimeTracker.vscontent里的这份XML文件信息更改为描述WebSite1的信息,主要把FileName改为WebSite1.zip,然后顺便把TimeTracker.vscontent也更名为WebSite1.vscontent,然后压缩WebSite1.vscontent和WebSite1.zip文件为一个新的WebSite1.zip(注意只有ZIP压缩文件才被接受),最后把新生成的WebSite1.zip更名为WebSite1.vsi。然后双击WebSite1.vsi,其安装过程和结果完全与StarterKits里的示例一致。至此,VSI疑团告破。
认真想一下这个模版输出功能,确实大有用处。程序员之间可以利用VSI文件进行真正便捷、可配置的代码交流;也可以利用项目模版创建一系列公用的应用程序模版。相信,不久的将来,大部分.NET社区或网站提供的.NET代码示例都会采用类似Starter Kits的做法,也相信大家的代码程序交流将会更加倾向于这种VSI文件之间的交换。
再补充一下:呵呵,发表了以后,再去google查了相关资料。才发现.vsi扩展名文件的安装,其实质是调用C:\Program Files\Common Files\Microsoft Shared\MSEnv目录下的VSContentInstaller.exe进行安装的。所以如果你出现不能直接双击安装.vsi的错误时,可以利用这个命令行文件进行安装。但是我还没有找到可以用来打包生成vsi的工具程序。但根据查阅的资料显示,利用Microsoft.VisualStudio.VSContentInstaller.dll(与VSContentInstaller.exe同目录)里提供的接口似乎可以自己编写程序创建一个vsi打包工具,但尚未经过实际验证,有空再试试。
前阵子花力气载下了Windows Vista Beta1和Visual Studio 2005 Beta2 July CTP两个共近6G的软件。因此,一载完自然就热血沸腾想安装上去瞧个究竟,以补偿漫漫长夜载东西的郁闷。这里我们先尝鲜Windows,看看Vista吧。
我是在我原Windows XP SP2上用虚拟光驱安装Vista的。Vista要求全新一个分区安装,不能在现有操作系统上升级安装。Vista的安装相对以前版本的Windows确实改进了不少,没有以前那么多的步骤和停顿。在复制好所有文件到硬盘后,系统进行了一次重新启动,然后进入Windows准备初始化。在出现Windows图标和Codename Longhorn文字后,突然硬盘没有了反映,屏幕保持进入Windows前的黑屏状态,而这又不是死机。经过我反复几次重启,现象依旧。我开始怀疑是不是虚拟光驱安装的问题,于是我重新进入WindowsXP,把虚拟光驱里的Vista所有文件拷贝到硬盘中某个目录里,准备从硬盘里安装。但是后来那个该死的Vista安装程序丢了个大大错误提示框给我:“stub loader for setup program has encountered a problem and needs to close”,这个说明从硬盘安装Vista似乎行不通,于是只好重新利用Virtual CDROM安装。但是为什么在看似一切都正常的情况下,会出现Loading Windows卡壳呢?
由于我的Vista虚拟光驱是在我的一个40G的USB移动硬盘上的,在复制好所有文件到电脑内置硬盘里后,也即Windows Vista开始初始化硬件和安装信息时,出现了卡壳。在一个偶然机会下,我面对着黑屏愤怒拔了移动硬盘,啊~,电脑内置硬盘灯一下亮了起来,Windows又开始继续Loading了,直至下面的全新的Vista界面出来。后来经我反复拔插USB移动硬盘,总是这种情况: 插入时Vista就卡壳,即使是已经在Vista里面了。而拔出时一切就又恢复正常。这不知道是不是Vista硬件支持不好,还是BUG?
进入Vista后,第一眼感觉就是黄绿色桌面背景和暗黑色任务栏搭配起来,看上去挺舒服的。打开左下Start菜单,发现所有程序已经不再是一个展开的二级菜单,而是直接嵌套在了Start菜单左边栏里了,显得更加专业,空间也更加紧凑。另外,注销和关机则相反多了一个小箭头,通过它可以拉出一个菜单,进行相应选项。比如Shutdown里有StandBy、Hibernate、Shutdown、Restart和最底下的Options菜单。这样我们就不必再类似WindowsXP点击Shutdown后出现一个对话框让你选择是关机还是重启等,而可以直接一步到位的选择相应操作,这点对于讨厌多余窗口的人来说,是个不错的改善。在这个Start菜单中你还会在Lock和Shutdown左边发现一个搜索栏和搜索按钮。这个改进,其实就相当于把任务栏里的搜索条或者IE浏览器中的搜索条也搬到了大家常用的Start里,也体现了Vista搜索无处不在的特征。

再转过来看下桌面,我设置在桌面上显示“我的电脑”等图标后(噢,等下,我的电脑现在不叫My Computer了,而直接称呼为Computer,相应的,My Document也叫Documents了。也许微软觉得没必要再强调My了,毕竟在这个处处互联的网络时代,强调个人PC时代的My意义也不太大了),哇~,桌面图标好大个,一种很粗旷的感觉。这点对于习惯于1024*768分辨率中的小巧图标的我来说,一下子适应不过来,老觉得好像是640*480分辨率一样,很不爽的感觉。不过很快我就说服自己适应这些硕大的图标了。
OK,现在赶紧打开Computer,出现了我们最经常使用的My Computer窗口。这个界面对于没用过Vista早期版本(即Longhorn前几个版本)的人来说,绝对是个Surprise!感觉中这类窗口似乎不是Windows窗口,而更像是在Mac,或者X-Window中的窗口。不过左下角Windows图标和Start字样才会让我们回到现实中,这确实是在Windows里。最顶上的后退和前进按钮和一个导航栏加以搜索栏让人瞬间明了目前方位。而此时的File菜单则被下降在标准按钮和导航栏下面,这点是在令人讨厌,尽管你不得不承认把标准按钮和导航栏放在窗口最上方能让用户立刻醒目明白目前自己所在,但是,你也不得不承认,这种挑战用户习惯的行为确实让人很讨厌,至少现在是。接着中间区域还是放着类似CDROM、HardDisk、Folder等常规图标,只是大家可以看到每个HardDisk分区都有一条进度条,让你通过图型方式更加明白目前硬盘的使用状况。而在窗口最下边,还多了一个显示Windows里文件夹、文件等类型对象的各种属性信息,比如创建时间、文件名称、作者等等。最让人拍奇的还是Rating和Keywords两个属性,似乎每个文件你都可以给它添加关键字让搜索引擎更方便查找,也可以给它评价个星级,和大家一起分享下5星级文件的感受。这个想法还是不错的,把原本一个一个冷漠的文件,一下子跟用户互动起来。对于Vista中的IE7.0,个人感觉一般。毕竟一个IE窗口多个Tab页的浏览方式,MyIE已经给过我们;而对于RSS浏览时套用默认样式显示也并非特别新鲜。毕竟在IE6发布后就遭撤的IE开发组,在面对RSS等新潮流后又慌忙组建,其应付的成分还是居多的。
接着看看控制面板Control Panel。控制面板改动也不大,就是增加了几个控制选项,和重新划分了控制类别。对于其中的网络功能,这里不得不再抱怨下。我用的是笔记本安装这个Vista的,通过安装以太网卡和无线网卡驱动也顺利识别了这两个网卡。于是接着自然就是为以太网卡分配一个IP地址和输入网关等信息,以让电脑能通过局域网访问Internet。不幸的问题就是,每次重设IP地址,按确定后都要重新启动操作系统才能正常使用这些新的IP地址,也才能顺利访问Internet。这种现象让人感觉一下子回到了解放前,回到了Windows98,令人费解。另外,对于能跑到WindowsXP的大部分应用程序,都可以在Vista上正常运行。而有部分应用程序就不能正常运行,比如我想用Vista玩《泡泡堂》时,就出现启动泡泡堂游戏程序时出错的现象。
总的来说,这些表层上使用感受,真正带给用户的便利的不是很多。因此,我想对于未来Vista发布后,要说服普通家庭用户升级到Vista比较困难,需要给用户一个升级的理由。而对于我们开发人员来说,Vista带给我的惊喜和享受就显得多得多。
Vista离我们还比较遥远,据说是2006年底才正式发布,这还是不包含再次跳票的风险估计。相对于Vista来说,MSN7.5,甚至MSN8.0就离我们稍微近些了。MSN7.5的测试版近期即将正式发布测试,而我们却已经可以通过一些途径获取到MSN7.5的中文或英文测试版了。这次新版的MSN7.5增加了一些小功能,诸如语音剪辑、动态会议背景以及重新设计过的界面及按钮。其中比较突出的是增加了语音剪辑和加强了语音的功能。恰好在MessBase.com上还进一步发现了未来MSN8.0和下一代Hotmail的截图,很是让人期待。让我们一起期待吧。

.NET 2.0中的SqlConnection多了一个StatisticsEnabled属性和ResetStatistics()、RetrieveStatistics()两个方法,用于获取SQLServer的连接统计数据。当然,这样做是以性能损耗为代价的,但作为监控数据库状态的一种快捷实用手段未尝不可。
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ page language="C#" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
string connString = "Northwind的连接串";
SqlConnection conn = new SqlConnection(connString);
conn.StatisticsEnabled = true;
conn.ResetStatistics();
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Orders", conn);
SqlDataReader reader = cmd.ExecuteReader();
reader.Close();
conn.Close();
Hashtable ht = (Hashtable)conn.RetrieveStatistics();
foreach (string key in ht.Keys)
{
Label1.Text += "Key: " + key + " = " + ht[key] + "<BR />";
}
}
</script>
<html>
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="Form1" runat="server" autocomplete="on">
<asp:Label ID="Label1" Runat="server" Text=""></asp:Label>
</form>
</body>
</html>
<%@ Import Namespace="System.Data" %>
运行后的结果就是SQLServer连接统计数据结果:
Key: NetworkServerTime = 0
Key: BytesReceived = 156913
Key: UnpreparedExecs = 1
Key: SumResultSets = 1
Key: SelectCount = 1
Key: PreparedExecs = 0
Key: ConnectionTime = 30
Key: ExecutionTime = 30
Key: Prepares = 0
Key: BuffersSent = 1
Key: SelectRows = 830
Key: ServerRoundtrips = 1
Key: CursorOpens = 0
Key: Transactions = 0
Key: BytesSent = 48
Key: BuffersReceived = 20
Key: IduRows = 0
Key: IduCount = 0
- Building a better .NET Application Configuration Settings Class:虽然在.NET Framework里的ConfigurationSettings类提供了对web.config等配置文件里配置信息的保存与读取操作,但是这些对于我们日常实际的开发工作却显得“不够用”,比如我们需要新增加一个配置信息节点、对配置信息进行修改保存、配置信息加解密等等都是ConfigurationSettings类所无法提供的。尽管我们可以通过结合Xml文件操作等手段达到我们的目的,但是却忽略了我们对配置信息操作的简易实用的强烈要求。为此,该文章里就针对这种情况创建了满足上面需求的配置信息操作的几个实用类。其中值得一提的是,本来ConfigurationSettings里所有的配置信息读写都是以string类型操作的,而wwAppConfiguration采用反射手段实现了配置信息的自动类型转换,用代码说话就是:
decimal taxRate = decimal.Parse(ConfigurationSettings.AppSettings["TaxRate"]) 只需要简单写成
decimal taxRate = CustomConfiguration.TaxRate 即可。
同样,要保存一个配置信息,只需要简单代码:
CustomConfiguration.TaxRate = 0.04M; // 设置配置信息
CustomConfiguration.WriteKeysToConfig(); // 写入配置文件(需要写文件权限)
- Generic ADO.net Data Access:顾名思义就是一个通用的ADO.NET数据访问类库。它主要目的就是让你只要比较简单的修改配置信息,就可以做到更换数据库系统而不必修改代码。适用于要求与后台的数据库系统无关的应用程序。整个类库就是对ADO.NET里常用相关操作再进行一次封装,GProvider根据配置文件里的配置信息决定数据提供者是SQLServer、Oracle、Access等各种数据库系统中的一种,而诸如GAdapter、GCommand、GReader、GConnection等实际是利用针对接口编程达到抽象的目的。更具体可以参考其源代码,它是个开源项目。
- 上面两个是.NET技术资料。接着看些其他方面的资讯吧,这些资讯只是引用供大家参考,不代表个人观点。
- 方兴东:可能带动“第四次工业革命”的电机系博士生
- 老板该如何向核心员工许诺
- 一篇令所有游戏圈的兄弟汗颜的文章