上一篇Blog向大家介绍了智能标签。如前所说,开发智能标签程序并非很“舒适”,尤其是在部署上,因为我们必须将COM组件注册到计算机上,然后将其ClsID加到位于注册表的智能标签列表处。而如果使用SmarterTag(注意这个名词和SmartTag的区别),这个托管包装器来开发智能标签程序,那就爽多了。
首先,在这里下载SmarterTag,除了SmarterTag之外,还有一个QuickStart可以下载,QuickStart是一个项目源码,演示了如何开发一个SmarterTag项目。
将下载的SmarterTag中的文件解压到磁盘上的某处,比如“C:\SmarterTag”,然后运行reg.bat文件,将SmarterTag注册到计算机上。然后我们要做的,就是打开VS.NET 2003,创建一个普通的类库项目,并且在项目中引用Microsoft.PRC.Office.SmarterTag.dll程序集。
下面演示的,是开发一个能够寻找到正文中的“kane”,然后显示一个标签,上面的菜单操作可以将正文中的“kane”修改为“kaneboy”的智能标签(这个示范也包含在QuickStart里面)。效果图如下:


一个SmarterTag必须实现ISmarterTag接口:
public class FindKaneboy : ISmarterTag
ISmarterTag接口要求我们的类实现如下的方法和属性:
public void Init(String applicationName)
{
// 初始化代码
}
Init()可以让我们的SmarterTag在载入时,进行一些初始化工作。比如从后台载入客户名单等等。
public Boolean IsMatch(String text)
{
return text.ToLower().Trim() == "kane";
}
IsMatch()用来判断参数中的文本是否符合智能标签要标记的文本。在这里,只要文本是“kane”就行了。
public String[] ActionTypeNames
{
get
{
return new String[] {"SmarterTag.QuickStart.ReplaceKane, SmarterTag.QuickStart"};
}
}
ActionTypeNames属性的作用是,决定在智能标签的菜单上,要出现哪些菜单项。每个菜单项都是一个实现了IAction接口的类。这里需要返回一个字符串数组,数组里面的每个元素,是一个菜单项对应的类的类型全名。这个返回的字符串数组的数量,也就决定了智能标签上会显示多少个操作菜单项。
接着我们就要构建一个实现了IAction接口的类了,IAction表示智能标签上的一个菜单项:
public class ReplaceKane : IAction
IAction只有一个属性和一个方法需要实现:
public String Caption
{
get
{
return "补充为“kaneboy”";
}
}
Caption属性返回要显示在菜单项上的文本。
public void InvokeAction(Object target, String applicationName, String text)
{
Range rng = target as Range;
Object start = rng.Start;
Object end = rng.End;
Range rng2 = rng.Document.Range(ref start, ref end);
Object unit = WdUnits.wdCharacter;
Object count = 3;
rng2.MoveEnd(ref unit, ref count);
if (rng2.Text != "kaneboy")
{
rng.Text = "kaneboy";
}
}
OK,InvokeAction()方法稍微复杂一点,因为这个方法就是当用户点击智能标签上的这个菜单项时,要执行的代码。target参数表示在宿主程序(host application)中智能标签所标记的那块文本区域所对应的对象。宿主程序的不同,这个对象类型也不尽相同,对于Word而言,target是一个Range类型的对象。第二个参数applicationName标识了宿主程序的名称。第三个参数text是智能标签所标记的文本内容。
在上面InvokeAction()方法中,代码将智能标签所标记的文本内容从“kane”修改为了“kaneboy”。
由于我们编写的是完全的.Net程序,所以InvokeAction()是可以做任何.Net代码可以做的事情的(在权限允许的情况下)。比如显示一个MessageBox,或者显示一个WinForms窗口,或者调用WebService......这里就是业务逻辑代码的主要落脚点。
QuickStart中另外包含的SmarterTag识别了“kaneboy”,和上一篇Blog所说的那个标记博客堂最新文章作者的智能标签。

在.Net Framework 2.0中,新增了一个名称空间:System.Transactions。从其名字就可以看出来,里面包含了Transaction相关的类。System.Transactions提供了一个“轻量级”的、易于使用的Transaction框架。
在以前,要实现Transaction需要利用EnterpriseServices,让组件从ServiceComponent继承下来。而通过System.Transactions,只要简单的几行代码,不需要继承,不需要Attribute标记,呵呵。
下面介绍System.Transactions中最简单的(也可能是以后最常见的)用法:
using (TransactionScope ts = new TransactionScope())
{
// 在这里编写需要具备Transaction的代码
ts.Consistent = true;
}
TransactionScope类用来构建一个Transaction Scope,在这个Scope里面的代码将具备Transaction的能力。TransactionScope实现了IDisposable,在调用TransactionScope.Dispose()的时候,如果Consistent属性没有被设置成true,那么就将会触发Rollback动作。
using (TransactionScope ts = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection("..."))
{
conn.Open();
}
ts.Consistent = true;
}
上面的代码就演示了在一个Transaction Scope里面,打开一个数据库连接。这个数据库连接由于处在一个Transaction Scope里面,所以会自动获得Transaction的能力。如果这里数据库连接的是SqlServer2005,那么这个Transaction将不会激活一个MSDTC管理的Distributed Transaction,而是会由.Net创建一个Local Transaction,性能非常的高。但是如果是SqlServer2000或者7,那么则会自动激活一个Distributed Transaction,在性能上遭受一定的损失。
using (TransactionScope ts = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection("..."))
{
conn.Open();
using (SqlConnection conn2 = new SqlConnection("..."))
{
conn2.Open();
}
}
ts.Consistent = true;
}
这个例子更加充分的说明了Transaction Scope的强大,两个数据库连接!虽然上面的conn和conn2是两个不同的连接对象,可能分别连接到不同的数据库,但是由于它们处在一个Transaction Scope中,它们就具备了“联动”的Transaction能力。在这里,将自动激活一个MSDTC管理的Distributed Transaction。(可以通过打开管理中心里面的组件服务,来察看当前的Distributed Transaction列表。)
下面再介绍如何手动将一项资源(Resource)参与(enlist)到一个分布式事务中:
ICommittableTransaction tr = Transaction.Create();
using (SqlConnection conn = new SqlConnection("..."))
{
conn.EnlistTransaction(tr as ITransaction);
}
tr.Commit();
上面的代码手工创建了一个ICommittableTransaction对象(通过Transaction类的static方法)。SqlConnection对象通过EnlistTransaction()方法参与到这个Transaction中去。注意:EnlistTransaction()方法只接受ITransaction类型,因为ITransaction没有Commit()方法,你肯定不会希望ICommittableTransaction之外的其他对象来执行Commit()方法吧,呵呵。
参考资源链接:
System.Transactions命名空间
MSDNTV: Introducing System.Transactions in .NET Framework 2.0
祝博客堂全体成员和所有读者新年快乐!没什么可奉献的,提供给大家一些最新的下载链接吧:
Microsoft Chinese New Year Pack 2005:包含了一些有关中国新年的墙纸、音乐、屏保。
ASP.NET安全更新(针对1.1 SP1和1.0 SP3):最新的针对ASP.NET漏洞的.Net Framework安全更新。
另外,在这两天,Microsoft针对Windows系统发布了多个安全更新,请访问Windows Update。
以前在我的Blog上就曾经写过
一篇文章,描述了ASP.NET 2.0 Beta2中对于页面编译模型,相对于Beta1的重大改变。今天在网上发现了两篇(
here &
here)不错的Blog,更详细的描述了这个变化,以及其中运行的机制原理。
从我个人的喜好而言,我更喜欢Beta1的Code-Beside方式,因为机制非常清晰明了,很好理解,而且感觉也非常优雅。但是Code-Beside的方式有一个明显的缺陷,开发人员很难使页面从自己定义的一个Page Base Class继承下来,而在ASP.NET 1.1中,这是非常简单的事情(只需要直接更改Code-Behind文件的父类即可)。
Beta2的改进使其实现方式更加复杂了,但是好处就是让开发人员又能享受自己定制的Page Base Class的好处了,而且也消除了在ASP.NET 1.1中,Code-Behind文件中不得不加上一大串protected控件声明的缺陷。
在一月份一直忙于投身于一个工作流的演示项目中,项目牵涉到了SPS、InfoPath、K2、Mobile、Exchange等。如果有感兴趣的朋友,可以在
这里看看这个演示系统的一些截图。顺便在这里也推荐一下
K2,这是一个非常不错的工作流引擎,和SharePoint、InfoPath有良好的连接能力,而且扩展性也是很强的。
这篇文章讲述了如何编写一个SPS的备份和恢复程序。在微软的下载站点,可以
下载到在SPS中进行查询所使用的Sql语法。MicroToby也奉献了一篇精彩的描述SPS定位以及前景的
文章。
前阵子,有网上的朋友向我询问现在微软对于BI Portal的解决方案。何谓BI Portal?BI Portal的意思就是Business Intelligence Portal,商业智能门户。其实,使用微软现有的各项产品,SPS2003、Project Server 2003、SqlServer Reporting Services等等商业应用服务器产品,以及客户端强大的Office System,建立一个BI Portal的难度相比以前是大大降低了。
微软自己也提供了一个BI Portal的Sample
下载。这个Sample使用了SPS、SqlServer Reporting Services、Office Web Component等技术,构建了一个基于Office System 2003的集成性基于Web的OLAP解决方案。企业中的员工可以通过这个BI Portal,创建并共享OLAP/Relational/XML-Based视图,并能对各自的视图进行个性化定制。
前两个星期,投身在一个为客户做的工作流程演示项目中。项目的目标是在短时间内,演示构建一个能够体现移动设备优势的工作流系统。
项目中使用了SharePoint Portal Server 2003作为整个系统的Web基础组件。

其中一个流程使用InfoPath作为表单输入终端:

工作流引擎使用了K2,K2能够很好的和SharePoint/InfoPath集成,并且具有非常好的扩展性。

用户可以通过PPC移动设备,直接参与流程:

通过Pocket IE,PPC可以直接浏览流程审批页面,并在页面上进行流程处理:

或者,通过离线邮件的方式,以邮件来参与流程:


当然也支持直接使用Outlook或者OWA的方式: