Joycode@Ab110.com

March 2007 - Posts

ZDNet线下聚会第三次(SharePoint主题的最后一次)报名!


活动时间:2007年4月1日(星期日)14点
活动地点:CNET(中国)总部(海淀区知春路113号银网中心A座9层,大海会议室)
活动讲师:陈曦(微软MVP,SharePoint资深专家)
嘉宾讲师:涂曙光(大牛大牛大牛)

现场将设有有奖互动的环节,惊喜等你来。
技术沙龙活动情况相关报道


本活动不收取任何费用

Symbian OS中的RArray类的排序功能

RArray类,属于symbian OS提供的基础容器类,并且是比较重要和常用的一个。

如果从名字来看这是一个数据类,功能貌似和 MFC的CArray,stl的vector差不多吧?
如果这么想就错了,RArray是个泛型数组容器类,但是功能比CArray vector 提供的要多。

尤其是他提供的排序和查找功能,其实现方法比较诡异,对初学者来说容易造成迷惑。
个人认为这个设计比较蹩脚,至于为什么会这样,我想不出,已经写信给作者咨询了,不过还没得到答复。

RArray的排序是这样的,它规定数组中每个元素可以有一个 order key,这个order key其实就是数组元素的某4个字节
至于具体是哪4个字节作为order key是由key offset决定的,key offset 是构造函数的参数,是可选的,默认为0

就是说,默认情况下,数组里面每个元素的前4个字节会被用来作为排序的key。
因此RArray也规定,每个元素至少要有4个字节,并且大小必须是4个倍数,否则某些函数不能用,甚至会产生异常。

比如我们声明一个 结构体 Bar 作为数组的元素,然后构建一个Bar的数组 barArray

struct Bar
{
   TInt  iId;
   TInt  iSize;
}

RArray<Bar> barArray;

于是 iId就会成为order key了,因为默认情况下key offset 为0,iId就是元素的头4个字节。
如果你要用isize做order key,那么只要指定key offset为4就好了。

如果需要RArray的排序功能那么 你就需要用到一系列名字中带有KeyOrder的函数比如 InsertInSignedKeyOrderL,FindInSignedKeyOrderL等等

Insert操作时,会按照插入元素的order key排序来查找合适的Insert位置。
Find时,也是比较order key,由于查找时只比较order key,所以会写出这样有点诡异的代码
比如我们要查找 iId 为 100的元素的位置
Bar foo;
foo.iId = 100;
TInt index = barArray.InsertInSignedKeyOrderL(foo);
查找条件中的 iSize没有初值?对没有,也没必要,因为InsertInSignedKeyOrderL只比较前4个字节
iSize用不到,所以也不用给初值。

注意 函数名中的 Signed,还有与之对应的 Unsigned,这些表示比较order key的时候是否考虑符号。
就是order key是 当作TInt还是TUint来比较。

如果你不用这些带有KeyOrder的系列函数,那么和一个CArray的数组基本一样。

另外 RArray有2个特化版本,RArray<TInt>,RArray<TUint>,可能是为了提高效率吧。

现在我明白Symbian 里为什么没有 list map 等容器类了,RArray实在是一专多能。
不过我还是认为这样的设计不够优雅,也许作者有苦衷?希望RArray作者的答复里可以给我解释。

实时监测机场的起降情况

经常坐飞机,有时候就想能不能有一个系统能够让我了解我所乘坐的飞机的具体情况,以及机场的准确位置。当然,目前我对首都机场的了解简直比我家还要熟悉。上海虹桥、深圳以及广州白云等机场也是比较了解的。但是当我第一次到达西雅图机场的时候,当时还真有一些昏头昏脑,实在太大了,呵呵。

在首都机场的网站上,我们可以查找到各航班的信息,比如是否晚点、计划时间等,而且是以图表方式给出的。但是能否以更加精确的方式来反应呢?想像一下,如果您能够以实时动画的方式查看各个航班的信息:是否满员、飞机实时的具体位置、方向、起飞降落时间、机型等等情况,那是多么爽的一件事情呀?如果您对这件事情比较感兴趣,那么请看左图。这是苏黎士机场的实际运营情况。当然为了“反恐大业”的需要,您可以看到的这个版本使用了一些历史数据,而没有接收实时的数据。

网站地址:

http://wpf.netfx3.com/direct/zurich/zeuswpf.xbap

软件需求:

操作系统必须是Windows XP+SP2、Windows Server 2003+SP1或者Windows Vista,前两者操作系统必须安装.NET Framework 3.0。

键盘操作:

Ctrl+鼠标右键:扩大视野范围(Zoom Out)

鼠标左键拖动:移动视野范围

鼠标右键拖动:缩小视野范围(Zoom In)

英文博客信息:http://blogs.msdn.com/tims/archive/2007/03/27/great-wpf-applications-13-z-rich-airport.aspx

我感觉国内的一些ISV软件厂商可以借助WPF的机遇,做一些富有创新的软件,比如股票软件、基金软件等等。可能基于原来的软件开发的难度,有很多创新我们无法付诸实施,但现在既然有了WPF这么强大的工具,我们还在等什么呢?:)

[招聘] 微软在武汉地区招聘 Technical Account Manager

[代MS武汉华中区ES负责人xfzhang贴招聘信息,欢迎有志者加盟。]

3年前,微软在武汉设立了华中区(Central China,覆盖湖北、湖南、江西3省)办事处,如今由于业务的迅猛发展,需要大量人才加盟。
Technical Account Manager(以下简称:TAM)是微软Enterprise Services部门最具有活力的职位之一,如果您认为在下述方面有专长,请积极报名:

1、 工作地点:中国湖北省武汉市(请慎重考虑);
2、 很强的客户沟通能力和业务拓展能力(TAM中的Account Manager部分);
3、 很强的微软技术背景和产品熟悉度(TAM中的Technical部分);
4、 熟悉Active Directory体系架构和部署方式、熟悉Windows Server 2003主要产品特性和企业部署能力;
5、 熟悉SharePoint技术,如果有SharePoint Portal Server 2003或Office SharePoint Server 2007经验将优先考虑;
6、 熟悉Exchange技术,如果有Exchange Server 2003部署经验将优先考虑;
7、 熟悉.NET开发,如果有Visual Studio 2005或.NET 2.0/3.0开发经验将优先考虑。

如果您对在微软、在武汉工作感兴趣,请发送简历至:xfzhang@microsoft.com

对SPS 2003 URL进行访问授权控制

对于普通ASP.NET站点来说,要对该站点的URL进行访问授权控制,可以通过创建一个HttpModule来监控每个Request,如果Request Url为受控URL(即要访问该URL地址需要经过一种特定验证授权)时,则跳转到验证授权页面进行身份验证授权,完成后再返回即可正常访问Request Url。我想,这个实现并不难,网络上也可以找到诸多用HttpHandler和HttpModule来做这块处理的示例。

那么,SharePoint Portal Server 2003中,访问受控URL和普通ASP.NET站点有何不同吗?带着这个疑问,我们可以一开始也用HttpModule来做尝试。假设此时我们访问一个SharePoint 文档库的某个内容,其URL地址应该是 http://localhost/DocLib1/Test.doc,而在我们的受控URL数据库记录中发现 http://localhost/DocLib1 为受控URL,那么要访问 http://localhost/DocLib1/Test.doc,就不能让未经过验证授权的用户直接访问,而应该跳转到我们验证授权页面进行身份验证授权后方能访问。结果很让人遗憾,我们的访问畅通无阻。于是做了调试跟踪,发现在 HttpModule 中 Request.Url 不是我们想要的 http://localhost/DocLib1/Test.doc,而是一个对我们未知的 http://localhost/_vti_bin/owssvr.dll,正因为这个地址不是受控URL,所以HttpModule不做处理直接让用户继续访问了。

姑且不论owssvr.dll到底为何物,现在要解决的关键问题有两个:

  1. 为什么我们点的是 http://localhost/DocLib1/Test.doc 这个请求,而到HttpModule时,却变成了http://localhost/_vti_bin/owssvr.dll,谁干的好事?
  2. 我们能否在这家伙做这件事之前把执行权抢过来做我们自己的处理?

对于第一个问题:谁动了我的URL?在了解这个问题答案之前可以先参考以下文章:

看完上面两篇文章,或许你已经清晰知道是谁动了我们的URL。是stsfltr.dll(可以在IIS管理器-->Web站点属性窗口-->ISAPI 筛选器找到)这个ISAPI Filter在HttpModule之前抢先做了处理

第一个问题找到了,第二个问题:怎么解决这个问题,把执行权抢过来?只能自己再写个 ISAPI Filter,并把该 ISAPI Filter排在stsfltr.dll之前了。于是,我们创建了一个C++ Win32 项目,定义了下面这个一个ISAPI Filter class:

class CRedirectorFilter : public CHttpFilter

{

public:

     CRedirectorFilter();

     ~CRedirectorFilter();

 

     BOOL IsSecureDocument(LPCTSTR docUrl, LPCTSTR agent, LPCTSTR cookie);

     BOOL GetCookie(CHttpFilterContext* pCtxt,CString strName, CString & strValue);

     BOOL GetAgent(CHttpFilterContext* pCtxt,CString strName, CString & strValue);

 

// Overrides

     // ClassWizard generated virtual function overrides

         // NOTE - the ClassWizard will add and remove member functions here.

         //    DO NOT EDIT what you see in these blocks of generated code !

     //{{AFX_VIRTUAL(CRedirectorFilter)

     public:

     virtual BOOL GetFilterVersion(PHTTP_FILTER_VERSION pVer);

     virtual DWORD OnPreprocHeaders(CHttpFilterContext* pCtxt, PHTTP_FILTER_PREPROC_HEADERS pHeaderInfo);

     virtual DWORD OnEndOfNetSession(CHttpFilterContext* pCtxt);

     //}}AFX_VIRTUAL

 

     //{{AFX_MSG(CRedirectorFilter)

     //}}AFX_MSG

};

通过OnPreprocHeaders来处理判断我们的受控 URL 逻辑,如果是受控URL且尚未经过验证,则绕过stsfltr.dll直接跳转到验证授权页面进行身份验证授权;如果不是受控URL或已经经过验证,则直接交给IIS继续处理。

对于MOSS 2007,没有了stsfiltr.dll的困扰,实现类似方案就相对方便许多了,有兴趣者可以利用HttpHandler或HttpModule进行类似实现。

BTW:对于对受控URL的判断逻辑,如果感觉C++实现比较吃力费时,可以考虑用.NET Assembly来写这块逻辑,然后利用C++调用托管DLL来实现这块逻辑。具体可以参考KB:

暂时广告贴:OTEC广州三月份线下聚会


我会奉献一个如何在SharePoint Designer 2007中创建自定义操作的讲座,欢迎光临!

ASP.NET AJAX (Atlas) 拖放(Drag &amp; Drop)功能6种实现方法总结

在Ajax程序中实现传统桌面程序中异常简单的拖放功能却并不是件容易的事情。然而Web上的拖放功能又如此的让人痴迷,所以几乎每个成熟的Ajax类库都提供了自己的一套实现拖放的封装,ASP.NET AJAX (Atlas) 自然也不例外。本文将总结并简要分析ASP.NET AJAX (Atlas) 中拖放功能的6种不同的实现方法,希望能够帮助朋友们选出最适合实际需求的方法。

其中第1到第4种方案,在我的《ASP.NET Ajax程序设计——第I卷:服务器端ASP.NET 2.0 AJAX Extensions与ASP.NET AJAX Control Toolkit》一书中有详细介绍(4月出版),本文中的代码和图示也节选自该书。第5第6种方案,在我的《ASP.NET 2.0 Ajax程序设计——第II卷:客户端Microsoft AJAX Library》一书中将有详细介绍(暂定7月出版)。

不过纵观这些解决方案,我很遗憾的发现,要么是使用简单,可定制能力差,要么就是可定制能力强,但使用起来要写很多代码。希望ASP.NET AJAX (Atlas) 团队能够再接再厉,努力把这个重要功能做得更好。或者我有哪种方法漏掉了,也请朋友们帮忙补充一下。

 

[1] 使用服务器端DragOverlayExtender或客户端DragOverlayBehavior

服务器端的DragOverlayExtender就是靠着客户端DragOverlayBehavior而实现的,前者是后者在服务器端的组件化封装,所以我们将二者放在一起讨论。

这个“拖放”功能很简单,其实这只是个“拖拽”,而没有“投放”。也就是说,你可以随意将某个Panel在页面中拖来拖去,不过却没有什么固定的地方可以“投放”,就像在Windows桌面上拖放某个窗口的位置一样——其实用处不大,也没有提供什么可定制能力。但它使用起来非常简单,也支持将Panel的位置保存在Profile中。

下面是一段DragOverlayExtender的示例代码,至于DragOverlayBehavior的用法,请查看DragOverlayExtender页面生成的HTML代码:

<asp:Login ID="floatLogin" BackColor="white"
  BorderStyle="Solid" BorderColor="black" 
  runat="server">
</asp:Login>
<asp:DragOverlayExtender ID="DragOverlayExtender2" 
  Enabled="true" TargetControlID="floatLogin" 
  runat="server" />
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

效果如下:

 

[2] 使用服务器端DragPanel

DragPanel是ASP.NET AJAX Control Toolkit中的一个扩展器控件。其功能基本与DragOverlayExtender和DragOverlayBehavior一样,且同样可以保存Panel的位置信息至Profile中。不同之处在于,DragOverlayExtender和DragOverlayBehavior的拖拽实现方式中,鼠标放在整个Panel的任何部分都可以开始拖拽,而DragPanel在进行拖拽时,只有鼠标放在指定的DragHandle(类似于Windows窗口的标题栏部分)中才能开始拖拽。

对于DragHandle的扩展性和实用性,同样不敢恭维。

下面是一段示例代码:

<asp:Panel ID="floatPanel" CssClass="floatPanel" runat="server">
    <asp:Panel ID="floatPanelHandle" CssClass="handle" runat="server">
        窗口的拖动
    </asp:Panel>
    <div class="content">
        在Windows中,对窗口的拖动似乎成了我们习以为常的事情。
        ………………
        ………………
        Window窗口的表现行为一样。
    </div>
</asp:Panel>
<ajaxToolkit:DragPanelExtender ID="dpe" TargetControlID="floatPanel" 
    DragHandleID="floatPanelHandle" runat="server">
</ajaxToolkit:DragPanelExtender>

效果如下:

 

[3] 使用服务器端ReorderList

ASP.NET AJAX Control Toolkit中的ReorderList控件将在页面中呈现出一个由数据绑定自动生成的条目列表。用户可以通过鼠标拖动某一项来直接改变该列表中条目彼此之间的相对位置关系,且在拖动的过程中,ReorderList控件提供了丰富的、可定制的视觉效果。当用户在某个位置放开鼠标之后,ReorderList控件也将同样会自动通知与其绑定的数据源控件,以Ajax的异步或整页回送的同步方式更新服务器端数据。

ReorderList控件的使用比较简单(服务器端控件),功能也相当的丰富,扩展能力也不错。不过仍称不上最灵活,比如我们想把条目在多个ReorderList之间拖放,那么就没办法实现了——因此,不要指望它能实现WebPart那样的功能。

下面是一段示例代码:

<ajaxToolkit:ReorderList ID="musicList" CssClass="musicList" 
  DragHandleAlignment="Left" PostBackOnReorder="false" 
  DataSourceID="musicDataSource" DataKeyField="Id" 
  SortOrderField="Order" runat="server">
    <ItemTemplate>
        <ajaxToolkit:Rating ID="rating" runat="server" 
           CssClass="rating" StarCssClass="ratingStar" 
           FilledStarCssClass="filledRatingStar" EmptyStarCssClass="emptyRatingStar" 
           CurrentRating='<%# Bind("Rating") %>' MaxRating="5" 
           ReadOnly="true">
        </ajaxToolkit:Rating>
    </ItemTemplate>
    <ReorderTemplate>
        <div class="dragDue">
            Drop Here!
        </div>
    </ReorderTemplate>
    <DragHandleTemplate>
        <asp:Label ID="lbTitle" CssClass="dragHandle" 
           ToolTip="Drag Me!" runat="server" Text='<%# Bind("Name") %>'>
        </asp:Label>
    </DragHandleTemplate>
</ajaxToolkit:ReorderList>

效果挺酷的:

 

[4] 使用UpdatePanel与ASP.NET AJAX中的新版本WebPart控件

ASP.NET 2.0中的WebPart相关的控件虽然非常丰富,易于使用且功能强大,我们在程序中也很需要它所提供的拖拽功能,但它却存在着两个致命的缺陷:

  1. 拖放功能只支持IE浏览器。
  2. 每次用户通过拖放改变配件的位置之后,页面总会自动进行回送以保存当前的设定。

其中第一个问题可以通过ASP.NET AJAX中的新版本WebPart控件搞定,第二个问题可以通过添加UpdatePanel搞定,本来在CTP版本中的ASP.NET AJAX里面,这些功能均已经完美实现了。谁知道在最新的Futures CTP中,却又不好用了。

既然现在已经不能用了,也就没必要分析其优点缺点了。不过还是给出一张截图吧,缅怀一下曾经的辉煌(注意,这可是在Firefox中啊!)……

 

[5] 使用客户端DragDropList

DragDropList定义于ASP.NET AJAX Futures CTP中,功能非常强大,且全部在客户端实现,给服务器端减轻了不少的压力。使用DragDropList实现第4种解决方案中的WebPart类似的效果完全没有问题,不过唯一让人感到遗憾的就是,其扩展功能不是很好,用户虽然可以随便将某个Panel从一个区域拖到另一个区域,但拖拽的结果却很难持久化下来……且使用起来也不是那么的容易,效率上更是不敢恭维……总之,这是个很让人矛盾的东西,有些鸡肋的感觉。

我曾经在《使用ASP.NET Atlas实现拖放(Drag & Drop)效果(下)》这篇文章中给出过DragDropList的示例程序,虽然是基于CTP版本的ASP.NET AJAX ,不过实际上并不需要多少修改就能运行于最新版本之上。感兴趣的朋友可以看看,也可以到官方论坛上搜索一下相关的主题。

 

Devil 在客户端自行实现IDragSource和IDropTarget接口

来到了这个解决方案,可以说你对ASP.NET AJAX中的拖拽实现有了一个较深入的了解。上面的DragDropList其实就是实现了IDragSource和IDropTarget接口,其中前者用来定义可以被拖拽的项目,后者用来定义可以被投放的区域。详细理论上的说明,可以参考我的文章《使用ASP.NET Atlas实现拖放(Drag & Drop)效果(上)》,虽然目前已经有所变化,不过仍可以参考。

这种实现方案应该说是最为强大的了,想要什么功能,肯定都能实现。不过实际开发中的难度也不小——甚至可以说是相当复杂,Jeff Prosise的这篇文章《Implementing Drag-Drop in ASP.NET AJAX》给出了一个非常简单的示例程序,感兴趣想要学习的朋友不妨看看……

JetBrains向MVP免费提供Resharper
根据Jeffrey PalermoJetBrains 将向MVP免费提供Resharper,感兴趣者请与JetBrains 的 David Stennett联系:David Stennett: david _a@t _ jetbrains.com 。
【非技术】西雅图之行

上个星期去西雅图参加MVP全球峰会,很高兴看到国内的很多朋友,包括大美女Sisley,大小Eddie,还有和我合作翻译Christian Nagel《.NET企业服务框架──应用.NET企业服务开发分布式业务解决方案》 (CSDN读书频道提供三章)一书的速马,和来自CSDN的很多朋友(谭颖华,蒋晟,潘宇光,超级绿豆,朱长德,秋水无恨等),以及腾讯的张善友,孙鹏等。可惜,回来时因为天气的原因中途转的航班被取消,不得不在芝加哥滞留了几天。临上机时,又发生了一件啼笑皆非的事情。回家后,身体一直不适,白天还要上班,Scott的新博客文章没有及时翻译,请见谅! 至于这次会议的技术方面的东西,以后再写。

很多人写了关于峰会的东西,感兴趣的话,大家可以去看一下,

潘宇光的西雅图现场报导

谭颖华的西行漫记

张善友的美国体验圣帕特里克节(St.Patrick's Day)

 

在这里能看到MVP上传的照片:

http://www.tuojie.com/mvp

WatiR or WatiN
这个月 watiN 终于Release了,在我们的项目中,一直就在争论到底是使用WatiR 还是 WatiN 的争论,在WatiN发布以前,因为WatiR已经有了稳定版本,所以就一直采用WatiR,等待WatiN 出来以后,我当然是要使用WatiN了,今天花了一天的时间,把以前WatiR的测试用例全都重写了一遍,感觉就是一个字"爽",以前想都不敢想的一些测试,现在也可以做了。

发现了WatiN的两个问题,不过都有了解决方案。
1. WatiN没有直接的JavaScript 的调用接口,这点WatiR强一些
2. WatiN和WatiR犯了同样的问题,当在一个Test Case 中启动多个IE的时候,这些IE之间会共享Session,这点超级不爽。

WaitR的好处是:
1.Open Source
2.Ruby 语言

WatiN的好处是
1.Open Source ,新的Release 甚至为了方便大家使用,修改了使用协议
2..Net 平台,如果大家是开发Asp.net 的网站地话,会非常的方便,因为可以使用很多现有的类库


BTW:
  今天也顺便解决了,WaitR在 NAnt 中有时会无法操作IE 的Bug,要解决这个问题,需要下载今天早晨的最新Gem Build


附和一下 demonfox 同学,说说symbian & s60

Windows的庞大和臃肿是早有体会的了,最近作Symbian开发

别以为Symbian是个小东西,我得到的统计
Symbian & s60 源代码包括 10万个左右文件,总共1G左右的大小。但这还不是全部源代码,某些内核,本地化资源的内容没有计算在内。

在手机和PDA上系统的Release版本也不过几M的样子,源代码是Release的几百倍。由此推算windows的源代码要以TB计算了。

在现在的软件开发和设计模式下,代码膨胀是不可避免的,能写出简练精巧的代码的人是极少数,其他大部分是写臃肿丑陋的代码的庸才,但是需要实现功能那么多,靠少数高手是根本干不完的。

另外需求变化很快,新的需求出现,原有的设计通常无法满足,只有在上面修修补补,经常可以看到代码中无数复杂嵌套的If ...else... ,重构的代价是高昂的,尤其在Weekly build 甚至Daily build的压力下,很少会冒险去动原有的可以测试通过的代码。

对于管理者来说,他们很清楚这样下去产品终究会走上绝路,但是他们会极力避免发生在自己的任期上。

我有时想,软件产品就像生命一样,也会经历生老病死的轮回。

最后做个推荐,我发现博客堂只有放在首页的随笔才会访问量比较高,文章就差很多了

写了篇关于 Symbian 两次构造 NewL NewLC ConstructL 的文章,有兴趣的去看看吧。
http://blog.joycode.com/yaodong/articles/94824.aspx

说说

 

我觉得Windows已经变成了一个怪物。

很多当初良好的设计理念和技巧已经为层层的妥协性和兼容性考虑搞得面目全非。它的内核变得如此复杂甚至于浏览器已经变成了内核中最中枢的部分之一。它的庞大成为臃肿和脆弱而不是强大的代名词。这个操作系统究竟还能否胜任我们在上面进行创新和开拓,我很怀疑。

Vista历时5年,千呼万唤,始见真身。但本来有的很多前端理念最后都只能割爱,比如最为可惜的就是提出transaction based filesystem的WinFX。关于各种内幕,人们问的最多的就是:5年的开发过程究竟发生了什么,为什么需要那么久,而又为什么最后还是砍掉了如此多的功能。我不想信口开河,只是个人认为,整个Windows系统长期积累的复杂性已经让很多有意义有魄力有革命性的创新无法在上面自由发挥。人们经常发现,你要这样做,就会影响到这个,然后会牵连到那个,最后这里有那么一个潜伏的bug就引爆了。在这样一个不是磐石一块而如迷宫一般的地基上建造出来的只能是脆弱不稳定臭虫满天飞的系统,微软的同事们也许会明白我在说什么,Vista开发到2年半后的那次Reset就是最好的证明。

最近自己碰到的两件事:

1. 我们组的project进入了最后部署阶段。就是这样一个还不算复杂的Alpha版的网络软件系统,我们在制作安装程序的时候居然用到了不下8种不同的Microsoft technology,什么Active Directory, IIS Diag, Virtual Directory, Application Pool, Winhttpcertcfg, Webstore, EventLog 粉墨登场琳琅满目不一而足。写setup的那位倒是好好秀了一把他对微软技术的熟悉程度,但我们都一致地为这样的本末倒置无颜以对。我最后揶揄地说:这个setup程序好像都要比我们真正的软件还要大了。

2. 我昨天发现IIS有这么一个限制:IIS不允许request url的路径里有冒号(colon, " : " ),一旦request url的路径里有冒号,IIS直接400 Bad Request。这个真是迭迭怪事,最后我在网上还真搜到了解释:

IIS does not permit colons in the URL. This is because the NTFS file system
considers a colon to be a special character that's used to denote alternate
streams within a file. If your example URL below were handled by the static
file handler in IIS, it would attemps to open the stream called "blah"
within a file called "blah" in the "script.cfm" directory under wwwroot.

More specifically, without this limitation, if a client were to request
http://www.example.com/script.cfm::$data, then the contents of the
script.cfm file would get sent to the client instead of invoking ColdFusion <http://forums.devshed.com/>
to process script.cfm.

If you want to prevent IIS from parsing your data, then put it either in the
query string or the entity body. A colon would be allowed in either of
those places.

Thank you,
-Wade A. Hilmo,
-Microsoft

大意是说因为NTFS文件系统的一个限制,所以IIS不接受request url path里的冒号,如果一定要用冒号,请放到query string里(就是问号?后面跟的东西)或者用request content body。回答的Wade Hilmo现在是IIS的Dev Lead。

我真的觉得悲哀,因为NTFS文件系统的一个潜在的安全漏洞,IIS居然可以做出违反RFC的事情来。RFC 1738明确说:

httpurl        = "http://" hostport [ "/" hpath [ "?" search ]]
hpath          = hsegment *[ "/" hsegment ]
hsegment       = *[ uchar | ";" | ":" | "@" | "&" | "=" ]

冒号完全是合法的url字符。

一个是文件系统,一个是web服务器,风马牛不相及的东西居然也能这么剪不断理还乱,我彻底败了。

就因为这一个小小的限制,我们需要重新定义我们的协议,然后牵连到我们的Windows Live Partner都要重新定义他们的接口。而且我们还要一直注意这个问题,如果将来onboard的partner在url中用了冒号,我们要想想会不会出问题(就我们所知,确实已经发现有这样潜在的partner在他们的协议中用了冒号)。我们又要.... 还要么?我是觉得够了。

===========================================================================

这是在新的Laptop上的新的Vista系统里写的第一篇blog,原本不应该这么攻击自己公司的产品的,而且说实在话,用了这些时间感觉Vista也是还不错的系统,除了那个可笑之极的Cancel or Allow的对话框(不是说不好问,但问一遍就够了吧,还没完没了地问了)。不过我真是觉得Windows系统已经到了一个很危险的阶段,而与此同时Linux和Mac OS的长足进步更是一日千里(我至今记得第一次看到Ubuntu和OS Tiger时惊艳的记忆,尤其是OS Tiger,我对这个基于unix内核的系统爱不释手)。我们应该有勇气像当初苹果一样,壮士断腕,重起炉灶,而不是还是如此这般3天一小修5天一大补地搞了。Windows真的是很危险,我们不能再靠搞搞花哨的用户界面来理所当然地认为用户还会掏钱买我们的产品。

有人说,重起炉灶,说得轻巧,这么多以前的用户怎么办?都不管了?

不,当然要管。利用virtualization提供向前兼容支持,保留底层的内核,重新开发核心的安全组件,那个奇怪的registry应该好好重新设计了,而网络时代使用越来越频繁的digital certification management,digital rights management,等等功能都要重新简化设计。这当然是很复杂很复杂的事情,但关键的是改变态度,办法是人想的,但态度决定一切。

$150等于什么?
在微软商店挑花了眼,终于花完了$150元,买到了自己还算满意的商品。最满意的是WM USB Powerd Speaker,有了它,我就不必再为laptop音量太小而烦恼了,我有了自己的移动影院。

Picture of WM USB Powered SpeakersPicture of WM Pen Drive 1GB


虽然已经有了40G的移动硬盘,但再增加一个U盘也不为过。1GB的U盘价值$62.99似乎太贵了,看来如果要到美国生活不是件容易的事,如果不是Microsoft馈赠的,我还是舍不得。遗憾的是这个U盘没有mp3的功能,不然就太棒了。

微软商店提供的女士商品实在是太少了点,有心给老婆买一件好的,挑来挑去实在挑不出什么好东西来,最后只得买了个杯子了事,实在有些愧对老婆了。

Picture of Office Fiesta Tumbler OrangePicture of Geeks Rule T-ShirtPicture of Microsoft Grip LED Pen


没有什么好看的衣服,T-Shirt的设计也很一般,特别是for ladies的,就更少,而且剩下的还都是大号。最后没有办法,只有随便给自己挑了一件T-Shirt,主要是为了花完这$150元钱。此外买的一支笔,同样出于这样的目的。

Picture of Wireless Optical Periwinkle Mouse

鼠标是值得买的,虽然自己已经有了一个鼠标,但还是无线鼠标用起来更爽一些。

最后只剩下$0.04了,基本上做到了不浪费一粒子弹的目的。节约是美德,即使是别人白送的,丢了也怪可惜的。如果商店还有4美分的商品,我也会毫不犹豫放到购物车里,嘻嘻。下了订单,就等着收货吧!

Policy Injection Application Block

Microsoft Patterns & Practices团队在2007年发布的Enterprise Library 3.0 February 2007 CTP中,我们惊喜地发现了AOP的踪迹,其名为Policy Injection Application Block(PIAB)。Enterprise Library的产品经理Tom Hollander和架构师Edward Jezierski都相继在自己的博客上介绍了PIAB。从特征与功能来看,已经基本具备了AOP的要求。

从技术实现来看,PIAB并没有特别的创新,沿用了大多数致力于.NET平台AOP研究人员的思路,采用了Remoting Proxy技术。PIAB定义了特殊的工厂类,通过它添加Policy,然后创建代理对象实例。受到Remoting Proxy技术的限制,所谓的代理对象必须继承自MashalByRefObject。例如:
public class LoggingTarget : MarshalByRefObject
{
    public string DoSomething(int one, string two, double three)
    {
        return string.Format("{1}: {0} {2}", one, two, three);
    }
}

添加Policy与创建Aspect对象的方法如下:
private PolicySet GetLoggingPolicies()
{
    PolicySet policies = new PolicySet();

    Policy simpleInputsPolicy = new Policy("simpleInputsPolicy");
    simpleInputsPolicy.RuleSet.Add(new MatchByNameRule("MethodWithSimpleInputs"));
    simpleInputsPolicy.Handlers.Add(new SignatureCheckingHandler(new Type[] { typeof(int), typeof(string) }));
    policies.Add(simpleInputsPolicy);
    return policies;
}
private LoggingTarget CreateTarget()
{
    InterceptionFactory factory = new InterceptionFactory();
    factory.AddPolicies(GetLoggingPolicies());
    return factory.CreateNew<LoggingTarget>();
}

代理对象(Proxy Object)会通过Handler链定位到真实对象(Real Object),而Policy则被注入到代理对象和真实对象中。整个流程如图:

PIABIntroPipeline.gif

在Policy中,包含了一个Matching Rules集合以及Handlers Pipeline。从AOP技术的角度来看,代理对象所指代的真实对象就是“Aspect”,而Policy则是切入点,它可以通过Matching Rules来定位代理对象的方法,至于Handler则近似于Advise。

Authorization横切关注点(Cross-Cutting Concerns)的处理方式如图所示:

PIABaborted.png

PIAB目前预定义的Handler包括Validation Handler、Logging Handler、Exception Handling Handler、Authorization Handler、Caching Handler。这些Handler与Enterprise Library中的其他Application Block几乎是一一对应的。事实上,权限认证、日志、异常处理、缓存等,恰恰都是AOP技术最重要的关注点。在February 2007 CTP版本之前的Application Block,实际上已经具备了AOP的雏形。然后,由于它在“横切”与“注入”方面的缺乏,始终无法达到AOP所要求的重用目的。Policy Injection Application Block正好弥补了这样的缺憾。

本人也曾利用Remoting Proxy技术开发了.NET平台下的AOP组件,基本实现了AOP的主要功能。然后因为两个困惑,使得这一工作没有继续进行下去。

1、使Aspect对象继承自MarshalByRefObject是否过于专制?鉴于许多语言都具备单继承的特性,如果剥夺了一个类继承的能力,就使得程序的设计者多了很多约束。这是否是明智的选择呢?

2、继承自MarshalByRefObject后,效率究竟如何?我曾经做个这样的测试,发现继承自MarshalByRefObject类的对象比没有继承MarshalByRefObject类的对象,在性能上相差了几十倍。PIAB采用Remoting Proxy技术,是否在性能上有所考虑呢?

Gmail的小Bug

有人说本博老是写一些乱七八糟的东西,没有深度。其实是本博太忙,过几天再来深入一下。这几天用Gmail发现一个小小的Bug,不知道有没有其他人有发现:

当附件是rar并且是中文文件名时候

点击Download链接,会下载一个错误的rar文件,解决办法是点一下Forward,然后再点Forward里面的附件,就可以下载到正确的附件,比较了一下2个链接,只差了一些参数,Gmail小组修改一下?

More Posts Next page »