Erucy's blog

Erucy's blog
随笔 - 36, 评论 - 107, 引用 - 1

导航

标签

每月存档

最新留言

广告

2010年03月22日

多个微软Windows版本将在今年内逐渐退出市场,并不再提供技术支持,希望仍在使用这些Windows版本的企业和个人及时更新系统(或者打SP)

这些Windows版本包括:

1、Windows 2000 Pro和Windows 2000 Server,作为已经发布10年的Windows产品,将于今年的7月13日彻底停止技术支持。

2、Windows XP,2001年发布的产品,在SP2及以下的版本将于今年7月13日停止技术支持,用户可以免费升级到SP3以便获得后续的技术支持。

3、Windows Vista,未安装任何SP的Vista将在今年4月13日停止技术支持,用户可以免费升级到SP2以便获得后续的技术支持。

详细信息请参考:

http://blogs.technet.com/lifecycle/archive/2010/02/24/end-of-support-for-windows-xp-sp2-and-windows-vista-with-no-service-packs-installed.aspx

相关资源下载:

Windows XP SP3:http://www.microsoft.com/downloads/details.aspx?FamilyID=68C48DAD-BC34-40BE-8D85-6BB4F56F5110&displaylang=en

Windows Vista SP2:http://www.microsoft.com/windows/windows-vista/default.aspx

posted on 2010-03-22 12:01:33 by erucy  评论(0) 阅读(298)

 
2010年02月11日

又是写书的过程中发现的。SharePoint 2010在日历列表一些比较细节的地方有了不少很不错的改进:

1、在新建一个事件的时候,如果修改了开始时间,那么结束时间会跟着顺延。另外,默认情况下结束时间不再和开始时间一样,而是比开始时间晚一个小时。比如一开始是从8点到9点,如果我们把开始时间改成10点,那么结束时间会自动变成11点。当然这个做的有点傻,比如开始时间是8点,我把结束时间改成5点,之后把开始时间该成10点,那么结束时间会自动变成7点……算法真是一目了然。

2、终于可以直接在日历视图的某一天或者某个时间段上,直接点击添加来在指定时间添加事件了。只需要把鼠标指到这个日期或者时间的空白处,就会浮现一个添加链接,英文版叫“Add”,繁体中文版好像叫“增添”,简体中文版叫“为第二阶段删除的项目添加” @_@,没错,你不是在做梦:

cal2

这一版的翻译可见一斑,希望在RC能改掉(RC已经出了,我还没装)

3、可以在一个视图上显示多个日历的内容了:

cal1

其中绿色和黄色的部分来自两个不同的日历列表,通过下面这个界面进行设置:

cal3

从下面这个界面中我们可以看到,除了支持SharePoint列表之外,还可以显示Exchange中的日历:

cal4

另一个翻译让我比较吐血,这个“解决”在英文版里叫“Resolve”……

还好这些翻译问题改起来也不麻烦,改一些resx文件就好了。在C:\Program Files\Common Files\Microsoft Shared\web server extensions\14\config\Resources\wss.zh-CN.resx

posted on 2010-02-11 21:47:52 by erucy  评论(3) 阅读(1793)

 
2010年02月03日

唔……事先声明,其实这篇文章没有太多实际的使用意义,所以想了解某个东东怎么用的同学可以按Alt + F4(或者Ctrl + W)了。想了解SharePoint里面是怎么工作的同学可以继续往下翻。

最近正在和KB一起写关于SharePoint 2010开发方面的一本书,在研究2010新增加的对象模型的时候,偶然发现了这个方法。我们都知道在2003/2007里面,根据ID获取列表条目使用的是SPList的GetItemById方法(什么,没听说过这个方法?那恐怕你不是一个合格的SharePoint开发人员……)。新增加的这个方法名字叫GetItemByIdSelectedFields(同时也增加了一个GetItemByIdAllFields的方法与之作伴,不过这个和GetItemById是完全等效的,就不再废话了),方法的定义是这样的:

   1: public SPListItem GetItemByIdSelectedFields(int id, params string[] fields)

当我第一眼看到这个的时候,立刻就想到了SPQuery的那个ViewFields属性,获取某个列表条目的时候,只返回某些指定的字段,来提高效率。可是当我写了个Console程序试验的时候,发现并不是我想象中的样子,比如我写成(这个方法要求写内部名称):

   1: SPListItem item = spList.GetItemByIdSelectedFields(1, "Title", "Created");
   2: Console.WriteLine(item["Modified"]);

这段程序居然没有报错,而且Modified的值也正常返回了,于是我试了试,一个自定义列表里面居然有50来个字段的值都正常返回了,但是所有的查阅项、用户和用户组(其实这个本质上也是查阅项)都没有返回。

在好奇驱使下(暂时还害不死我),我Reflector了一下这个方法的源代码:

   1: if(field == null)
   2: {
   3:   throw new ArgumentNullException("fields");
   4: }
   5:  
   6: StringBuilder builder = new StringBuilder();
   7: foreach (string str in fields)
   8: {
   9:   if (str != null)
  10:   {
  11:     builder.Append("<FieldRef Name=\"" + str + "\"/>");
  12:   }
  13: }
  14:  
  15: foreach (SPField field in this.Fields)
  16: {
  17:   bool flag = false;
  18:   foreach (string str2 in fields)
  19:   {
  20:     if (str2 == field.InternalName)
  21:     {
  22:       flag = true;
  23:       break;
  24:     }
  25:   }
  26:   if (!flag && field.MustFetchByDefault)
  27:   {
  28:     builder.Append("<FieldRef Name=\"");
  29:     builder.Append(field.InternalName);
  30:     builder.Append("\"/>");
  31:   }
  32: }
  33:  
  34: return this.GetItemById(id, null, false, builder.ToString());

关于最后那个GetItemById是怎么回事,暂时先不用再去深究了,只要知道它是一个GetItemById的重载,目的就是查找条目用的就行了,最后一个参数把需要获取的字段以CAML的形式放进去。

第7行那个foreach很好理解,把我们需要的字段加进去;但是第15行的那个foreach一开始就有点让人摸不着头脑了,还要把其他字段也放进去?而且SPField的这个MustFetchByDefault是什么东西?再挖挖看看:

   1: internal bool MustFetchByDefault
   2: {
   3:   get
   4:   {
   5:     string fieldAttributeValue = this.GetFieldAttributeValue("List");
   6:     if(!string.IsNullOrEmpty(fieldAttributeValue) &&
   7:        (fieldAttrbuteValue != GlobalList.Docs.ToString()))
   8:     {
   9:       return false;
  10:     }
  11:     return true;
  12:   }
  13: }

如何判断一个字段是不是要取呢?通过判断字段的一个List属性,至于GetFieldAttributeValue方法就不再往上贴了(否则有骗字数的嫌疑),总之它是从Field的类似SchemaXml属性(字段描述)的Xml结点中,去找一个List的属性。如果找到了,而且不是GlobalList.Docs(某个特殊的东东)的话,那么这个字段就不是必须的,换句话说这个字段我就不用返回给用户。

那什么字段的SchemaXml里会有List属性?一个字段里有一个和列表的属性?查阅项!哈,真的是回避掉了所有的查阅项。(Docs这个东西是“路径”这个字段的List属性,估计有某些特殊的来源)

现在我们知道为什么会包含其他所有字段,并且不包含查阅项了。但是为什么要这样?如果我们对SharePoint的内容数据库有所了解的话,我们会知道其实查阅项在内容数据库里只存了一个ID值在AllUserData表里面(但是用对象模型取出来的时候,是包含查阅那个条目相应字段的内容的),这也就意味着,如果要返回查阅项的值,就需要多做一些额外的数据库操作(比如再去找到被查阅的那个条目,把相应字段的值返回来,拼装成“1;#Administrator“这种鬼样子)。更重要的是,如果这个查阅项是一个多值的,那么这个查阅项本身都是保存在另外一个表中的(AllUserDataJunctions),这样要返回起来还真是要费不少功夫。所以2010里面新增加了这么一个东西,如果我们的列表中包含好多个查阅项,而我们可能暂时只用到其中一两个(或者一个都不用)的话,看来用这个方法确实能提高不少效率。

posted on 2010-02-03 00:12:19 by erucy  评论(0) 阅读(1901)

 
2010年01月09日

之前ColldaDec有三个工具,后来网站当掉之后就没有办法下载了,其实一直都想整理一下开源掉,正好有人问下载地址,借此机会发布出来。

当时所有的工具、文档(包括陈曦录的几个视频)和源代码都发布到CodePlex上了:

1、WPManager(Web部件管理器):用于在SharePoint 2007上部署、卸载Web部件,无需编写dwp/webpart描述文件,无需编写manifest,无需手动修改web.config,只需要打开生成的dll文件,选择部署位置,点击“部署”就可以一切搞定。支持dll、cab和wsp三种部署方式。同时支持部分Web部件的卸载功能,同时还有个彩蛋。

发布地址:http://wpmanager.codeplex.com

2、OSSEventManager(事件处理程序管理器):可以方便的在一个列表上部署、挂载、卸载SharePoint 2007的列表条目事件处理程序。

发布地址:http://osseventmanager.codeplex.com

3、Friendly Query:使用类似T-SQL语句的形式进行SharePoint列表查询,无需任何CAML。之前写过一篇blog:点击这里

发布地址:http://fquery.codeplex.com/

 

posted on 2010-01-09 17:15:19 by Erucy  评论(1) 阅读(2515)

 
2009年02月17日

标题党一下。

问题发生在一个文档库(文档模板是“空白页”)中,写了一个Added的事件处理程序,把标题字段改成文件名(不带扩展名的),但是发现新建页面的时候(不是上载)没效果。难道没有捕获到Added事件?

经过单点调试,发现事件是捕获到了,因为里面抛出一个异常导致没有正常执行。

很奇怪的问题:在Added事件中,properties.ListItem居然是null!(ListItemID是0),一般而言只有在Adding的时候才是null(因为Adding时条目还没有真正被创建出来),不知道是不是SharePoint的bug,不知道是不是在某些hotfix更新过了(我对hotfix的跟踪不是很及时。。。),也不知道在其他文档模板的情况下有没有问题。

解决方法是这样的:

   1: using(SPWeb web = properties.OpenWeb())
   2: {
   3:   SPFile file = web.GetFile(properties.AfterUrl);
   4:   SPListItem item = file.Item;
   5:   // do something with the item
   6: }

可以看到,AfterUrl是可以拿到这个新页面的地址的,而且可以正常拿到文件和条目,说明在Added的这个时候条目已经出现了,但是为什么直接用properties.ListItem拿不到呢?有时间的话可以去挖掘一下……

posted on 2009-02-17 17:47:02 by erucy  评论(1) 阅读(4449)

 
2009年02月03日

之前在某个不能使用任何后台代码的项目中开始研究的用javascript去控制SharePoint,略有心得,也曾经在赏梅斋的moss开发群里做过一次和这个话题相关的讲座,记录点击这里

前一阵整理了一下这个项目里用到的一些javascript的方法,并随着后面的几个项目添加了一些新的内容进去,现在发布出来。

地址是:http://www.codeplex.com/SPJsLib

主要是基于jQuery这个javascript库来做的,我做的时候和测试的时候jQuery还是1.2.6版本,现在已经是1.3.1了,在项目的release里也包含了一个1.2.6版本经过压缩的jQuery文件。

使用的时候不需要对jQuery有了解,当然如果了解jQuery的话更快速的实现更丰富的功能。

具体的使用方法参考项目网站里的文档(word 2003格式,中文的,几乎每个方法都有sample code,代码里的注释都是英文的),这里大概介绍一下这个库的作用:

这个JavaScript库大致分成两大部分:

第一部分:访问SharePoint内容

通过AJAX技术(jQuery提供了很方便的跨浏览器的AJAX解决方案),调用SharePoint内置的Web Services,读取、查询、添加、修改或删除列表中的条目。此外还支持了对当前用户的用户配置文件中各个属性的读取(这是某个项目的产物)

比如,下面这段简短的代码可以更新myList列表中所有lookup字段查阅了ID为19的条目的标题(来自文档):

   1: var res = queryItems('myList', "<Where><FieldRef Name='lookup' LookupId='TRUE'/><Value Type='Lookup'>19</Value></Where>", ['ID']); 
   2: var ids = []; 
   3: $.each(res.items, function(idx, item){ 
   4:     ids.push(item['ID']);        // $.each是jquery中的方法,效果类似于C#中的foreach 
   5: }); 
   6: var updateRes = updateItems('myList', ids, {'Title':'These are items lookup 19!'}); 
   7: alert(updateRes.success);

 

第二部分:控制SharePoint表单

这个表单指的是列表的新建和编辑表单,支持的字段类型包括:

单行文本、多行文本(纯文本和带格式的文本)、数字(普通和百分比)、货币、选项(下拉列表、Radio、多选)、查阅项(单选、多选)、时间和日期(仅日期和带时间)、是/否、人员和组(不完全支持)、超链接、图片

提供的功能包括:

1、隐藏/只读字段

2、获取/设置字段的值

3、级联两个选项(下拉列表)类型的字段

4、级联两个查阅项类型的字段

5、为查阅项和选项(下拉列表)提供筛选功能(如果比较多的话选起来会方便很多)

6、从客户端检测字段是否为空(和字段的那个设置无关,甚至可以根据某个字段的设置来决定是否要检查某些字段,文档中有个例子)

7、重定义“确定”和“取消”按钮的行为

这两部分内容结合起来,不用任何C#代码也能够完成很多操作了。当然,最好对javascript有一定的了解(不需要对jQuery有了解,当然了解更好)。

文档中的两张图(查阅项字段的级联和筛选):

clip_image002

clip_image002[9]

只读部分字段的效果:

image

如果有任何问题或者建议的话可以在blog上或者codeplex上反馈给我,欢迎试用(已经在IE6/IE7/FF3.0上经过了初步测试)~

posted on 2009-02-03 01:16:04 by erucy  评论(4) 阅读(6128)

 
2009年01月23日

转载blog都不写来源……

posted on 2009-01-23 14:22:30 by erucy  评论(2) 阅读(6397)

 

新加了不少特性,css的selector也换了一套,据官方测试效率要比以前高不少,之前被人诟病的效率问题看来得到了很大的改进。新增加的live/die方法终于可以在绑定事件的时候绑定到页面所有(不管是现在的,还是尚未被创建出来的)元素了,这样就不用在创建新元素之后再手动去绑定一次事件了。

另外扫了一眼jQuery的UI部分,感觉也有不少可用的,过节时研究一下。

节后计划发布SharePoint的两个js库,一个是用于和列表进行数据交互的(增、删、查、改);另一个用于处理列表表单(编辑和新建表单)中的字段元素(隐藏、只读、设置值、读取值),春节期间要修改、测试一下,然后写些文档。

敬请期待。

ps. 在考虑之前太监了的那个自定义字段到底还要不要继续写完…… T_T

posted on 2009-01-23 14:21:02 by erucy  评论(0) 阅读(5487)

 
2008年12月07日

借MVP之名从微软那里借来了这本书,现在要交个作业(就是写个书评)。

这本书基本上和任何程序设计的概念、算法、语言都没有太大关系,是一本关于“工具”的书;然而和一般的使用说明书不同的是,这本书并非是完整的介绍Visual Studio的使用,而是分门别类地介绍了200多个关于如何更有效率地用好Visual Studio的技巧。古人说,工欲善其事,必先利其器,这本书正是这样一个目的。

书里面介绍的Visual Studio的内容基本上是基于VS2005的,当然在VS2008里基本上也都有这些内容,有些技巧在VS2003中也可以使用。不过有一点需要注意的是,这些技巧是基于英文版的VS的,中文版有个别内容有一些出入(主要是快捷键有些不同)。

本书的作者Sara Ford是VS这个产品组中的一名测试人员,因此对VS有比较深入的理解,这本书中的内容实际上是从她(没错,是“她”)的博客中整理出来的。书中除了这些技巧之外,在附录中还有一些关于VS的8g(比如为什么程序的名字不叫vs.exe或者visualstudio.exe而是devenv.exe)、作者关于软件测试的一些心得、作者的编程经历(里面居然还有任天堂的红白机……)。此外,作者还很“狡猾”地在整本书的最后(附录后面)写了第252个tip,要知道,就连封面上写的都是(251 Ways to Improve Your Productivity),作为完整看完整本书的“奖励”,嘿嘿……

书中关于vs的技巧大致划分为如下几个段落:

1、代码编辑器。这里面主要是关于Editor这个开发人员接触最多、也是作为IDE来说vs最核心的一部分内容。这部分是和我们日常code关系最为密切的。

2、高级编辑功能。依然是在围绕代码编辑器的介绍,比如关于选择、注释、格式化代码、打开文件、书签、智能标签、代码片段等内容。

3、搜索。这个也是在开发过程中使用很多的一个功能,对于分析其他人的代码有很大的帮助。

4、应用程序布局。包括了文档工作区、工具栏窗口、窗口布局、工具栏和上下文菜相关的一些技巧。

5、工具栏窗口相关的技巧。包括命令行窗口(Command Window)、输出窗口、工具箱、任务列表窗口、对象浏览器的技巧。

6、关于对话框的一些技巧。比如外部工具、搜索对话框、开始页(Start Page)的一些技巧。

7、关于解决方案(Solution)、工程(Project)和调试相关的技巧。

其实书中的很多技巧都是关于如何更高效的使用VS(通过快捷键)、如何通过设置来改变VS默认的一些行为的技巧,也有一些技巧对我来说是很有用的,能够真正使用到日常的开发中(有意思的是,当我把其中一些技巧告诉周围人的时候,对方说:“你才知道有这个功能?”,呵呵)。举几个印象比较深刻的例子:

1、循环剪贴板。其实这个功能在菜单里就能看到,不过可能很多写代码的人都不怎么看菜单吧,尤其是“编辑”菜单。用Ctrl + Shift + V就可以使用循环剪贴板。有点像是office里的那种,Ctrl + C的时候把内容复制到一个循环队列中,队列长度是20,也就是说循环剪贴版中可以存下最近20次的“复制”或“剪切”操作的内容,当然20次也足够用了……

2、Ctrl + I的快速搜索。同样在菜单里就有,同样之前没有关注过。不用任何对话框、工具栏就可以在当前打开的文件中做搜索,很有意思,建议大家自己试试。

3、在当前行的任意位置Ctrl + Enter在上一行插入空行(Ctrl + Shift + Enter在下一行插入空行)。这个看似很简单的功能,但是对于提高coding效率还是相当有用的一个技巧。比如一般当我写代码块的时候,都是写完一行(比如for、foreach、if或者函数名)->然后敲入一对完整的大括号->然后把光标往上移动一行->移动到行尾->按回车,现在这个操作一次就可以完成了。在整理代码的时候也很有用。

4、Ctrl + L剪切当前行、Ctrl + Shift + L删除当前行。其实我之前知道有这个功能,不过没记住快捷键……

上面这些都还只是第一章中第一节里面的内容,后面还有很多有用的、有意思的小东西。看完这本书之后,我觉得Visual Studio这个IDE真是博大精深,很多功能如果不是在这里面写出来,恐怕我一辈子都不知道居然vs还能这么用,留给我印象最深刻的就是工具栏上的那个搜索框:当输入一些文字之后,按回车,会在当前打开的文件中从当前光标位置向后搜索内容,并选中第一个搜到的内容(估计用过这个玩意儿的人都知道);输入一个数字行号,按Ctrl + G,就会跳转到这一行;输入工程中的一个文件名,按Ctrl + Shift + G,会打开这个文件;输入一些内容,按F1会打开帮助搜索这段内容;输入一个函数名、按F9,会在这个函数上加上断点;输入大于号,后面可以使用vs中的一些命令,比如File.OpenFile……

我不知道这本书会不会引进到中国甚至出中文版,不过我想如果你每天有超过2、3个小时的时间都是在和Visual Studio打交道的话,那么建议你去读一下这本书,即使你的英文不算太好,读起来也是很轻松愉快的。

posted on 2008-12-07 21:29:23 by erucy  评论(4) 阅读(8753)

 

今天才有空继续写这个,之前出差了一周……

不过第二天可写的内容没有那么多了,主要是在讲Live Mesh(就是类似于基于网络的“我的电脑”)的应用和开发。

Live Mesh目前分成两个版本,公开版(www.mesh.com)和开发版(url忘了,似乎有个ctp什么的),开发版需要有专门的Key才能在上面做开发(于是讲课后每人发了俩key),每人5G的空间。

简单的操作和“我的电脑”很类似,新建文件夹、上传文件,目前似乎只支持图片的预览,其他格式的内容的查看似乎都不支持(包括纯文本)。其实这部分的功能主要还是各个设备之间的同步,当场演示了用智能手机拍了张照片,然后通过gprs网络自动同步到mesh上,然后也自动同步到电脑上,然后通过电脑修改之后再自动同步回mesh上。另一个作用就是文件共享和协作,可以邀请一个email地址或者live的账号来分享文件。

另外Mesh现在也支持一些应用程序,现在上面已经有一些简单的应用程序可以用,比如桌面贴、填字游戏之类的,当然也都可以支持共享和多人协同的操作。

关于开发部分,主要就是通过一个Resource Explorer可以观察到mesh里面的内容(包括联系人、mesh的文件夹和文件、应用程序等等),可以通过xml或者json的形式来返回结果。其实编程从底层上就是向一个url发送一个请求(GET或者PUT),然后返回一段xml来进行信息的查看、增加或者修改。当然,外面也包了一层API可以直接用。

从两天的培训来看,Live Services这套内容主要还是偏向个人应用(尤其是Mesh),可以一定程度上进行少数人的协同工作。当然,Live ID集成这套东西似乎还是比较有作为的。而且目前这些云端服务器都在美国,网速是一个很大的问题。

posted on 2008-12-07 20:38:21 by erucy  评论(1) 阅读(6473)

 
2008年11月27日

微软最近正在大力推广live services这一套东西(在TechEd中也占了不小的比例)

这个Jumpstart貌似是一个全球的培训活动,北京这边是2天的课程,包括session和HOL,讲师是总部live services team来的

Part 1. Overview

第一节课比较困,不过基本上都是在show一些demo,概念也不是很多。总的来说,live services的目的就是将用户(Users)、设备(Devices,比如PC、Mac、Mobile、XBox之类的)、应用(Application)整合起来。

用户体验到的是Hotmail、Messenger、Live Mesh这样的应用;开发人员面对的是Live Framework(这个明天讲)。而现在的开发人员还是在做一些底层的比如用户系统、目录、存储管理、通讯管理这样的基础架构,到Live Services中这些都由微软提供了,开发人员可以更加关注业务和用户体验。

目前有一个开源的项目是完全用live services构建的:http://www.adventureworksresorts.com

Part 2. Online Identity(其实就是LiveID)

首先就是一堆概述,比如为什么要用LiveID之类的(号称是全球最大用户数的身份验证提供方,可以安全、稳定的提供用户身份验证服务,且免费;目前有很多应用都是以LiveID作为身份的——当然,基本上都是微软的应用)

当然,这里面提到LiveID的意思是说我们可以在自己的应用中使用LiveID作为身份验证服务,也可以将LiveID和已有的验证服务(比如AD之类的)集成起来。在身份集成的APPZ(Authentication, Policy, Profile, Authorization,又是一个拼写的噱头)中,LiveID负责解决Authentication、Policy和部分Profile的问题。

将LiveID集成进我们自己的应用的另一个好处就是安全,所有的登陆操作都在live.com上完成,用户不再会担心网站会保留我们的live的用户名和密码用来做其他一些事情(似乎有些网站就是要直接输入live的用户名和密码的……),所以他一再强调一定不要在不是live.com的网址上输入live的用户名和密码。

LiveID的集成方式主要有三种:

(1)Web Authentication。这种方式基本上就是在我们的页面中嵌一小段html代码,用于显示登陆(或退出登陆)的按钮(或链接)。这种方式基本上就是和传统的第三方验证提供程序一样的工作原理。需要在live services中注册一个AppId,同时指定这个AppId对应的domain,live在做验证的时候会检查跳转回去的地址,如果不是注册的domain的话,就不允许,以放置信息被窃取。这种方式登陆后会返回一个token,这个token是根据AppId、UserId、时间戳和签名加密成的。在界面上,这种登陆方式是跳转到live.com上进行用户登陆,但是这个登陆页面是允许用户进行部分的修改的(通过一段xml上传到live services中),比如css。这个方式最为简单,只是纯粹的身份验证,我们的应用可以直接使用token解析出来的userId作为用户身份的标志。

(2)Delegate Authentication。这个方式要更复杂一些,可以在网站中获取更多关于用户的信息,比如用户的好友列表(Flickr现在似乎就支持这个功能)、用户的照片库之类的。

(3)Client Authentication。客户端程序的验证,验证的时候直接弹出一个Live的控件输入邮箱和密码(有点像msn的登陆界面),登陆后就拥有了这个live的身份,可以无缝的和微软其他的live应用集成(比如通过接口直接发space的blog之类的)。

然后现在LiveID正在(或者已经?)作为OpenID的一个提供方,凡是可以用OpenID作为身份认证的应用,都可以使用LiveID,这个他做了一个demo,不过没有成功……

Part 3. Communication

这部分主要介绍的是Messenger的lib(javascript的),通过这个lib,可以在我们的页面上嵌入一个小型的messenger。我做的HOL里有一个这个,不过非常简单,只是登陆后显示用户名而已,不过是纯前台的,没有任何后台代码。(当然,登陆也是要先跳转到live.com上)另外,也有服务器端的Messnger控件可以用,使用起来更方便一些,拖上去配置几下就行了。

其余的还有可以在应用中做自己的alert(可以通过msn消息做提醒,不过这个似乎要经过微软验证和授权);还有自己的基于msn的p2p应用,叫做Activity(比如写个小游戏之类的,底层通讯是走msn协议,但是不经过服务器),但是目前不支持2人以上,而且同样要经过微软的检查和授权才可以最终发布。

Part 4. Virtual Earth

这个似乎没啥新鲜的东西了,和google那套差不多。不过接口更开放一些,而且可定制的东西更多(可以自己定义3D模型放在自己的地图上),有一大堆服务器端控件可以用,js的似乎也有(记不太清楚了)。现场做了一些demo,比如嵌入一个地图(居然显示了实时的天气情况,3D的,云层,很酷……);西雅图的建筑基本都3D话了,可以直接在里面walkthrough;在自己的应用中设定起点终点,然后画出行车路线图。

有人问这个和google嵌入应用的区别在哪里,他说主要在于license方面、3D方面等等。

Part 5. Live Search

主要就是一些开发接口,同样需要去注册一个appID,然后就可以通过形如: http://api.search.live.net/xml.aspx?Appid=xxxx&query=xxxx这样的request直接取到搜索结果;当然这是xml形式的结果,还有其他形式的通过不同的页面,比如json.aspx

posted on 2008-11-27 00:00:46 by erucy  评论(1) 阅读(8641)

 
2008年11月23日

之前我们分析了为什么一个简单且看似合理的SPD工作流循环为什么有可能在执行过程中跳出循环的原因,我们的目的在于让这个工作流变得更加稳定。

当一个工作流无法正常工作的时候,可能就会需要其他工作流的帮助。一个人干不了的活,大家一起干。我们需要有另外一个工作流实例,来对第一个工作流进行“监督和提醒”。另外一个工作流即可以放在同一个列表上(因为它们是不同的模板,可以同时产生两个不同的实例),或者另一个辅助列表上。放在同一个列表上在列表设计上比较简单,但是因为同时有两个不同的工作流实例在运行,分析和工作流设计要格外小心;放在多个列表上的话,每个列表上只运行一个实例,通过一个字段关联起来,逻辑上更容易分析,但一旦涉及到迁移和部署就会非常麻烦(见老赵的这篇文章)。为了做测试,我先把所有工作都堆在一个列表上。

思路是这样的,工作流两个模板分成工人和监工两个角色,工人负责干活(执行具体的操作),监工负责提醒工人。工人执行完操作之后,告诉监工“我干完了!”,然后监工说“哦?那么你可以先休息一下”并且在到点之后提醒工人说“嘿!该干活了!”。实际上,这是两个工作流实例互相触发的过程,并通过一个标志位决定目前是工作者应该执行操作,还是监视者执行操作。当然,为了避免之前所说的“触发在退出之前发生”的情况出现,两边都要有一个确认时间段,等待另外一方结束后自己才开始运行。

这两个工作流的设计如下:

首先是工人:

image

然后是监工:

image

其中的Mark就是标记为,决定哪个工作流应该运行,初始值设置成true。执行过程是这个样子的:一开始两边都触发,但因为Mark为true,所以工人开始,监工退出 –> 工人先休息5分钟(偷懒一下) –> 设置标记,触发监工运行 –> 干活后退出 –> 监工被触发后(以为这个实例的触发是由Mark = false引起的,所以监工必然继续运行)先休息5分钟(等工人把活干完并且工人实例退出) –> 设置标记,触发工人实例 –> 工人被触发(同理,它是被Mark = true引起的,所以必然继续运行) –> 休息5分钟(这5分钟的目的就在这里体现出来了,它是在等待监工实例的退出,否则如果监工因为尚未退出没有被工人的后续操作触发,而且工人自己的实例也出现触发早于退出的情况出现时,那么就没有人提醒工人继续工作了) –> ……于是可怜的工人就在监工的控制之下不断地开始计数了。

我们以工人实例的5分钟休息和监工实例的5分钟休息作为代价,换来了两者互相触发的稳定流程。所以这一方法理论上的计数间隔时间是10分钟,据我测试实际时间平均在15分钟左右。

可以高枕无忧了吧任其运行了吧,还不能!为什么呢?在实际的应用中,除了这两者互相触发之外,还可能由用户去修改这个条目,从而唤醒那个已经停止了的实例。让我们来分析一下可能出现的局面:工人正在睡觉(等待监工退出),此时监工已经做完了本职工作退出 –> 就在工人睁开眼睛,准备提醒监工(设置标志位)之前,某个外来用户做了个更新,当头一棒叫醒了监工(因为工人正在运行,所以没有新的工人实例出现) –> 监工懒洋洋地睁开眼睛,发现现在还不应该工作(标志位尚未被工人更新),于是打算退出 –> 而就在监工从醒来发现没有活干到退出的这一段过程中,工人完成了本职工作(设置标记位、计数) –> 这样一来,由于在工人干活的时候监工还没有退出所以新的监工实例没有出现,如果工人干完活退出前就发生了自我提醒的事情(自我触发发生在退出之前),也不会有新的工人实例出现!于是,两个人因为外来者的干扰同时结束了工作,没有人负责计数了!

好吧……我承认这种情况非常极端,我在测试过程中同时开了个Console每隔1-60秒随机更新一下条目作为外部干扰,在流程跑了一整个晚上之后仍然在正常运行(已经计数了31次),但是从理论上来讲,上面的这种情况是仍有可能出现的(如果实例退出时间 > 工人所有的实际操作时间)。为了避免这种情况的出现,我们需要在两个工作流中再次加入等待流程,等待又用户外部干扰产生的意外唤醒退出后再向下执行。

我没有具体做实验,但是设计了这样一种编排方式:

image

在工人中,将Mark标记设置放在暂停之前,以便提前触发监工;监工等待1天让工人干完事情,然后设置标记触发工人,等待5分钟后再做一个HeartBeat(随便更新一个字段)。监工的5分钟和工人的2小时都是为了避免另一方因为外部操作而被唤醒。我们可以讲用户外部操作这个动作插入上述流程中的每个操作之间,来分析外部操作究竟是否会影响到整个计数流程的进行。因为情况比较多,我就不在这里一一分析了。需要保证的是,监工的第二次暂停必须远小于工人的暂停(因为触发是不规律的,要留一个比较大的浮动范围),同时工人的暂停也要远小于监工的第一次暂停。这个流程理论上的计数间隔是1天零5分钟。

文章在这里得到了一个相当复杂,但几乎cover了所有情况的一个解决方案(我说几乎是以为我在做设计时脑袋都大了,不知道是不是漏过了什么信息)。如果各位看官有更好的解决方案,也欢迎在后面留言。

ps. 这个玩意儿在我这边的实际项目背景是这样的:有一个列表,每个条目都有一个RAG(Red, Amber & Green)状态字段,根据不同情况的不同Date Due,在Date Due内RAG状态为绿色;再过一个月之内,RAG变成黄色;超过一个月后RAG变成红色。可以说这是比较常见的一个应用,但之所以采用SPD工作流的方式进行循环触发的原因,首先是客户不允许编写后台代码(否则timerjob轻松搞定这个需求);其次,SharePoint的计算字段中不能采用Today公式,换句话说SharePoint的计算字段不是在取值时计算,而是在条目更新时计算的(所以就算像某些文章中提到的那种hack方法在公式中加入了Today,也只是相当于上次修改的日期)。

posted on 2008-11-23 13:09:26 by erucy  评论(0) 阅读(4401)

 

作为SharePoint工作流的一个重要编写工具,SPD(SharePoint Designer)以其良好的界面拖拽方式和较为丰富的逻辑、动作越来越多地被用于实际项目的开发应用中。它比SharePoint内置的若干工作流更为强大,功能更完善;而又比Visual Studio的工作流更为简单,几乎不需要了解什么关于WF的知识和概念。

然而,SPD也有很多不完善的地方(这也是VS工作流的生存空间),例如SPD工作流是一个串行流程,换句话说它是一个顺序工作流,而不是一个状态机工作流(虽然它也可以通过某些方式实现状态机工作流的功能,但这不在本文的讨论范围之内);又比如说它不支持循环,即满足某些条件的时候跳回到之前的步骤重新执行——这正是本文要解决的问题。

其实很多文章都提到了关于SPD工作流循环的问题——当然,那些文章的目的是要避免工作流的循环和死锁。先来看一下为什么工作流会产生循环死锁。例如,我们在SPD工作流中设置了当条目变更时自动启动,然后在流程中修改了当前条目的某个字段——于是,这一修改再次自动触发了这一流程,于是工作流开始循环。这是最为简单的一种循环的触发形式,更多的形式比如一个条目的两个工作流互相触发、多个列表之间的工作流互相触发等等。

在那些文章中也都提到了要如何去避免这一循环,其实很简单,加上一个标记位就可以了,用于标记当前这一条目变更是由工作流本身引起的,还是由用户的操作所引起的。在进入工作流第一步,就要先判断这个标记位,如果当前的变更是由工作流引起的,则直接结束工作流,从而避免循环;否则,进行应有的操作,并且在操作后(或前,没有影响),将标记位设置成工作流变更。当然,这一方法需要在用于操作的时候,讲标记位恢复成“用户操作引起工作流”,以便正常触发SPD中的流程。

于是我们不禁想到,这一循环触发的特性是否能够被我们用来进行循环的设计。答案是肯定的,也有若干文章提到了这一点,具体的方法就是在流程中更改当前条目即可。

接下来,我会用一个自动计数的场景来分析一下SPD工作流究竟应该如何进行循环。自动计数的场景非常简单,就是每隔一段时间将条目的某个字段的值自动增量,这用到了SPD中的一个暂停功能、计算功能以及给字段赋值的功能。

我们先来看一下在那些文章中是如何实现这个循环的,SPD工作流的流程如下(当然不要忘了设置成条目变更时自动触发):

image

先来简单的解释一下这一流程,工作流开始的时候暂停5分钟作为计数的间隔,接下来将计数字段进行增量,存储到工作流变量中,然后讲这个变量重新赋值给计数字段。很简单的一个循环,不过先来分析一下其中的一些细节:

(1)关于暂停时间。我们将暂停时间设置为5分钟,但真的就是5分钟就会触发一次么?经实际测试,触发的时间大约在10-20分钟内不等,即使设置成1分钟,也是这个触发几率。一方面,这是由于工作流的默认timer间隔就是5分钟,并不会那么精准的触发;另一方面,这是由.Net 3.0中工作流的一个bug造成的,微软也给出了补丁(见这里),但实际上这个补丁解决的问题是暂停后不再触发的问题。目前我还没有找到能让实际暂停时间缩短到10分钟之内的方法……

(2)也许我们会有一个疑问:为什么先暂停后计数?这和我们常规的思维有些不同,我们通常会觉得应该先计数后暂停,毕竟计数才是这个工作流应该完成的“本分工作”。这个具体的原因我们先放在一边,先看看这个工作流执行的具体状况。

实际测试中,这样一个5分钟间隔的计数器可能跑了大约1-5次之后就停掉了(工作流完成),我做的另一个20分钟间隔的计数器最多的一个条目在运行了15次后也停掉了,于是我做了一个没有间隔的计数器(去掉暂停的步骤)在运行了76次之后也停了……为什么?这个循环中有问题么?

在这里,必须要先明确一些和SharePoint工作流相关重要概念,即工作流模板、工作流关联和工作流实例。所谓的工作流模板就是我们设置的一套规则,工作流如何如何运行,根据什么条件进行分支,进行什么要的操作;工作流关联指的是工作流模板和具体列表、列表条目的绑定关系,即这个工作流在哪个列表上运行;工作流实例是一个工作流模板在一个列表条目上开始运行后产生的实例(用虽然有些偏差但更容易理解的另一个说法,模板相当于类,而实例相当于对象)。SPD设计的工作流实际上是同时完成了模板和关联的操作,开始运行后产生实例。一个非常关键非常重要的地方在于,一个工作流模板关联在一个列表条目上之后,同一时间内只能有一个实例在运行。当已经有实例正在运行的时候,任何操作都不会触发新的实例。

这就解释了我们为什么要把暂停放到最开始的原因。看吧,如果暂停放在最后会怎样:开始计算、复制–>条目变更 –> 试图触发新的工作流实例 –> 引擎发现当前实例还没结束(因为进入了暂停状态,这个实例在睡觉!)所以这一触发被忽略掉 –> 暂停结束,没发生其他的事情 –> 工作流完成。于是这个计数只是在我们修改的时候增量了一次就结束掉了。

但是这依然不能解释为什么暂停放在最前面也会出现工作流停止,退出循环的问题。据我猜测(没有经过证实,但是和Kaneboy讨论后得出的这个结论)是因为工作流的完成需要一定的时间,换句话说,我们应当在头脑中给每个工作流的最后加上一个“退出”的操作,用来结束掉当前的工作流实例。因此,上面那个计数器在运行时就会变成:暂停(当前实例在睡觉) –> 睡醒了,开始干活 –> 计数,条目变更 –> 慢着!事情就在这里出现变化了。这个时候因为条目有了变化引擎想要触发新的实例,但是旧的实例正在退出,究竟是退出快还是触发快?如果退出发生在触发之前,那么触发的时候因为没有实例在运行,新的实例就会顺利产生,进入下一轮计数;如果触发发生在退出之前,那么触发时仍有实例在活着,引擎拒绝生产出新的实例,等到旧实例退出后,工作流就完成了,计数停止。

看!这个简单的计数器并不一定能如我们想象那样的顺利运行。目前我在一台服务器上运行了一个时间间隔为一天的工作流(实际应用中,我们一般也都是以天为单位来工作的),不知道能跑多少天。

文章写到这里并没有结束,因为我们的目的并不是分析它为什么停止,而是要设计出一个不会停止的循环。(就像你对客户说,我知道这个地方为什么出错了!但客户并不会因此就付给你钱,客户的目的是要你做出一个不会出错的东西)

posted on 2008-11-23 12:01:36 by erucy  评论(0) 阅读(4672)

 
2008年11月14日

貌似终于要支持webpart可视化开发了,虽然还是通过load userControl的方式,相当于内置了QuickPart。剩下的几个特性都很让人期待。

This week at TechEd EMEA in Barcelona,  Jason Zander, the GM for Visual Studio, announced and demonstrated the Visual Studio 2010 tools for SharePoint.  Here's a quick summary of what he showed:

  • Server Explorer for SharePoint viewing Lists and other artifacts in SharePoint directly inside of Visual Studio

  • Windows SharePoint Services Project (WSP file) Import to create a new solution

  • Added a new web part project item and showed the Visual web part designer which loads a user control as a web part for SharePoint

  • Showed adding an event receiver for SharePoint and using the wizard to choose the event receiver and to just create a source file with that event receiver.

  • Added an ASPX workflow initiation form to a workflow project and showed how this workflow initiation form has designer capability

  • Showed the packaging explorer and the packaging editor which lets you structure the SharePoint features and WSP file that is created

You can learn more on Channel9 and the Visual Studio 2010 homepage.

原文地址:点我

posted on 2008-11-14 11:28:50 by erucy  评论(0) 阅读(4549)

 
2008年11月11日

这次TechEd我和老侯讲的Session,在MVP Community Cabana,和其他几个同等类型的session相比起来听众不多

把大致内容和demo的截图总结一下,算个记录,也给没机会去TechEd的留个东西,另外给我们的一些组件做个广告

言归正传,这个Session的表面上的主要内容是应用WSS构建数据跟踪(Data Tracking)类型的协作应用平台,实际上是通过自定义字段类型来拼装SharePoint应用。首先这个应用平台的两个限定词先解释一下:

1、数据跟踪类型的应用,其实按理说应该是叫数据流类型的。基本上就是以数据流转为主的协作应用,比如场地预订、图书借阅之类的

2、协作型应用,也就是说是由一组人或一些角色来共同完成的应用。比如小组、部门或企业内部的。

微软将应用平台按照类型划分为大概如下几种:Lists(由简单数据表构建的数据存储)、Tracking application(数据跟踪类型)、Mini LOB application(简单的小型业务系统)、LOB(Line of business) application(企业核心业务系统)。按照其应用的数量(横轴)和构建复杂度(纵轴),微软给出了这样一张图:

image

数据列表类型的应用虽然构建简单,但占据了大量的数量(例如联系人、通知、讨论、简单的文档共享灯);企业核心的业务系统虽然构建复杂,但应用的数量相对非常少。

先来看看一个应用的组成部分,以及SharePoint在这些部分中的优缺点:

(1)数据结构定义。SharePoint的列表是一个很好的容器,虽然其存储能力有限,但一般来说足够满足一些日常的应用。而且SharePoint列表也如同数据表一样,内置了多种数据类型,并且包含了一些构建应用基本的“应用字段类型”,例如超链接、选项、查阅项等。

(2)视图。SharePoint内置的列表视图功能比较完善,支持数据列的选择、筛选、排序、最大两级的分组等等。不过SharePoint视图没有权限,难以通过视图控制不同角色的查看。

(3)表单。SharePoint列表创建出来之后,会自动生成3个相应的表单:查看、新建和编辑。但是表单的样式、字段的样式都是固定的,即使通过SPD,能够做出的修改也非常有限,难以适应用户多样的需求。

(4)权限管理。SharePoint在发展到WSSv3之后支持到条目级别的权限。但是不支持字段级别的权限,这对于应用来说比较麻烦,难以控制某些字段哪些人可见、哪些人可以编辑。

(5)业务逻辑。SharePoint列表只是一个容器,应用的逻辑一般都需要开发或配置来完成。好在列表的工具栏、下拉菜单都提供了方便的扩展特性,可以加入一些自定义的操作。事件处理程序、工作流也可以在一定程度上满足对条目在逻辑方便的控制。

WSS作为一个以协作为主要目的平台,经常被用于进行文档管理、知识管理、简单的内容共享的应用(也就是对应Lists类型的应用);而且大多数用户都希望SharePoint能够方便的完成复杂一些的协作型应用(也就是图中第二个层次的应用,也是这次session的主要议题)。然而在使用中,我们会发现SharePoint虽然提供了很多方便的特性,但在某些关键方面难以满足我们的需求,无法通过内置功能的拼装达到我们的目的,需要进行二次开发。而这个session的主要目的,就是通过一些开发好的自定义字段类型组件,来方便、快速地拼装出实际的协同应用平台。

自定义字段类型我就不再过多地介绍了,这是WSSv3新加入的特性,极大地扩展了对列表的开发余地。通过自定义字段类型,可以根本地解决表单多样性的问题、从一定程度上解决字段级权限控制和业务逻辑的辅助。

后面就是通过我们一些已有的自定义字段类型,来完成一些特定的功能,最后给出一个由自定义字段类型拼装完整应用的例子。

先来看几个简单的例子:

1、内容类型图标。内容类型也是WSSv3新加入的一个特性,允许我们在一个列表中放置不同结构、同样目的的内容。一旦在列表中开启了内容类型的控制,就可以创建多种内容类型的条目,但是这些条目在列表视图中很难直观地区分开来(内置的方法只能通过显示“内容类型”这个字段来区分,当然,文档库的文档类型图标是一个例外),于是通过这个自定义字段类型,就可以给不同的内容类型设置不同的图标(在视图和新建菜单中),使得应用看起来更加直观和专业。(目前这个图标还可以控制点击后的行为,比如进入查看页面、编辑页面等)。

image image

2、外部图片。在WSS上做新闻编辑或者图片插入的话非常头疼的就是图片上传和图片插入的分离(如果在MOSS上,还可以用发布功能里的那个插入图片来顶一下)。这个字段就是利用一个高级编辑器(FCKeditor)的二次开发接口,将图片的浏览、上传放到了网站的图片库中(第二张图是在浏览网站的图片库,并且可以将新图片从本地上传到图片库中)。

image image

3、Email地址。这个很简单,就是在单行文本的基础上加了Email格式验证,虽然原理和实现都很简单,不过却很有用。

image

4、设置字段的隐藏和只读。这是一个比较复杂的自定义字段,可以根据条目中某个字段的值、当前用户等内容进行一个复杂的表达式计算,来控制某个字段是否显示,或者是否可编辑。

image

5、密码字段。这个没截图……就是在显示、新建、编辑密码的时候打上马赛克,并且在储存的时候用某个私钥进行加密。新建时候要求输入两次,编辑的时候需要输入原密码以及两次新密码。

之后,通过一个完整的会场预订的应用,展示了如何通过自定义字段类型,来快速地拼装这种协作型的应用:

首先,一个会场预订的功能必然会有一个会场的列表。使用一个自定义列表来创建会场列表,包含了会场的标题、所在区、所在酒店和一些相关信息。

1、在很多地点相关或者类型相关的字段中,我们往往能够希望两个甚至多个下拉列表框能够互动,比如说当选择“北京”后,列出北京的区域;选择天津后,列出天津的区域。这可以通过一个自定义字段类型来完成,相关联的父字段、关联的内容都可以灵活定义:

image image

2、作为相关内容,一个场地肯定会有多条相关内容。这也是在应用构建中非常常见的一种主-子表类型的表关联,通过一个外键进行关联。在SharePoint中,查阅项的作用与此非常类似,可以在子表中设置一个指向主表的查阅项(外键)。然而这种查阅项有时是非常不直观的,只能在子表中看到其条目属于哪个主表,难以看到主表条目中有哪些相关的内容。通过一个“反向查阅项”(或者主-子表字段)类型,就可以实现这一功能。设置可以在主表的编辑页面中,直接新建、修改、删除相关的子表字段:

image

实际上这个相关内容是保存在另一个列表中,有一个指向“场地列表”的查阅项。主表编辑页面中的新建、编辑页面直接使用了子表的新建和编辑页面,只不过做了一些小的修改(在表单打开时自动初始化查阅项指向对应的主表条目)。

3、预订场地通过另外一个列表来实现,可以直接进入这个列表新建列表条目,然而更直接也更友好的方式,就是直接在场地列表中对“心仪”的场地进行预订操作(在列表界面和条目界面都可以进行操作,直接转入场地预订列表的新建页面):

image image

4、场地预订列表中为了标示预订的场地,会设置一个查阅项指向场地列表。但如果出于某种考虑,希望讲场地列表和场地预订列表放在不同的网站上(例如场地列表在资源网站上,由资源管理者统一管理;而场地预订列表在会议网站中),就需要借助另一个自定义字段,跨网站查阅项。这个自定义字段和查阅项的功能基本相同,只是SharePoint内置查阅项只能查阅同一网站中的列表,而这个可以跨网站查阅,并且可以指定一个视图做初次筛选(以免查阅项中出现的内容过多难以选取)。(其实跨网站查阅这一功能在SharePoint查阅项中是提供了的,只不过没有开放到界面上)。它的设置界面:

image

5、所有资源预订类的应用都必然有一个需求,那就是冲突检测。一般的做法是将冲突检测放在事件处理程序中,如果有冲突则抛出异常,不过这不够方便,如果能够在填写场地、时间的时候就能实时地检查是否有冲突,那是最好不过了:

image

这是一个挑战想象力、颠覆传统的自定义字段类型,按照惯常的思维方式,列表的字段一定是作为某一种特定的数据存储之用的;然而,这个“时间冲突检测”的自定义字段类型,不保存任何数据,仅是在新建和编辑页面上出现,提供一个操作。

好了,现在我们可以看到这些场地预订的情况了,日历视图能够让显示更加直观:

image

6、最后,一个预订系统必然要有的一项就是管理员的审批操作。“好,这个地方这段时间就归你了。”/“不行,这个地方要留作它用。”管理员的选择无非就是这两种。当预订较少的时候,管理员可以直接通过SharePoint的审批视图依次查看每个条目进行审批;但一旦条目多起来,偷懒的管理员(懒是世界进步的动力,嗯嗯)希望能够一次性审批多个条目。“要是能像邮箱那样给个多选框,让我选中要批准的,再一点鼠标,就全部搞定该多好。”于是又一个自定义字段登场,它同样只作用于展示层,不保存任何数据:

image

配合这个自定义操作,管理员就可以有更多的时间来……咳咳。

至此,一个完整的会场预订功能就拼装出来了。尽管它有一些简单,但是基本上包含了一个数据流转的协作型应用的所有步骤了。而且在这个应用拼装的过程中,除了最后为真正完成多项审批而编写的10行左右代码,整个过程中几乎没有任何代码操作,完全通过自定义字段类型和其他一些webpart的配置就达到了目的。这极大地方便了管理员的操作,于是IT Pro们就有更多的时间用来聊天灌水了(这不是我,嗯,我不是IT Pro,嘿,说你呢……)。

当然,最后这个应用里有一些小trick,比如如何改变列表条目的下拉菜单、如何改变工具栏菜单。当然,你说可以通过feature来做,但是这个demo中的这些菜单没有一个是通过feature完成的。为什么?因为feature只能挂在某中列表类型或者内容类型上,麻烦……至于是怎么做的,等今后有时间再慢慢介绍。

这些自定义字段类型,我们迟早会发布出来,有些简单的可能就直接free了。请关注公司网站:www.servbus.com,或者直接给我发邮件:duwei@servbus.com。(打到技术blog的广告行为……)

posted on 2008-11-11 23:25:50 by erucy  评论(0) 阅读(18394)

 
2008年11月08日

总的来说这次缩水比较严重,普通session从2天半减到2天,而且场地也变小了,与会者的伙食变差(讲师的还凑合),会场上提供的水到后来就不够用了(speaker room的也没了)。而且这次OFC课程比较少,SharePoint课程也比较少,没有混到课,于是只好借MVP名义报了一节Community Cabana的Session,地方超小,还没有书包送 >.<   等明后天把这个session的内容整理一下发上来,当然也是sharepoint相关的,和侯总一起讲的。

这次会议的几个着重点在于几个新东西:SQL Server 2008、Hyper-V和虚拟化部署(这个课超多)、Azure Service(所谓的云计算)、VS2010(这个名字的叫法很有意思,一般国内team的speker都念成“二零一零”,今天Colin Yu念成“两千零十”,一看就是平时英文说的比中文多的,哈)、一点点windows 7,还有一些不太新的东西,比如UC。剩下的session大都是在炒冷饭,比如我们的……

因为第一天有session,前面在准备,后面在处理一些公司事务,所以第一天就晃过去了。

今天两节印象比较深刻的session,一个是Hyper-V,一个是Colin Yu的Dublin + .Net Services + SharePoint。

Hyper-V从win server 2008出来后已经挺长时间的了,是微软做虚拟化部署解决方案中的一个重头产品,今天我听的那个session是王……(忘了,英文名是Phoenix)和万网的范总,关于虚拟化部署的最佳实践以及SQL Server 2008在虚拟机上的性能分析。基本结论就是hyper-v很牛,很考验服务器(建议配置都是什么16核、32-64G内存、iSCSI存储、3块以上网卡的服务器……)。从性能上来讲,一个相当于0.8个核的虚拟机cpu(就是一个8核系统跑10个虚拟机)相当于T2300 1.6G的双核CPU的性能;内存相当于DDR2的速度;4块300G做RAID1的硬盘在每个虚拟机中的总体性能相当于SCSI的64%,写速度19MB/s。

微软号称用Hyper-V之后性能比物理机器下降8%。范总他们做了一个SQL Server 2008的测试,各项指标大约在物理机的80-90%左右,也还可以接受。另外SQL Server 2008比2005提升了相当大的性能……

Phoenix说目前微软的msdn、technet和20%的www.microsoft已经是跑在Hyper-V环境中的了,根据测试性能只降低了4%。

下一版的Hyper-V还将支持瞬间的虚拟机在服务器间的迁移、以及在online的情况下更改虚拟机硬件配置。可惜这个玩意儿只有64位版,没法自己试……

 

Colin Yu的课是这次TechEd我听的最后一个Session,印象颇为深刻。前面先讲了一堆故事,吹捧了云计算。然后做了一个Demo:把SharePoint相关的一个文档库通过ISB(internet service bus)push到.net services中,然后建了一个工作流在.net services中,在上传文档后触发.net services中的工作流,并返回到SharePoint网站中的任务列表进行工作流操作;随后,又卸掉了这个workflow,在windows application server(代码名Dublin,可以在IIS中host workflow和communication,下一代的application server,windows 7中提供)挂了另外一个类似的工作流。然后SharePoint端未经过任何配置的修改,就能运行这个新的工作流……很神奇 -.-

下课后和Colin聊了一阵儿,说目前Azure Services中的Microsoft SharePoint Services基本上是把WSS搬到了云中,不过存储和计算还是使用的同一台服务器的资源,然后他们正在重写这套类WSS的内容,使用云端存储(SQL Services)等内容真正的把SharePoint在云中实现。另外他们已经有了把Dublin整合入SharePoint的设计,不过这个还得等下下版的SharePoint……O14肯定是来不及了。O14应该会很大程度上提升列表在性能上的问题。

然后跟Colin和上海team的缪瑾和她的同事(忘了叫啥-.-,也是个mm)聊了若干和SharePoint、workflow相关的内容。他们说现在他们很希望能够得到用户关于SharePoint改进方面的反馈,能够把越来越多的反馈内容提供给微软产品组,这样微软就会更加重视中国市场……

聊的很happy,为了回家陪lp,于是没跟他们一起去吃涮羊肉……

 

中途张弛同学借我的相机跟美女姐姐合影……不过为了估计他的形象还是不把照片贴出来了……

贴张移动话筒状的ocean同学,以及李辉同学:

DSC_1762

DSC_1781

posted on 2008-11-08 20:38:59 by erucy  评论(0) 阅读(6254)

 
2008年10月08日

最近的一个SharePoint项目要求不能使用后台代码,所以为了与SharePoint内容进行交互,就得使用AJAX通过内置的web service去访问和修改SharePoint数据。

对于我这种学SharePoint比学asp.net早的人来说,用javascript去调用web service并不是一件容易的事,虽然在asmx页面中有关于发送和接收包的结构,但是很多地方都语焉不详,而且平时即使用web service,也是直接在vs里直接添加,用面向对象的方式去调用,顶多操作一些xml,对其内部的通讯结构和内容并不了解。

为了应对这种需求,特意在服务器装了sniffer pro去侦听web service数据的内容,前面都很顺利,读取用户配置文件、读取列表内容一切正常,但是到修改的时候就碰到了问题,包的数据内容与sniffer截获到的完全一致,但就是调用不成功。鼓捣了半天发现是在http header中漏掉了SOAPAction这个属性,加上之后就一切正常了。

其实这个SOAPAction在asmx的页面中也写到了,不过之前一直只注意数据,没有注意header;在sniffer中也截获到了,不过也没有注意到http header……看起来要通过web service向sharepoint里写内容的话,SOAPAction这个header是必不可少的,有点像FormDigest控件对于普通web page的意义。

等项目搞完了考虑把操作sharepoint数据的这个javascript库公开出来,嗯嗯。

ps. jQuery真是好啊真是好,解决了很多头疼的跨浏览器问题。

ps & ps. Aptana真是好啊真是好,见过的最好用的javascript编辑器。

posted on 2008-10-08 17:01:04 by erucy  评论(0) 阅读(5570)

 
2008年09月10日

u2u的创建者之一,smartpart的作者之一。讲课时心脏病突发……

posted on 2008-09-10 09:21:05 by erucy  评论(0) 阅读(5529)

 
2008年08月28日

这个估计是最常用的.net工具,Lutz Roeder同学终于把它转交给Red Gate Software去开发了……这个东西居然有8年多了。

After more than eight years of working on .NET Reflector, I have decided it is time to move on and explore some new opportunities.

I have reached an agreement to have Red Gate Software continue the development of .NET Reflector. Red Gate has a lot of experience creating development tools for both .NET and SQL Server. They have the resources necessary to work on new features, and Reflector fits nicely with other .NET tools the company offers.

Red Gate will continue to provide the free community version and is looking for your feedback and ideas for future versions.

For news and updates on Reflector, sign up for the .NET Developer’s Newsletter from Red Gate. To find out more about the agreement, see the interview on Simple Talk.

posted on 2008-08-28 09:15:40 by erucy  评论(0) 阅读(6599)

 
2008年08月27日

最近有个需求,将不同的内容类型组织到同一个列表(不是文档库)中,希望能够给不同的内容类型显示不同的图标。不过SharePoint内容类型似乎没有关于图标的设置,翻了ContentType的SchemaXml和若干个xml配置文件都没找到相关的办法。

今天突然想到了计算字段,猜测大概能做到这一点,不过计算字段只能显示单行文本、数值、是/否等几种固定类型,不能显示html内容,我觉得可以通过修改默认的计算字段配置文件来达到这一目的。上网搜了一下,果然找到:Enabling HTML and/or Images in a SharePoint List using a calculated field

大致的方法就是控制计算字段在显示的时候的html编码,在FLDTYPES.XML中我们可以看到默认是这个样子的:

1 <Default> 2 <Column HTMLEncode="TRUE" AutoHyperLink="TRUE" AutoNewLine="TRUE"/> 3 </Default>

也就是说对于单行文本的显示方式,都是加上了HTML编码的,自然我们可以改掉这个地方,但是为了不影响其他计算字段的显示,可以用一些特定标记来判断,比如改成这样:

1 <IfSubString> 2 <Expr1><![CDATA[<custom/>]]></Expr1> 3 <Expr2><Column/></Expr2> 4 <Then> 5 <HTML><Column/></HTML> 6 </Then> 7 <Else> 8 <Column HTMLEncode="TRUE" AutoHyperLink="TRUE" AutoNewLine="TRUE"/> 9 </Else> 10 </IfSubString>

这段的意思是:如果计算字段的值包含“<custom/>”(这不是一个html标签,所以页面上不会显示),那么就不编码,否则对内容进行html编码。

于是,就可以在列表中创建一个计算字段栏Icon,它的公式设置成:

1 =IF([内容类型]="类型A", 2 "<custom/><img src='/_layouts/images/img1.gif'/>", 3 "<custom/><img src='/_layouts/images/img2.gif'/>")

要是支持SWITCH就更好了……

posted on 2008-08-27 15:09:08 by erucy  评论(0) 阅读(4989)

 
2008年08月26日

这里的表单指的是列表默认的新建界面和编辑界面,在点击“确定”之后实际上是可以触发一段我们自定义的代码的,比如跳转页面、做一些其他操作等事情。(虽然跳转页面可以通过url中的Source来做,但是我们往往需要跳转时url加上当前列表条目的ID,不过新建页面中是拿不到条目ID的……)

添加表单事件的方法很容易,不过没有见到网上有任何文章说这件事 -.-

在SPFormContext中使用OnSaveHandler属性就可以挂载一个EventHandler了,所以我们可以在表单页面中加入如下代码(通过WebPart或者自定义字段):

1 protected override void OnInit(EventArgs e) 2 { 3 base.OnInit(e); 4 // add save handler 5 if (SPContext.Current.FormContext.FormMode == SPControlMode.New) 6 SPContext.Current.FormContext.OnSaveHandler += new EventHandler(MyHandler); 7 }

通过Reflector,我们可以看到保存列表条目的那个确定按钮“SaveButton”在保存时所做的操作,如果当前表单中有SaveHandler的话,则不会自动保存该条目。换句话说,我们需要在代码里面自动做这件事,不过也很容易,利用SaveButton的静态方法SaveItem:

1 protected void MyHandler(object sender, EventArgs e) 2 { 3 string checkInComment = Page.Request.QueryString["CheckInComment"]; 4 if (checkInComment == null) checkInComment = ""; 5 SaveButton.SaveItem(SPContext.Current, false, checkInComment); 6 7 // do custom actions, now we can get the item id! 8 if (SPContext.Current.FormContext.FormMode == SPControlMode.New) 9 Page.Redirect("some url.aspx?ID=" + SPContext.Current.ListItem.ID.ToString(), true); 10 }

通过在自定义字段中使用,可以用这种方法实现一些功能(在自定义字段控件中可以直接用this.ControlMode代替FormMode)。

不过这种方法有一个缺陷,就是在默认的新建、编辑页面中虽然可以正常使用,但是在DataFormWebPart中(就是用SPD插入的“自定义列表表单”)中,SaveHandler无法被触发,而且当前的FormContext也有一些属性不正常(例如拿不到页面上的控件,FormMode是Invalid)……我还没有实验使用ListFormWebPart(就是原来那个表单WebPart)配合RenderTemplate的方式是不是能够行的通……

posted on 2008-08-26 09:29:14 by erucy  评论(0) 阅读(4996)

 
2008年07月30日

    我们在SharePoint上查看列表视图的时候,默认的那个Web部件(ListViewWebPart)提供了丰富且友好的功能,可以在上面进行排序、筛选等操作,每个列表条目上还有一个友好的下拉菜单。在2007中,SharePoint内置了一个类似的控件SPGridView来达到类似的效果,所以当我们需要显示一些其他数据的时候(例如来自SQL Server等),将数据绑定到SPGridView上就可以实现类似的排序和筛选效果,而不用写一行排序筛选相关的代码,下拉菜单的实现通过几行简单代码可以搞定。

    关于SPGridView网上有很多文章介绍它的用法(例如jianyi的这篇文章,其中介绍了如何通过ObjectDataSource来显示一个SharePoint风格的数据视图,并有一个比较简单的下拉菜单,也可以做排序和筛选)。但是文章的后半部分,也就是如何显示SharePoint列表数据的部分,有比较大的问题,而且根据我搜索的结果,也很少有文章提到这个问题。

    网上的一些例子在使用SharePoint列表作为数据源的时候,直接使用了SPDataSource来进行数据绑定。这个东西也是2007中新加上去的,配合SPGridView的一个控件,可以直接通过List属性绑定到一个SharePoint列表上。显示成那个样子没有问题,但是在排序和筛选的时候就有问题了。不知道那些文章的作者是否试过绑定SharePoint列表,反正在我这里用无代码方式是不能进行筛选的(排序似乎OK)。处理筛选的时候,一般介绍的方法是指定SPGridView的FilteredDataSourcePropertyName属性为“FilterExpression”、指定FilteredDataSourcePropertyFormat属性为“{1}='{0}'”,但是这种方法对于数据源为SPDataSource的SharePoint列表绑定是行不通的,因为SPDataSource并没有FilterExpression这个属性,也没有任何和筛选相关的属性,我也没找到其他解决筛选的方法。从这一点看来,我觉得SPDataSouce并不是一个完善的数据源实现,不知道在2009中会不会有改进。

    其实解决SharePoint列表数据绑定的方法也很简单,那就是先把列表数据转换成DataTable(通过SPListItemCollection的GetDataTable方法),再用ObjectDataSource作为数据源绑定到SPGridView上,这样就可以实现不写代码的排序和筛选了(不过也有一些不如用SPDataSource的地方,放到后面再说)。

    先来说筛选,关于SPGridView的筛选问题网上几乎所有的文章都提到了这一篇:Filtering with SPGridView。这篇文章主要说的内容有两点:第一、在SPGridView绑定的时候,如果希望实现筛选功能,那么在绑定时需要指定SPGridView的DataSourceID为ObjectDataSource的ID,而不能直接将DataSource指定为ObjectDataSouce;第二、默认情况下SPGridView的筛选和排序同时进行的时候会有问题(显示不合逻辑),文中给出了一种使用ViewState保存筛选条件的解决方案,在这里就不再赘述了。

    然后说说数据绑定问题,SPGridView是不支持自动生成绑定列的,所以必须把AutoGenerateColumn设成false。一般我们在写asp.net的时候,绑定数据列使用BoundField控件,在SharePoint中有一个更好的选择,那就是SPBoundField。它的使用方法和BoundField完全一致,但是它对SharePoint的数据类型(也就是栏类型)做了处理,对超链接、多选、查阅项等内容都有比较好的处理,它的底层是调用了对应SPField的GetFieldValueAsHtml方法(所以,如果你希望这个东西能很好地显示你的自定义字段类型,你最好在实现自定义字段的时候把GetFieldValueAsHtml重写)。当然,这个所谓的“比较好的处理”指的是使用SPDataSource作为数据源。当我们使用ObjectDataSource绑定用GetDataTable方法获得的DataTable时,问题就出现了:多选项不能正常显示为多选(而是;#那种内部表示)、超链接不能显示为链接(显示为“url,说明”)、人员没有链接、最不能忍受的是多行文本都不是以html形式显示的,这是因为在GetDataTable的时候,SharePoint就已经做过一次数据转换了,即使用SPBoundField绑定,也会有问题。解决方法也有,就是实现一个自己的GetDataTable……其实也不麻烦。

    最后,SPGridView是继承了GridView的,所以可以加“选择”功能,直接在最后加一列CommandField就行了。也可以通过一些trick的方法把选择按钮隐藏掉,然后实现单击一行的时候选中,比如下图:

    image

    当然,既然是继承了GridView,也可以做一些其他操作,比如加个按钮什么的。但是另一个问题又出现了,SPGridView在按钮列(或者那种下拉菜单)PostBack的时候,数据绑定失败。也有解决方案:SPGridView, SPMenuField, Grouping, Postback

posted on 2008-07-30 17:34:30 by erucy  评论(0) 阅读(6793)

 
2008年07月28日

    SharePoint内置了一套相对比较完整的Web Services提供给开发者,这样就可以在客户端、跨平台的程序中读取甚至修改SharePoint中的内容。不过当SharePoint网站不允许匿名访问的时候,调用Web Services自然也需要提供身份验证。

    SharePoint身份验证最常用的是Windows验证(Windows Authentication)和表单验证(Form Authentication)两种。

    Windows验证即使用Windows账号或者AD账号来进行身份验证,对于这种验证方式,在SharePoint SDK中已经给出了如何提供身份验证的方法,假设我们使用最常用的lists.asmx来获取SharePoint列表数据,添加的Web引用的命名空间是spwsList:

 

使用当前帐户身份:
1 spwsList.Lists wsLists = new spwsList.Lists(); 2 wsLists.Credentials = CredentialCache.DefaultCredential; 3 Console.WriteLine(wsLists.GetListCollection().OuterXml);

 

 

使用指定帐户:
1 spwsList.Lists wsLists = new spwsList.Lists(); 2 wsLists.Credentials = new NetworkCredential("username", "password", "domain"); 3 Console.WriteLine(wsLists.GetListCollection().OuterXml);

 

    上面的CredentialCache、NetworkCredential都是在System.Net命名空间下。

 

    表单认证是SharePoint 2007新加入的一种身份认证方式,其后台是使用.Net Framework中的Membership机制进行用户身份的识别,对于外网来说,大都是使用表单认证的方式来实现的。在使用表单认证的SharePoint网站中通过Web Service获取数据稍微麻烦一些,不过也可以通过SharePoint提供的表单认证Web Service来创建用户身份相关的Cookie。

    表单认证Web Service的地址是:http://[server]/[site]/_vti_bin/authentication.asmx

    在使用Web Service的程序中再次加入上面这个Web引用,假设其命名空间是spwsAuth,那么使用表单认证构造身份并访问数据的代码实例如下:

1 spwsAuth.Authentication auth = new spwsAuth.Authentication(); 2 auth.CookieContainer = new CookieContainer(); 3 auth.AllowAutoRedirect = true; 4 spwsAuth.LoginResult lr = auth.Login("username", "password"); 5 if (lr.ErrorCode == spwsAuth.LoginErrorCode.NoError) 6 { 7 spwsList.Lists wsList = new spwsList.Lists(); 8 wsList.CookieContainer = auth.CookieContainer; 9 XmlNode res = wsList.GetListCollection(); 10 Console.WriteLine(res.OuterXml); 11 }

posted on 2008-07-28 14:02:09 by erucy  评论(0) 阅读(7414)

 
2008年07月25日

今天遇到一个SharePoint网站,在服务器上可以访问,在服务器外访问不能(写到这里估计大部分人都能猜到是什么问题了)。于是弱智的我查看了所有IIS、Web应用程序、管理中心、SSP的相关设置,都没有找到问题所在。于是惊动了kaneboy同学,在其指导下,在IIS里新建了一个站点,扔了个hello world页面进去,依旧是里面能访问,外面访问不能。于是kaneboy同学沉思了一下,说“你防火墙关了么?”于是我就点点点了……我什么时候把服务器的防火墙打开的……

于是这篇日志就当作blog复出吧……上半年被毕业事宜折磨了半年……我过一段时间重新开始写自定义字段类型的开发,最近又有了一点心得……

posted on 2008-07-25 19:07:09 by erucy  评论(0) 阅读(5837)

 
2007年12月04日

在上一次我们已经编写好了一个带有格式验证功能的Email地址栏,那么如果需要用到这个自定义字段,必须先对其进行注册,通知SharePoint有了一个新的字段类型。其方法就是编写一个xml文件。

先来看一下这个xml文件的内容,再对其进行一一介绍:

<?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
  <FieldType>
    <Field Name="TypeName">EmailField</Field>
    <Field Name="ParentType">Text</Field>
    <Field Name="TypeDisplayName">Email Field</Field>
    <Field Name="TypeShortDescription">Email</Field>
    <Field Name="UserCreatable">TRUE</Field>
    <Field Name="ShowInListCreate">TRUE</Field>
    <Field Name="ShowInSurveyCreate">TRUE</Field>
    <Field Name="ShowInDocumentLibraryCreate">TRUE</Field>
    <Field Name="ShowInColumnTemplateCreate">TRUE</Field>
    <Field Name="FieldTypeClass">EmailField.EmailFieldField,EmailField,Version=1.0.0.0,Culture=neutral,PublicKeyToken=9f4da00116c38ec5</Field>
    <RenderPattern Name="DisplayPattern">
      <HTML><![CDATA[<a href="mailto: ]]></HTML>
      <Column HTMLEncode="TRUE" />
      <HTML><![CDATA[">]]></HTML>
      <Column HTMLEncode="TRUE" />
      <HTML><![CDATA[</a>]]></HTML>
    </RenderPattern>
  </FieldType>
</FieldTypes>

在“FieldType”一节中,定义了和该字段相关的内容,可以看到其大致分为两个部分:

第一部分是关于该字段类型的一些基本设定,比如类型名称(TypeName)、父类型名称(ParentType),

显示名称(TypeDisplayName)是指在列表设置页面中显示的名称:

image

而简短描述(TypeShortDescription)则是在创建栏页面中显示的名称:

image

是否允许用户创建(UserCreatable)指定该字段类型是否可以在创建栏的页面出现,允许用户自行创建(而不是写在列表模板的定义xml文件中)

后面一些就是设置该字段类型是否可以出现在某些列表类型中,比较重要的一个是FieldTypeClass,定义了该字段类型后台对应的类名和程序集名称,注意都要使用全名,中间用逗号分开

而第二部分是通过一系列的RenderPattern设置该字段类型的显示样式。

RenderPattern大致分为几种,HeaderPattern和FooterPattern定义了在视图页面显示该字段时的栏的头尾样式,DisplayPattern定义了字段内容的显示样式,EditPattern和NewPattern为编辑和新建时的样式,以及PreviewDisplayPattern、PreviewEditPattern和PreviewNewPattern定义了在SharePoint Designer中的样式。

可以注意到,这种样式的定义是通过一种奇怪的可以用CDATA方式搀杂html代码的形式定义的,对了,这又是CAML……其中出现的两个Column结点表示该栏的内容。

 

写到这里,我们可以发现这个xml其实可以写的很复杂,尤其是在RenderPattern的部分,因为CAML允许我们在定义显示样式的时候使用switch条件,这部分的写法很灵活,我们可以多多参考默认的那些字段是怎么写的(在fldtypes.xml中)。

此外,这个xml文件中还会涉及到自定义属性和自定义属性输入界面的控制,这个放到相应的部分再讲。

另外,非常需要值得注意的,这个xml文件必须以“fldtypes_”开头,才可以被SharePoint识别为字段类型的描述文件。

ok,现在我们把上次编译出来的dll文件拽到GAC里,把这个xml文件放到12\TEMPLATE\XML目录中,重启iis(一定要iisreset,仅回收应用程序池是不行的),然后我们就可以在创建栏的地方看到这个自定义字段类型了,并且它的表现也和我们期望的一致。

在新建界面中格式验证失败时:

image

在显示界面中:

image

并且,这个字段在编辑界面中无法看到(被我们在代码中屏蔽了)。

这两次内容综合起来,我们可以编写一个很简单的自定义字段类型了,它的功能仅仅是使用默认的那些属性、使用默认的输入界面,加上一些其他属性的初始化功能和数据验证功能,在下一次中,我会介绍一下怎样来自己编写输入界面。

(未完待续)

posted on 2007-12-04 00:10:00 by erucy  评论(7) 阅读(6524)

 
2007年11月29日

从这次开始,将逐步介绍如何创建一个自定义字段类型,以及通过什么样的手段来完成我们需要的功能。

随着例子从简单到复杂,所涉及的内容也有所增长,所以大致的计划流程是这样的:字段类型、xml描述文件、输入控件、值类型、自定义属性控件、自定义属性bug的解决方案、(自定义字段间的通信),大概先分为这几期吧(看来是一个任重而道远的工程……)

那么本期先通过一个最简单的自定义字段类型的例子,来看一下如何创建自定义字段类型中的字段类。

在这个例子中,我们将编写一个Email地址的字段,它可以完成Email地址的合法性验证。

首先,自定义字段类型在SharePoint Extension for Visual Studio 2005里其实是有模板的,但是我们在创建一个项目的时候却看不到它,其实它的创建流程是这样的:

先创建一个空的SharePoint解决方案:

image

然后在新建一个Item的时候,在可选的模板中就能够看到一个“Field Control”了,选择它:

image

点确定之后,我们会发现模板为我们创建出了两个文件,xxx.Field.cs和xxx.FieldControl.cs,这两个文件分别定义了字段的类和字段的输入控件。并且自动生成了一个强命名的key,使得我们可以把编译得到的dll放到GAC中。这次主要对字段类进行介绍。

在上上次中介绍过SharePoint的内置的字段类型,每一个字段类型都有自己的类(例如单行文本对应SPFieldText),这些类全部都是SPField的子类。所以,当我们编写一个自己的字段类型的时候,也需要让这个字段类型是SPField的子类,这样才能够完成字段类型的功能。但实际上,我们往往并不需要直接继承SPField,而是找一个与我们所需要的功能最接近的字段类型继承它,这样的优点就是我们可以使用这种内置字段类型的一些特殊属性(比如单行文本中的最长字符数限制等),并且能够使用内置字段类型的默认输入界面,另一个优点就是如果要直接继承SPField,要多写一个东西(但是我忘了是什么了……汗……)。

在这个例子中,Email地址的输入和单行文本非常类似,于是我们继承SPFieldText。

好,可能有人会发现了,默认由模板创建出来的这个项目中它就是继承了SPFieldText的,在我们继续之前,不妨先来看一看这默认生成的代码中都有什么东西。

我们已经看到默认的模板创建出来了Field类和FieldControl类,并且Field类继承了SPFieldText,也就是单行文本。然后在这个Field类中,我们还可以看到如下两大部分内容:

第一部分:构造函数

public EmailFieldField(SPFieldCollection fields, string fieldName)
  : base(fields, fieldName)
{
}
        
public EmailFieldField(SPFieldCollection fields, string typeName, string displayName)
  : base(fields, typeName, displayName)
{
}

SPFieldText并不支持不带参数的默认构造函数,所以要重载这两种构造函数,而这两种构造函数也是SPField所使用的,默认情况下直接使用相同的参数调用父类的构造函数。通过Reflector我们可以看到,在SPField的这两种构造函数中都是根据参数设置了一些初始值。因此,如果需要有一些特殊的初始值要设置,我们可以放在这个构造函数中,例如如果我们希望这个Email地址栏只在新建界面中出现,而不让用户在默认界面上修改它,我们可以在构造函数中添加:

this.ShowInEditForm = false;

我们对这两个构造函数的修改一般也仅限于此类操作了。(其实我们几乎很少需要手动去调用Field系列的构造函数,在创建一个字段时我们往往使用的是SPFieldCollection的Add方法或者AddLookup方法)

在一个自定义的字段类型中,这个构造函数是字段类唯一一个必须重载的地方,其他内容都可以不写(当然如果你其他内容都不写的话,这个字段比起它的父类来说,无非就是多了一些初始值——当你需要这么做的时候,你就可以很简单地这么干来创建一种新的字段类型。。。)

第二部分:关联的控件

在默认生成的代码中,重载了SPFieldText的一个属性叫做FieldRenderingControl。顾名思义,这个只读属性是用来返回与此字段相关联的显示/输入控件的。这部分内容我们放在下下次的内容做介绍。

在这个Email地址的例子中,我们可以直接使用SPFieldText字段类型的默认输入控件(至于显示我们可以放到xml里来定义),因此我们无需重载它,把它删掉好了(同时也可以把那个xxxx.FieldControl.cs也删掉,而且它其实就是空的……)

既然是自定义字段类型,那么必然和默认的单行文本要有所区别,在这个例子中,我们所提供的额外功能就是Email地址的验证,于是我们就需要:

第三部分:数据验证

数据验证功能一般来说都是放在输入界面里做的,但是其实我们也可以把类似的功能放到字段类中(因为我们使用的是默认输入界面)。

在SPField中,有这样一个方法我们可以重载:

public override string GetValidatedString(object value)

这个方法的目的就是根据这个字段的值(object),返回一个通过验证的字符串。其主要目的第一在于验证数据,第二在于做数据串行化(Serialization),把数据值都转换成字符串。这个方法在每次提交值的时候都会执行到,所以可以用来进行数据验证。

在重载这个方法的时候,一般我们都先需要判断一下数据是否为空,然后再做真正的自定义的数据校验。如果在校验过程中发现了不合法的数据,我们需要使用一个特殊的Exception类:SPFieldValidationException。这个异常的表现形式就是我们在填错什么东西时,字段输入控件下面会出现的那行红字。

在这个例子中,我们使用正则表达式来验证Email地址,整个函数的函数体如下:

public override string GetValidatedString(object value)
{
    if (Required && (value == null || value.ToString() == ""))
    throw new SPFieldValidationException(SPResource.GetString(Strings.MissingRequiredField));

    // Validate email format
    string emailRE = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
    if (!Regex.IsMatch(value.ToString(), emailRE))
        throw new SPFieldValidationException("Invalid Email Address.");

    if (value == null)
        return string.Empty;
    else
        return value.ToString();
}

这个例子写到现在,功能已经完成了,这就是最简单的一个自定义字段类型的开发。当然到现在我们还不能用它,还需要写一个xml描述文件,放在下次介绍。

那么在这个字段类中,我们通常还可以写哪些内容呢?

第四部分:自定义属性

每个字段类型都有它自己特殊的一些属性,我们称之为自定义字段属性(比如单行文本的最大长度、数字的最大值最小值这样的)。

在SDK中编写自定义属性的方法中,并不需要在字段类中加什么内容,但由于那个bug的存在,在两种解决方案中,都需要在字段类中加上自己的属性。有关这一部分,也等到专门自定义属性的时候再说。

第五部分:获取字段值

在SPField中,获取一个字段的值通常有多种手段,完成不同的用途。例如刚刚介绍过的那个GetValidatedString。

有时为了完成其他一些用途,或者和我们其他的一些代码配合,可能需要重载这些方法,它们有:

public object GetFieldValue(string value)

——根据字符串的值获得真正的值类型(简单类型如double,复杂类型如SPFieldxxxxValue),可以把它理解为反串行化的过程。

public string GetFieldValueAsText(object value)

——根据值得到文本,与GetValidatedString方法不同,这个方法并不是总被执行,它主要还是用于显示。

public string GetFieldValueAsHtml(object value)

——和上面的方法类似,只不过是用Html的格式来显示,这两个方法已经在(0)里面提到过了。

public string GetFieldValueForEdit(object value)

——在编辑时获取一个字符串,其实这是一个有点奇怪的方法,因为后面我们在介绍输入控件的时候,一般都是用object作为Value的。难道Edit时的value会和一般的value不同么?我发现这个方法的重载是在SPFieldNumber里,当它设置为用百分比显示时,想一想编辑时填的值和真正的值有什么区别(30% vs 0.3),就可以理解它的意义了。

上面这些方法就不再一一进行介绍了,有兴趣的可以用Reflector看一看Microsoft.SharePoint.dll中,内置的那些字段类型是怎么写的,会有很大的帮助。

第六部分:其他

其实,上面的那些内容除了自定义属性之外,都是来自SPField的属性或者方法,当然我们也可以根据需要重写它的其他属性和方法。也可以写自己的……

言归正传,我们已经写了一个最简单的Email地址字段类,那么怎么样使用和部署?用什么方式对它进行描述?请看下期……

(未完待续)

posted on 2007-11-29 00:56:00 by erucy  评论(4) 阅读(7090)

 
2007年11月26日

哈哈,玩笑玩笑。话说这是我很久以来非常非常想做的一件事情,嗯嗯。

图来啦!懒得搞彩色背景了,直接灰度算了……至于字体,那当然是老徐体,嗯。

SharePoint_Sketch

posted on 2007-11-26 00:30:00 by erucy  评论(15) 阅读(7954)

 
2007年11月25日

从这一节开始正式涉及到自定义字段类型的内容,嗯……不过这次还是没有代码

本次主要介绍一下自定义列表字段类型的大致内容,用途和缺点,以及大概的体系

上一次说到了SharePoint本身内置了很多种字段类型(其实还有更多,只不过我们没办法自己用罢了,都是系统默认的,比如Counter、File之类),这些字段类型虽然已经比2003时代要丰富而且功能强大了很多,但是有时依然不能满足我们的需求。例如如果你想做一个Email地址栏,你当然可以选择使用单行文本,但是一个好的Email地址输入是可以进行合法性验证的,单行文本却不行;又比如你想做更强大的输入界面,比如评分(现在SharePoint中已经有一个类似的东西了,RatingScale,但是遗憾地它只能用在调查列表中),你希望能把它做成youtube那样的效果;再比如你要做一个能够带有自动判重功能的输入栏……

自定义字段类型是一个很能激发我们想像力的东西,比如我们可以把一个字段类型当做一个按钮,它本身可以不存任何数据,只是在输入界面中根据其它字段来判断一些东西(比如我有两个时间类型的字段分别存放会议开始时间和结束时间,然后我可以做这么一个“按钮”字段,以便在输入的时候就可以判断有没有与此冲突的会议时间——这往往比使用Event Handler更加人性化一些,因为那是在提交后才判断的)。最近越来越发现自定义字段的强大,甚至有一种机制可以让不同字段之间进行交互,今天侯同学刚发现的这一点,大概试了试原理,还没用到字段类型上,等试出来了再说。

好了,言归正传,自定义字段类型主要解决的是以下问题:

  • 更复杂的输入、显示界面
  • 自定义的合法性判断检测
  • 更复杂的逻辑
  • 其他一些默认字段所无法完成的功能

举一些例子:

  • 地址。我们在网上购物的过程中填写地址时,经常会发现它分成了几个不同的部分让我们输入,比如省、市、区、街道、邮编等等。那么如果使用SharePoint默认功能的话,我们只能把这些分别存在一些栏中,这显然不好。自定义列表字段就可以把它们存在一个栏中,但是可以分别输入各个部分。(事实上,Todd的USAddress这个字段类型也是我见过的第一个自定义字段类型)
  • Email地址。如上所述,可以使用正则表达式加上一些合法性验证。
  • 评分。更加人性化的输入和输出,让用户使用时不在是只和枯燥的数字打交道。
  • 外部数据查阅。虽然默认有了BDC查阅和查阅项,但是有时我们可能会需要更灵活些的查阅,比如跨网站查阅列表内容(还记得么?这是2007支持的功能!但是并没有体现在默认界面上罢了)

当然,自定义字段类型并不是万能的,它有着这样那样的局限,而且其中很多都非常诡异:

  • 首先,自定义列表字段是不被office系列的客户端支持的。也就是说,我们觉得很好用的那个“文档信息面板”是不支持自定义字段类型的。我们在文档库中添加一个自定义列表字段时,甚至都会出现这样的提示:

image

如果你不记得什么是“文档信息面板”的话,喏(在线创建一篇文档时):

image

  • 其次,非常奇怪的,自定义字段类型中的值不能超过255个字符(即使你继承了多行文本也不行!),就“好像”它们都是从单行文本衍生出来似的(我们知道单行文本的最大长度就是255)。这是一个老外发现的,非常没道理的一个限制,那个老外最后用的方法是继承了多选这种字段类型,这样就可以多放几个255字符了,虽然选项数也是有限制的……
  • 另外,现在的自定义字段类型有一个很严重的bug,就是按照标准的编程方法(我指的是SDK里写的方法),它无法保存自定义的属性(每个字段类型都有些独特的属性,比如数值型中的最大值、最小值)。当然,这并不意味着我们就不能保存自定义属性,有一些解决方案去使用它(其中一种阳春白雪,从SharePoint存储自定义属性的原理入手,但是这个改起来超级麻烦;另外一种是我发明的,虽然看起来很丑陋,但事实证明有效且简单),我在后面会讲到具体怎么做。
  • 最后,我们开发人员最关注的就是,这个东西开发起来比较繁琐,尤其当你有很多需求要加进去时。虽然它并没有workflow那么深奥,但由于涉及到的东西比较多,所以还是有点难度的。还是Web部件和Event Handler容易啊……感叹一下。每次我讲自定义列表字段开发的时候,虽然我已经尽量把它涉及到的原理讲清楚了,但台下的反响还是云里雾里……不自己亲自做几个的话,恐怕是很难深入理解的。

一个自定义的字段类型如果算全了的话,可以分为5个部分(看,我说很繁琐吧……)

  1. 字段类。一个自定义的字段类型是继承自某个内置的字段类型的(这也是为什么我上次花了这么大功夫把内置的字段类型都罗列了一遍的原因),当然,我们也可以直接继承最基础的字段类型——SPField,但是这样要多做些事情(很遗憾,具体加什么我忘了-.-)。还是建议继承某种已有的吧(比如SPFieldText、SPFieldLookup、SPFieldMultiColumn之类的),大不了我们完全不用它默认的输入输出界面罢了。
  2. 字段值类。这是一个可选的部分。就像我上一次说的,如果字段的设计比较复杂的话,可能会需要字段值的类型,这种一般都用于一个字段中存储超过一个数据的情况(比如查阅项包含被查阅条目的ID和一个文本,Url包含地址和描述)。如果我们自己的字段类型需要有类似需求的话,可以继承一个已有的值类型,来写一个新的值类型。当然,如果原有的值类型能够满足我们的需求,直接用它就好了。
  3. 字段输入/显示控件。这也是一个可选的部分,但大多数情况下可能都要写,因为我们往往需要自定义输入的样式和输出的样式。这个控件可以使用一个User Control来做,因此支持可视化设计(如果愿意生写也可以……)
  4. 自定义属性的输入控件。同样是一个可选部分。自定义的属性对于一个自定义字段类型来说往往还是比较重要的,正是它体现了同一种字段类型下,一个字段和另一个字段的不同之处(比如查阅项查阅不同的列表)。本来这些自定义属性的输入是可以自动生成的,但由于刚刚说的那个bug,我们一般还是需要手动地去写一个自定义属性的输入控件,而且我们可以在这里也加入自定义的一些逻辑。这部分内容同样可以使用User Control,只不过需要再实现一个特殊的接口就行了。
  5. 字段定义文件。这是一个xml文件,每个自定义的字段类型都必须有(其实默认的那些字段类型也有),而且这个文件名必须以fldtypes_开头。这个文件中定义了关于该字段类型的一些基本信息(比如标题、类型、是否允许用户创建等等),还有它使用到的程序集信息、自定义属性的输入控件信息,另外还有各种显示样式(没错,这里也可以定义显示样式,而且支持一些诸如if、switch之类的条件判断,通过CAML格式实现),以及自定义属性(标准做法中的自定义属性在这里定义)。如果写这个文件时遇到了困难,我们可以参考一下默认的那些字段类型是怎么被定义的,此文件是那个很深的12目录中的"TEMPLATE\XML\FLDTYPES.XML"。

从另一个角度来说,自定义的字段类型也可以分成3个部分:程序集(dll)、控件(ascx)、描述文件(xml)。不妨先在此简要地介绍一下自定义字段类型的部署,很容易:把程序集扔进GAC里,把ascx放到"12\TEMPLATE\CONTROLTEMPLATES",把xml放到"12\TEMPLATE\XML",然后重启iis(一定要重启iis,仅回收应用程序池是不行的),然后就可以再创建栏那里看到新的字段类型了(如果我们没写错什么东西的话……)

从下一次开始,就是主要介绍以上那5个部分的写法,从中一一地展开介绍一下字段类型的工作机理。如果我能试出来字段类型之间通讯的话,我也会做一个介绍。

(未完待续)

posted on 2007-11-25 23:01:00 by erucy  评论(3) 阅读(7500)

 
2007年11月22日

SharePoint中若干自定制开发的内容,从目前我接触到的来讲,从开发语言上首先可以分为两大类,.net类和C++类,其中C++类主要是关于搜索中的IFilter和Protocol Handler的编写,使用的是COM的技术,这个回头有时间再说吧(或者有条件的话可以找微软要几份文档,之前帮微软做过文档和几个demo)。

然后就.net类的来说,我认为最为复杂的有两个内容,一个是工作流(我指的是vs开发的工作流),开发SharePoint工作流的话,除了要对SharePoint工作流的一些概念有所了解、对InfoPath有所了解之外,最重要的是WF(Workflow Foundation),这个研究的不太多;另外一个比较复杂的东西,就是自定义列表字段类型。就几次培训的反馈来说,普遍认为这个很麻烦,如果之前没有看过相关资料的话,2、3个小时之内很难把这个东西学明白。

于是从今天开始,准备写一个自定义列表字段类型的专题,争取涉及到其中可能会用到的各个方面。

之所以先从“0”开始,因为这次内容先不涉及到自定义的字段类型,先来看一下SharePoint中内置的那些字段类型,以及他们在对象模型中是什么样的。

首先下面这张图相信如果用过SharePoint的人应该再熟悉不过了:

image

这张图上基本上涵盖了大部分SharePoint内置的字段类型。如果我们装的是moss的话,还会多一个“业务数据”类型。

其实在wss3.0中,还多了一个可能一般使用者很少会见到的内置字段类型,叫“评估范围”,这种字段类型只在“调查”列表中会出现,并且不能在其他种类的列表中使用(即使通过对象模型也不能把它加到一个普通列表或者文档库中)。在新建一个调查列表的时候,创建列表的页面中,不是“确定”按钮,而是“下一步”,点这个按钮就会提示我们输入一些问题,这个时候就可以看到这个“评估范围”字段类型了:

image

这个字段类型主要的作用就是打分(有点像是youtube里面给视频打分的那种机制),可以设置分成几个分值,并且可以选择是否有空的项目(默认是N/A),以及将这些分值划分为三档,每一档的名称(好像只能是三档):

image

它的输入界面和输出界面都比较友好:

image

image

以上就是这个不太常见的列表字段类型的大概介绍,觉得这个字段类型写的还是很好的,其实我们可以通过自定义字段类型的方式,写出更加强大的字段类型出来。在此之前,先来看一下在SharePoint的对象模型中,字段都是怎样描述的。

如果之前曾经接触过一写SharePoint开发,我们会知道在对象模型中描述字段的类是SPField(对应的集合类是SPFieldCollection),这个类描述了一个字段中常用的一些属性(比如标题、内部名称、默认值、是否允许为空等等,以及在wss3.0中新加的是否在新建/编辑/显示等界面上显示这个字段——这个功能是只能通过自己写代码完成的,对应的属性叫ShowIn****,这是一个nullable的bool值,和普通bool值的用法有所区别)。

那么实际上,在SharePoint中内置的那些字段类型也都有各自的对象模型与之对应,这些类一般叫做SPField****,它们都是SPField的子类,各自扩展了特有的一些属性设定(比如单行文本中的最大长度、数字中的小数点位数等),有些比较复杂的字段类型还会有值类型于之对应,这些类一般叫做SPField****Value(****和它对应的字段类型的类名中的部分相同)。下面先大致看一下常用的内置字段类型:

1、单行文本 - SPFieldText

这个可能是用的最为广泛的字段类型了,它的输入界面就是一个单行文本框,没有数据验证功能(除了是否为空)。可以设置最大长度(局限在255以内)。

2、多行文本 - SPFieldMultiLineText

输入界面是一个textarea,根据设置不同,可以是纯文本或者是带格式文本的(按照html格式保存的)。

3、数字 - SPFieldNumber

输入界面是textbox,但是带有数据验证(是否为数字,以及最大/最小值等)。

4、货币 - SPFieldCurrency

和数字其实差不多,只不过现实的时候会多一个货币符号。

5、是/否 - SPFieldBoolean

一个CheckBox

6、日期 - SPFieldDateTime

一个带picker的textbox,可以选择“日期和时间”或“仅日期”

7、选项(单选) -  SPFieldChoice

可以以dropdownlist或者radio button的形式出现。这个字段有点点特别,虽然它看上去只能存一个值,但其实它是多选类(SPFieldMultiChoice)的子类……

---------分割线(以上可以算是简单类型)--------------

8、选项(多选) - SPFieldMultiChoice

如果使用多选,那么是通过一组checkbox输入的。在这个类里面定义了这个字段中究竟有哪些选项(通过Choices属性,自然,作为它子类的SPFieldChoice也有这个属性)。于之相对应的,可以通过SPFieldMultiChoiceValue类来访问它的值。

9、评估范围 - SPFieldRatingScale

刚才介绍过了,它其实也是多选类(SPFieldMultiChoice)的子类。于之对应的值类型为SPFieldRatingScaleValue。

10、链接或图片 - SPFieldUrl

可以是链接,也可以是图片,它包含url和描述信息两个部分,通过其值类型SPFieldUrlValue可以很方便的得到这两部分。

11、查阅项 - SPFieldLookup

通过dropdownlist完成单选,一个特殊的listbox完成多选(wss3.0支持查阅项多选了!),由于每个被查阅的项会有id和文本,所以也需要有值类型,这个比较特殊,有两种值类型,SPFieldLookupValue和SPFieldLookupValueCollection(因为支持多选了嘛)。然后在SPFieldLookup类中,定义了要查阅哪个列表的哪个字段,以及是哪个网站上的列表。是的!wss3.0中的查阅项其实是支持跨网站查阅的(通过设定LookupWebId属性),但是在默认的界面上并没有暴露出一点。所以一个跨网站查阅项是一个很值得一做的自定义字段类型!

12、用户和用户组 - SPFieldUser

它的输入是通过一个带有AJAX支持的输入框完成的,这是一个很强大的控件。其实这个类是SPFieldLookup的子类,因为它们做的事情在本质上都差不多。相应的,其值类型SPFieldUserValue也是SPFieldLookupValue的子类,还有SPFieldUserValueCollection……

13、多栏 - SPFieldMultiColumn

这是另一个很特殊的字段类型,默认情况下我们无法直接使用它,使用它的唯一途径就是通过自定义字段类型继承它来完成我们的需求。顾名思义,这是一个能在一个字段中储存多个信息的字段类型。

-----------邪恶的分割线-----------------

好,那么现在我们已经了解了SharePoint内置的这些字段类型,之所以需要了解它们的目的除了方便“日常应用”外,最为重要的,我们正是通过继承这些字段类,来编写一个自定义字段类型的。也就是说,我们要先找到一个和需求功能类似的字段类型,继承它!

(未完待续)

posted on 2007-11-22 00:49:00 by erucy  评论(9) 阅读(7480)

 
2007年11月16日

近日同学所在某公司的SharePoint网站在打了补丁之后挂掉了(登陆不能,登陆页面也不出现,用的LDAP认证),然后他自己鼓捣出来之后,在我威逼(没有利诱)之下,把他关于SharePoint的部分笔记发给我了,贴到这里给大家看看,可能也会有人遇到类似的问题。

他们用的是WSS3.0 + LDAP认证方式,https加密传输,主要用于做文档管理,没有任何自己开发的代码在其中。

首先是关于崩溃问题(笔记记载如下):

前两天出了一点小故障,问题描述要比解决方案复杂得多。。
开始可以出现登录页面,但是登录上去就抱错,说找不到default页面,然后看到winows update里面有个sharepoint的升级,就运行了。重启了机器后sharepoint的务就挂了。。。
唯一能想到的修复方法就是运行那个sharepoint配置向导,但是第9步会说spadmin服务没有起,十分伤心。就扔下不管了。
今天有人要用了,只好硬着头皮看看,发现这次配置向导竟然通过了。唉,微软的东西就是搞不懂,不过网站还是起不来,就乱改了一通iis配置,然后又用配置向导修复了好几次,终于可以出现登录页面了,但总说我登录不上。研究了半天估计是ldap配置出了问题,果然一检查是把上面2的web.config给覆盖了,于是恢复了就好了。。。
现在想一想当初可能就是升级后把一些配置给我覆盖了吧。。

然后是关于WSS3.0如何使用LDAP认证的问题:

基本按照网上的一些步骤配置,不过有些改动,详细内容可以参考这个网页:
http://www.sharepointblogs.com/helloitsliam/archive/2006/08/15/10027.aspx
这里只说一下具体做法
1. 从一个装了moss2007的机器上copy一个microsoft.office.server.dll文件放在桌面上,在C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI目录,然后将这个文件拖进c:\WINDOWS\assembly目录,注意一定要拖进。。
2. 修改sharepoint管理中心网站和web网站的web.config文件,默认在c:\Inetpub\wwwroot\wss\VirtualDirectories\80(和另一个管理端口)
在<machineKey>这行和</system.web>之间加入:
    <membership defaultProvider="LdapDemoMembership">
      <providers>
        <add name="LdapDemoMembership" type="Microsoft.Office.Server.Security.LDAPMembershipProvider, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71E9BCE111E9429C" server="xxx.xxx.xxx" port="389" useSSL="false" useDNAttribute="false" userNameAttribute="uid" userContainer="ou=xxx,dc=xxx,dc=xxx,dc=xxx" userFilter="(ObjectClass=*)" scope="Subtree" otherRequiredUserAttri
butes="uid,cn" />

      </providers>
    </membership>
保存关闭。注意useDNAttribute="false"一句比较重要,搜索的资料很多没有说,否则会连不上。
3. 打开sharepoint的管理中心(可以从开始->管理工具->),应用程序管理,验证提供程序,编辑现有的默认验证,验证类型选中表单,这里要打开一下匿名的权限(注意稍后再给禁掉),成员身份提供程序要和前面添加的一致,如LdapDemoMembership,角色管理不用填,最下面启用客户端集成,然后保存。
4. 手动添加一个管理员帐号(过后可以再删掉),还是应用程序管理,Web应用程序的策略,添加用户,区域选择默认(或自己设的网站区域),这是用户里应该能够识别ldap服务器上的所有用户,给一个完全控制权限。
5. 访问sharepoint的web网站,会出现登录框,用刚添加权限的帐号登录,点右上网站操作,网站设置,高级权限设置里面的匿名权限打开。然后回去关闭掉4中打开的匿名访问。这样可以做到需要ldap认证,但默认用户有一个访问者的权限,通过更改sharepoint网站中的访问者权限就可以限制普通用户的权限(已经很低了)。

关于https的设置:

控制面板,添加删除windows组件里先添加证书服务,随便起个名字。
管理您的服务器,管理此应用程序服务器,对sharepointweb端和后台管理网站都要做:属性,目录安全性,服务器证书,一路下去,生成一个txt文件。
更改默认网站的端口,比如8080,启动。
浏览器中访问http://localhost:8080/certsrv,申请一个证书,高级申请证书,使用base64...,将txt文件中begin和end之间的部分copy过去,提交。
管理工具,证书颁发机构,挂起的申请,改刚才的id颁发证书。
再登录刚才localhost网址选查看挂起的证书申请的状态,可以下载DER编码的证书保存。
回到开始的服务器网站属性,再选择服务器证书,处理挂起的请求并安装证书。
完毕后就可以https访问了。最后在目录安全性,编辑里勾上要求安全通道和128位加密。

都是原文照搬过来的,我是不是太懒了。。。。

准备弄完手头的连载之后开始写一个自定义列表字段的专题,或者各位看客有啥想了解的关于开发方面的(除了工作流-.-)东东也可以提一下,嗯嗯

posted on 2007-11-16 12:38:00 by erucy  评论(1) 阅读(7217)

 
2007年09月27日

在水木上看到的,Excel 2007在公式计算中有一个超级弱智的大bug:

计算乘法时,当计算结果等于65535,且两个乘数中有一个是小数时,有些时候结果会变成100000……

image

真是不知道产品组是怎么搞的。。。这种毫无理由的bug。。。

想当年似乎有一种计算器还是计算芯片,当计算两个特定的数相乘的时候,结果是错的

posted on 2007-09-27 04:45:00 by erucy  评论(20) 阅读(8422)

 
2007年09月16日

可以像写SQL语句那样来写CAML查询,点击这里免费下载。

我没有经过太大量的测试(没有覆盖到每种可能的分支),目前还处在beta版,欢迎大家试用。

如果有什么问题,可以在这里回复,或致信通向分享:feedback(at)CollaDec.com。感谢支持!

 

其实之前也有一些国外的人做了一些生成CAML查询的东西(毕竟CAML还是太难写了,主要问题倒不在于xml,而在于那些内部名称)

不过看了一眼之前的那个CAML Generator,本质上还是像xmlwriter那样去加那些结点,而且没有解决内部名称的问题

然后想写一个客户端去生成CAML,就像SQL Server里做视图的那样,后来觉得还是不太方便,索性打算写一个直接像SQL那样的语句去直接查询内容

其实这个东西的核心内容就是一个T-SQL语句的解析器

之前一直想不好怎么做比较方便,也参考了一些开源的解析器,帮助不是很大,这也是拖了很久的原因。

最近在做实验室的程序的时候做了类似的东西,于是借着手熟就顺手写了

主要就是借助几个数组去存那些查询字段、查询条件、排序字段、分组字段,

手写了一个状态机(懒得再去找开源状态机组件了,而且还得再带个dll,比较麻烦),标记出每个成分后面允许的内容(比如在select后面的返回字段后面,可以是一个逗号,也可以是where、order或者group),难度并不大,只要想清楚了就是个体力活。不过估计这个状态机应该还能再精简一些,等有空再分析分析吧。

另外一个比较核心的部分就是查询表达式的处理,把那种查询条件转换成xml格式的,这个其实就相当于表达式计算问题,随便找本数据结构的书上应该就有(分成两步:中缀表达式转后缀表达式、后缀表达式的计算)。

然后就是把那些列表名称、字段名称该分析的分析、该转换的转换,这个就很容易了。

下一步对这个的打算,除了找找bug、优化一下算法,可能考虑添加对跨列表、跨网站查询的支持,以及对moss中search的支持(这个可能比较麻烦)。

给个小sample:

SPWeb web = SPContext.Current.Web;
string queryStr = "SELECT * FROM 通知 WHERE ID>10";
FriendlyQuery query = new FriendlyQuery(web, queryStr);
query.RowLimit = 100;
query.Scope = FriendlyQuery.QueryScope. AllItemsAndFolders;
SPListItemCollection items = query.GetItems();
foreach(SPListItem i in items)
    Response.Write(i.Title + "<br/>");

posted on 2007-09-16 01:08:00 by erucy  评论(13) 阅读(6983)

 
2007年09月14日

你还在为SharePoint中那麻烦的查询语句而烦恼么?

你还在由于不熟悉CAML而厌恶查询么?

你还在为了查询去到处翻找一个字段的内部名称么?

 

现在不必了!

有了CollaDec即将发布的FriendlyQuery类库(免费的),让你像写SQL查询那样方便地完成SharePoint列表的查询和排序,你不需要了解CAML、不需要知道那些杂乱的内部名称,只需要简单地写上一行,就能大量地解决你的开发时间。

 

也许原来你会写出这样冗长且超级难读的CAML查询串:

<Where><And><And><Or><Geq><FieldRef Name='_0x006e_um1' /><Value Type='Number' >15</Value></Geq>
<IsNull><FieldRef Name='_0x006e_um1' /></IsNull></Or><Eq><FieldRef Name='CreatedBy'/><Value Type='Integer'>
<UserID Type='Integer' /></Value></Eq></And><Gt><FieldRef Name='_0x1111__0x2222__0x3333__0x4444__0x5555__0x6666_' />
<Value Type='DateTime'><Today /></Value></Gt></And></Where>

 

但是现在,只需要用这种形式:

SELECT 标题, num1, [now] FROM 列表A

WHERE

(num1 >= 15 OR num1 IS NULL) AND 创建者 = ME AND 过期时间 > TODAY

 

敬请关注CollaDec,本Blog,以及OTEC

posted on 2007-09-14 00:02:00 by erucy  评论(5) 阅读(6873)

 
2007年09月12日

版本控制和文档修订留痕的比较是在文档管理中很重要的组成部分。在SharePoint中,版本控制是默认支持的。在mdms2003中,利用word2003的文档修订功能,以及event handler实现了将文档的修订留痕保留到SharePoint中的功能。在mdms2007中,也用了类似的方法。

但是熊总那天突然发现了word2007一个非常好的内置的版本比较功能,完全可以通过客户端来替代那种简陋的文档修订留痕记录。而且它支持和SharePoint中的文档版本做比较。(word果然是一个很强大的东西,只不过有80%的功能我们从来都没有用到过……)

比如在文档库中的某篇文档,其版本记录如下:

image

我们在线打开这篇文档(只读或者编辑都可以),然后使用版本比较功能:

image

这里可以和SharePoint上该文档的上一个主版本或者最新版本、或者任意的一个版本之间进行比较。我们选择1.0版本:

image

可以选择比较过程包含哪些内容。之后会打开一个很友好的页面列出两个版本的文档中有哪些地方不同(并可以方便地在几个不同处自由跳转)以及两篇文档的原文。(注意在原文中并不是通过修订的方式来修改的,也就是说版本间的差异是通过相似度计算得到的结果)

image

并且,我们可以把比较的结果(包含两个版本的差异)另存成一份文档保存下来(这个就不截图了)

总结!这是一个很有用的功能!不过也是有缺点的,就是文档版本的比较粒度不够细,是在句子和句子之间进行比较的,而句子中究竟修改了哪个词,只能靠人眼去看了。

posted on 2007-09-12 14:51:00 by erucy  评论(7) 阅读(8219)

 

在我以懒为借口的前提下,平时只是极其偶尔地更新一下普通的blog,写个游记、写个小说连载、接个镖什么的。然而就在懒洋洋地晃悠之间,发现周围的一票人都变成MVP了……

So, ......

posted on 2007-09-12 14:49:00 by erucy  评论(7) 阅读(6159)

 

根据熊总的指示和安排,在关于Search的startkit中,有关于IFilter和Protocol Handler这两大部分的内容。与一般的SharePoint开发不同的是,这两个关于Search的扩展是深嵌在底层的,需要直接使用C++的COM来编写……无奈我不会COM……不过至少看一看代码改一改还是可以的。实际上不论是IFilter还是Protocol Handler都不是SharePoint中的新生事物,早在windows desktop search中就有这俩东西的身影了(尤其是IFilter)。

IFilter比较顺利,网上的资料也比较多,虽然网上没有sample,但是可以从windows的sdk中找到几个例子,有简单的也有复杂的。于是照猫画虎地研究了一把mp3格式,写了一个mp3的IFilter。如果有机会地话再详细介绍IFilter吧。

而Protocol Handler这个东西就比较麻烦了,复杂程度不是IFilter可比的(实际上在Protocol Handler中,是包含了一种特殊的IFilter的),网上的资料很少,更别提sample code了。翻遍google和各个blog,只找到了一个用C#来编写的东西(来自John Kozell),不过这只是一个框架,没有实质的内容。我按照这个框架尝试写了个例子,无奈在moss上跑不成功,并且把moss的搜索给搞死了……于是只好等待。

(提外话,其实在SharePoint2001的sdk中,有一个Protocol Handler的例子,但是这个sdk已经找不到下载了……)

终于前些天等到了2007的SDK 1.2版发布,其中激动人心地包含了一个Protocol Handler的例子,拿过来翻了一遍代码,功能并不复杂,只是换一种方式实现了共享文件夹的搜索。但是,且不说这个sample毫无说明文档(那个readme.txt不算),当我试图编译它的时候居然编译都编译不过去……改吧了好几天终于在昨天晚上成功搞定,以下为内容。

这个sample编译不过的主要原因,是因为缺了一个资源文件:SampleProtocolHandler.rc(在readme里还有关于它的说明)。其实如果换一个对COM和ATL有些了解的人,估计搞这么个东西应该不费吹灰之力。关键是我不会COM……

该文件我放在otec上了,解压后请自己改个扩展名…… 地址:SDK 1.2中Protocol Handler Sample中缺失的文件

用这个rc的时候,需要把那个工程中资源的语言改成中文(0x804),当然把rc的语言设置改了也行。

几个关键问题:

1、由于我是在本机编译代码放到虚机上执行的,但是由于虚机上没装vc8(就是vs2005对应的C++),由于在vc8中,编译结果嵌入了manifest清单(这么干的目的是为了防止dll hell,从xp后设计出了一个类似于GAC的WinSxS[Side by Side]),所以要想在没装vc8的环境下运行vc8的程序或者使用其dll,必须先在环境中把对应的东西放到WinSxS里。方法很简单,在装了vc8的机器上,在vs的目录里有SDK\v2.0\BootStrapper\Packages\vcredist_x86这个目录,在需要部署的机器上运行里面的vcredist_x86.exe就行了,会把需要的那些dll扔进winsxs里。

2、在注册COM的时候,一般都是使用regsvr32.exe xxxxx.dll去注册的,实际上是调用了DllServerRegister方法。在sdk的那个sample中,注册表信息是写在那个rgs文件里的,按道理说rgs应该是在.rc中被引用,然后编译成.res,被链接到dll中。由于缺失了rc文件,所以这个注册信息没有写进去,导致了regsvr32注册失败,错误号0x80070715(没有资源)。补上rc后,发生了0x80070716,在资源内没找到注册信息,看了一眼发现是多写了俩引号……。再改再编译再注册,发生了0x80029c4a,未找到tlb文件。原来注册atl的com还要带着tlb啊……把tlb拷过去,终于注册成功了。

其实这里所谓的注册无非就是在注册表里填一些内容,如果有耐心的话,手填也行……我一开始就是手填的……

3、在moss中,新的Protocol Handler要新建一个内容源来跑,但是在管理中心中,没有out-of-box的界面去添加自定义的内容源类型。好在sdk中还有另一个例子是如何添加自定义内容源,这个就不多说了。

放个截图:

image

(爬网日志去爬那个sample://协议)

image

(搜索结果。可以看到除了搜到了sample协议,而且还搜到了mp3里面,这个归功于之前写的mp3的IFilter)

小知识:

IFilter:IFilter是在搜索时按照相应的文件类型、clsid或者progid去搜索该类文件内部的一个插件。在moss中提供了常见的一些IFilter,比如office文档、txt、html、xml等,在搜索时,可以对这些文档进行全文检索。第三方的IFilter主要有pdf和autocad的。其实在windows桌面搜索中已经用到了IFilter技术,在“我的电脑”中进行搜索的时候,会有一个搜索条件是文件内容包含什么什么的,这个地方就是利用了同样的IFilter来检索文件内部的。

Protocol Handler:在moss中进行爬网搜索的时候,会根据不同的类型采用不同的方式进行爬网,默认提供了对于http、sharepoint、exchange public folder、共享文件夹等类型协议的支持。在默认安装了moss搜索后,其支持的协议有:bdc、bdc2、file、http、https、rb、rbs、sps、sps3、sps3s、spsimport、spss、sts、sts2、sts2s、sts3、sts3s这些,可以看到有很多都是sharepoint自己的爬网协议。不同的协议采用了不同的Protocol Handler进行爬网。

posted on 2007-09-12 05:43:00 by erucy  评论(5) 阅读(7162)

 

Powered by: Joycode.MVC引擎 0.5.2.0