RSS 2.0 Feed

Sunday, August 17, 2008

【SharePoint】:

SharePoint (MOSS) 2007 有了一个 SharePoint Online 服务了。这个是 Microsoft Online Services 的一部分,也是微软的“Everything could be hosted” 口号的具体落实。除此之外,还有 Exchange OnlineOffice Communications OnlineCRM Online

msonline

CheckList for custom code (MOSS 2007): 采用对象模型的自定义开发方式,使得开发人员可以在MOSS 2007平台上进行各类扩展方案开发。但是同时,一个粗糙不当的设计或实现,都将把MOSS自定义应用带入深渊,轻则慢得比乌龟还慢,重则异常不断经常出错。这个时候,或许该下载一份 Code Checklist 给开发人员,好好对这 checklist 一条一条检查看看是否符合,以此在避免不必要的风险下,尽情享受到MOSS2007各种好处。

SharePoint Governance:貌似Governance这词比较酷还是怎么的,越来越多人喜欢用这个词了。比如 IT Governance,翻译为IT治理;那么 SharePoint Governance,就叫SharePoint 治理吧。按官方翻译过来,所谓SharePoint治理,就是使用基于SharePoint的产品和技术来指导开发和方案应用的,集角色、职责和过程于一体的套件。听上去应该是“上层建筑”,不过可以用 SharePoint Governance Tools 来辅助实施看看。至于用后的效果如何,“谁用谁知道”。

除此之外,MS还公布了一些协议规范(协议技术规范),SharePoint发烧友可以去下载回去烧烧。

【WPF-Silverlight】:

.NET 3.5 中新增了一个新的 WebBrowser 控件用于 WPF 应用中。以后在 WPF 程序中就不要用以前的 WinForm WebBrowser 了,直接在XAML中写<WebBrowser>标签即可。

这里还有一个酷酷的 WPF 资源站点 Blendables.com,可以下载到很多酷炫的 WPF 范例。比如,这个鹰眼缩放功能的WPF Demo,就是一个非常酷的Demo。一看 Blendables 名称,估计大家也应该猜到站长是位 Blend 粉丝了。关于 Blend,网上发现一个相对完整的网上教程,虽然是Beta版本的,但仍然值得一看。

DataGrid 这个东西还在 WPF 中吗?嗯,看看 WPF Toolkit 这个玩意儿,不过之前你得打个 .NET 3.5 SP1。

最后,show 几个demo养养眼:

wpf001

hardrock

posted @ | Feedback (0) |

Sunday, April 06, 2008

MOSS里的CMS/Portal,需要进行高度的自定义,除非你觉得MOSS默认的“款式”就是你要的。PixelMill,我觉得它所发布的SharePoint SimpleCMS就是一款不错的应用。你可以观看 Video: Simple CMS for WSS,看看这个应用的一些具体使用方式,吸收下实例经验。我个人比较喜欢其中自定义的图片上传方式和新闻发布方式,这些符合用户操作习惯的应用才能生存。

image

MOSS里的Search,也是很好很强大的。在Codeplex中已经有了一个Search Community ToolKit,可以让你如虎添翼。比如其中的Smart Search,可以做出常见的相关搜索、搜索排行等,上海科技网站的搜索就是其中一个示例。

image 

SharePoint Team Blog上介绍了一个很酷的SharePoint应用Wonders。在那个Virtual Earth Flash上标注的各种颜色的小点,实际上是读取SharePoint List中的数据信息动态显示的。这是一个非常好的SharePoint数据整合范例,就像文章说的:"IDV Solutions’ Visual Fusion software extends SharePoint to create a visual composite application platform, empowering users and the enterprise to consolidate data and services surfaced in SharePoint and then compose them in the context of location and time".

image image

对于SharePoint,Web Site是一个很关键的概念,其不被关注很让人奇怪。对于Web Site,上有Farm、WebApp,下有List、Library,外有Template、Theme,内有Feature、Content Type等等。对于开发人员来说,Web Site意味着:

1、内容存储容器:List存储各类数据、Library存储各种文档、Sub WebSite用于区分和组织内容。

2、UI呈现:MasterPage母版页定义界面风格、Layout Page定义页面排版、Form Page定义List/Library的增删改查页面、Web Part定制化页面、Application Page提供全局访问页面、Site Page提供站点级访问页面、各式各样的Web Controls、Field Controls定义页面内部数据元素。

3、安全模型:User/Group定义用户和用户组的权限、对Web Site、List、Library、ListItem提供权限设置。

对应一个普通的ASP.NET Web应用的开发模式和方式,对照下SharePoint Web Site,好像能得出点什么,当然这个需要自己去体会了。在此之前,推荐 Ted Pattison 里的一些例子,那可是很好很强大的范例。

posted @ | Feedback (5) |

Sunday, August 05, 2007

不知不觉之中,又有一个新概念逐渐充斥在各个技术社区中。OBA,全称为 Office Business Applications,较早之前,Javed Sikander在MSDN中发表了一篇名为《Building Office Business Applications: A New Breed of Business Applications Built on the 2007 Microsoft Office System》的文章中定义它为“a new breed of easily customizable solutions that address real-world business problems through the 2007 Microsoft Office system”。但在我能看到的大多数介绍OBA文章中更接近Justin的定义——“Office Business Applications can be defined as a class of applications that connect Line of Business systems with the people who use them everyday”,简单理解就是,OBA 是用来连接用户生产力工具软件(比如MS Office)和 LOB 系统的一种应用类型。从定义看,就是业务用户从原来直接使用LOB转换到尽量通过用户日常使用的办公软件(可以是MS Office System,也可以是其它应用软件产品)来使用LOB。

对于OBA的桥梁作用有多少种实现模式呢?MS Office System的OBA应用给出了比较齐全的实现模式

比如Direct integration Pattern,可以是Outlook直接调用远程LOB的WebService,也可以是MOSS Portal直接用HTML嵌入LOB System信息。

再比如,Embedded LOB Information Pattern,直接在Office文档中嵌入LOB数据元素,最终直接通过Office客户端与LOB System交互。

当然,也可以直接反过来从LOB System生成含LOB Data的Office文档,然后提交到MOSS文档库进行工作流流转等。这一系列模式之间的关键理念就是,把用户平常最常使用的MS Office客户端直接与公司中LOB System实现各种方式整合,并引入Office服务端(如MOSS)的各类应用和服务,为整个整合提供更全面的支持。

也许你会理解OBA为一个框架,但从我理解上,我更倾向理解OBA为一种桥梁性应用,通过OBA应用我们可以有相关解决方案框架。比如atanu的OBA Solution Framework系列是目前这方面比较全面的介绍说明了。

MS的OBA架构如下所示。

posted @ | Feedback (2) |

Sunday, July 22, 2007

以前弄个了用于AD OU、帐号和组等对象的几个类(见《活动目录操作类更新》),现在对这个再进行一点改进和增加一些功能。貌似gotdotnet workspace已经无法使用,过些日子我把更新后的类库发布在codeplex上再发布个具体链接出来。

修改/增加的地方:

1、权限机制:摒弃在配置文件中配置域管理员帐号密码的方式,而采用重新用COM+安全身份来执行整个AD操作。

2、用户:修正Lock/UnLock和Enabled/Disabled,Mail-Enabled/Mailbox-Enabled的用法。

3、组:修正创建组时无法指定Group Scope/Group Type的问题,增加对各类型组的创建支持。同时支持更改组Owner,和设置管理Membership list的属性。

其中更新Membership list属性的更改比较有意思。因为在AD中并没有一个属性与之对应,只能通过修改访问规则来设置:

ActiveDirectorySecurity ads = myGroup.ObjectSecurity;
ActiveDirectoryAccessRule accessRule = new ActiveDirectoryAccessRule(
          new NTAccount(Domain, samAccountName),
          ActiveDirectoryRights.WriteProperty,
          AccessControlType.Allow,
          new Guid("bf9679c0-0de6-11d0-a285-00aa003049e2"));

ads.AddAccessRule(accessRule);
myGroup.ObjectSecurity = ads;
myGroup.CommitChanges();

4、Mail相关:增加了对Exchange Server/StoreGroup/MailStore/Mailbox的各类操作(相关见《枚举Exchange Server, StoreGroups, MailStore》)。同时支持对proxyAddresses等属性的修改设置。

其中更新proxyAddresseses并设置 Primary proxyAddress也比较有意思,摘出供参考:

       private void UpdateProxyAddresses(DirectoryEntry userEntry, ArrayList emailAddresses)
        {
            PropertyCollection properties = userEntry.Properties;
            PropertyValueCollection proxyAddresses = userEntry.Properties["proxyAddresses"];

            if (proxyAddresses != null)
            {
                for (int i = 0; i < emailAddresses.Count; i++)
                {
                    string emailType = emailTypes[i];
                    string emailAddress = emailAddresses[i].ToString();
                    int schemaIndex = Array.IndexOf(emailTypes, emailType);

                    if (schemaIndex > -1)
                    {
                        // Is it the primary address
                        if (schemaIndex == 0)
                            userEntry.Properties["mail"].Value = emailAddress.ToString();

                        string emailPrefix = emailPrefixes[schemaIndex];
                        bool found = false;

                        for (int j = 0; j < proxyAddresses.Count; j++)
                        {
                            string proxyAddress = proxyAddresses[j].ToString();
                            if (proxyAddress.StartsWith(emailPrefix + ":"))
                            {
                                proxyAddresses[j] = emailPrefix + ":" + emailAddress;
                                found = true;
                            }
                        }

                        if (!found)
                            proxyAddresses.Add(emailPrefix + ":" + emailAddress);
                    }

                    userEntry.Properties["proxyAddresses"].Value = proxyAddresses.Value;
                }
            }
        }

        public void MakePrimaryProxyAddress(DirectoryEntry userEntry, string newMailAddress)
        {
            System.DirectoryServices.PropertyCollection properties = userEntry.Properties;
            PropertyValueCollection proxyAddresses = userEntry.Properties["proxyAddresses"];

            if (proxyAddresses != null)
            {
                bool found = false;

                for (int j = 0; j < proxyAddresses.Count; j++)
                {
                    string proxyadd = proxyAddresses[j].ToString();

                    if (proxyadd.StartsWith("SMTP:"))
                    {
                        found = true;
                        string[] proxyparts = proxyadd.Split(':');
                        proxyAddresses[j] = "smtp:" + proxyparts[1];
                    }
                }

                if (!found)
                {
                    proxyAddresses.Insert(0, "SMTP:" + newMailAddress);

                    userEntry.Properties["proxyAddresses"].Value = proxyAddresses.Value;
                }
            }
        }

BTW, Workflow Foundation又有2篇经典文章值得一品:

posted @ | Feedback (3) | Filed Under [ Active Directory ]

Friday, April 27, 2007

1. 关于Check-out 锁定的错误:

当针对表单库关联Workflow后,用InfoPath客户端打开表单填写表单,填写完直接用Save保存回表单库。按设置,一保存回去就自动触发了工作流。但是触发后,有时可以,有时却报了Occured Error的错误,工作流加载失败。

由于有存在成功的现象,因此怀疑哪里环境出了问题。后来在Central Administration v3中配置了记录Workflow Infrastructure的详细日志,才发现出现了说该表单被Check out,然后已经处于锁定状态,所以工作流无法启动的异常信息。

这是个非常奇怪的问题。一直无法找到真正问题根源,不知是否为Bug。最后只能绕过该问题,在表单最后放了一个提交按钮,自动提交后自动生成唯一文件名保存在SharePoint Form Library中,然后马上关闭表单即可。

2. 用SPD 2007设计Workflow的建议:

记得,开发人员不到万不得已不要用SharePoint Designer 2007来开发工作流。这种事情让业务人员(如果有这种业务人员)去干这活吧。毕竟我个人以为SharePoint Designer 2007应该是定位在业务人员使用上的。开发人员老实开发Activity让业务人员用SPD 2007去设计工作流,或者直接用VS2005开发设计工作流才是正确的做法。

SharePoint Designer 2007和Visual Studio2005两者用来设计工作流的初衷都是为了让技术人员尽量管技术,让业务人员尽量分析处理业务。对此,DSL是用于沟通IT人员和业务人员的一个不错的选择;但Visual Studio 2005下的设计工作流更适合于开发人员,只不过通过DSL来缩小了与业务人员之间的Gap。而SharePoint Designer 2007,经过我这段时间作为开发者的快乐并痛着的经历,我觉得它完全是为业务人员而定制的一个产品,而非开发人员。最有力的证据就是——对SPD 2007设计的工作流的部署!你在测试环境用了SPD 2007进行设计了工作流,那就别指望能完全正确的直接部署到正式环境中,最有效的做法就是完全用SPD 2007再在正式环境中实施一次,或者用了站点模板部署后起码你还得用SPD 2007再打开正式环境的Workflow“编译”一次。这是一个另人抓狂的动作。

3. 基于Silverlight的Web Workflow的想法:

以前,有一个想法,就是做一个基于WPF的MOSS Document Sync工具。用于本地文件夹与MOSS Document Library做同步的一个TrayIcon小软件,主要功能当时就做了几点:

  • 任务栏界面
  • 集成和管理AD身份
  • 设置本地和MOSS文档库同步目录(可对应到文档库或文件夹)
  • 支持私人文档库和共享文档库
  • 支持单文件下载或多文件、文件夹打包下载
  • 集成MOSS Search

后来很郁闷的我的移动硬盘丢了,该工具源代码连同很多积累多年的宝贝一起从人间蒸发了。装了Vista系统后就懒得再去重新整理这块代码,所以以前和人提起过这个咚咚,但后来友人跟我要去尝试时,一时糗大,只好用其他好处打发之 -_-|| 当时之所以开发这个工具,主要是得益于虚拟了一个磁盘来和远程FTP同步的一些工具软件的想法的激发,同时也是作为长期不在Office的人之间基于MOSS互相交流文档的一个补充。

现在WPF/E终于Release了版本Silverlight出来,正好以前接触过一个Web上拖拉设计Workflow的业务型应用,也看过http://www.netfxlive.com/之类的 Web工作流设计器,于是有个想法,想在Silverlight和Workflow Foundation上做一个偏向公文或普通文件流转业务的可拖拉的Web Workflow应用。目前还在构想中,有三四个技术点还在验证。因为个人编程属于爱好,所以兴致来了连夜写着就很快,没来或忙时就会显得拖拉点,所以这个应用在时间长度上会显得长点,一有任何进展会随时跟大家沟通,也欢迎有任何这方面兴趣或经验的人一起交流。

posted @ | Feedback (3) |

Monday, April 16, 2007

对WCF的了解还停留在2006年初看Indigo的地步。当时看了一本MS 2005年出版的《Programming Indigo》电子书,是一本非常棒的书,我只记得当时作为初学者我看第一遍的时候,对其中每个章节中的相关概念定义都能心领神会,这就说明这本书是一本非常棒、值得收藏的书。因为WCF的核心就是接口协议定义,而它做到了让初学者能迅速理解这些接口协议。

对于学习WCF,我个人理解是一定要理解WCF中的接口协议定义和规则约束!了解这些远远比你去看看Code,写写Sample来得重要许多。从某种意义上,学WCF就是学概念、学定义、学规则、学接口协议,而不是让你像学C#或ASP.NET那般追求深入实际应用,然后再去反过来体会C#/ASP.NET原理。

一晃,Indigo更名为WCF并入.net3.0概念中。天天念叨着WCF、WPF、WF,可是除了WF还顺应潮流接点轨外,WCF就停在Indigo阶段,WPF更仅仅只了解其相关的XAML知识。正好最近越忙越是精力充沛,抽空花了两三个小时翻了2007年2月刚出版的《Programming WCF Services》一书,算是在Indigo基础上重新认识了下WCF,感觉还OK,各类细节变来变去,但只要它的接口协议、概念定义没变就好办,剩下的就是从《Programming WCF Services》新书中挑几章自己兴趣的或感觉变化比较大的再细细品味下,也算完成本书的阅读工作了。

昨天我说花了一夜用HTML+Photoshop+Javascript搞了个系统原型,于是有人开始质疑我这个做法是否值得,理由是让美工或其他人搞个比自己搞既快又好。我承认自从99年接触Photoshop 3.0/4.0以来,我的美工水平一直停滞在满足图片的修修补补,让专业美工搞这个自然是快而好。但我想做一件事情,更多的应该是看做这件事情的目的。系统原型相当于建筑行业的图纸,其更多的价值在于迅速构建一个与用户沟通的管道,确保做出客户想要的东西,同时为后面的系统设计提供了基础约束。由于业务复杂,加上时间紧张,自己也弄过ps,就凑合了,最终效果也不错。

 MS发布了个Windows Workflow Foundation Web Workflow Approvals Starter Kit,算是给了ASP.NET开发人员一个交待。

最近在做EPM,不过这个EPM没有用Project Server,却是完全用ASPNET + SQLServer搭建,这也是各种原因造就。不然利用 Project Server,一个小时应该可以搭建出一个简单却实用的 EPM 应用出来。恰巧上次和网友讨论过一些 MS 企业服务器产品的主要应用业务,这里也稍微整理下一些我接触过的MS服务器产品,不对的地方还请指正。

  • Project Server:  EPM
  • SPS: Portal
  • WSS: Team Work (Document Mgmt)
  • BizTalk:  EAI
  • Commerce Server: EBusiness
  • Content Management Server:WCM
  • Exchange:Mail, Message platform 
  • LCS:IM
  • MOSS:Portal+WCM+ECM+BI+Search+BPM

posted @ | Feedback (1) | Filed Under [ 个人评论和作品 微软企业服务器 ]

Tuesday, April 10, 2007

先看 Kaneboy 的《SharePoint Designer 2007, 强大的工作流设计器》。然后,我们针对利用 SPD 2007进行扩展、设计工作流三个常见问题做一些回答。由于开始步入大忙期,时间和精力有限,每个问题我都只点到为止,具体更细节就不累赘。

1、“从用户处收集数据”这个Action中输出的输出变量是什么,做什么用?或者换个问法,我怎么获取用户填写在收集表单里的数据?

A:输出的变量实际上是任务列表中的ItemID。“从用户处收集数据”这个Action是一个强迫工作流暂停以等待用户进行操作的过程。该Action实际是以任务形式在任务列表中新建一条任务向用户派发,然后用户上来编辑任务进行录入数据,以完成任务。这个输出变量ItemID就是用来定位获取用户填写的数据项的。在Conditions中放入“比较任意数据”,选择“任务”列表要查找用户输入值的哪个字段,然后下面把任务ID和输出变量关联即可。

2、初始变量Initiations和变量Variables有何区别?

A:初始变量赋值于工作流启动前,而Variables则赋值于工作流启动后。二者均在整个工作流生命周期内可用。初始变量工作流务必设置默认值,用于当新建就自动触发工作流的情景。无法通过查找获取到的数据,或者多次反复使用的数据都可以存入变量Variables中,以便在Workflow周期里方便使用。

3、自定义扩展Activity中,如何获取当前SPWeb、SPList、SPListItem、SPFile等?比如,最简单的,如何获取当前工作流运作的ListItem数据?

A:完全可以在自定义Activity中通过WorkflowContext上下文获取到当前项或当前SPWeb等信息。除非你要获取其他Site的数据,否则就没必要用去把Site Url、List Guid或ListItem ID等这些数据信息作为输入参数让工作流定制人员来手工输入以获取相关对象。

下面为一个代码模板(LiveWriter不支持代码色彩,就看黑白的代码吧):

public class MyActivity: Activity
{

#region Properties

public static DependencyProperty __ContextProperty = DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(MyActivity));
[ValidationOption(ValidationOption.Required)]
public WorkflowContext __Context
{
    get
    {
        return (WorkflowContext)base.GetValue(__ContextProperty);
    }
    set
    {
        base.SetValue(__ContextProperty, value);
    }
}

public static DependencyProperty ListItemProperty = DependencyProperty.Register("ListItem", typeof(int), typeof(MyActivity));
[ValidationOption(ValidationOption.Required)]
public int ListItem
{
    get
    {
        return (int)base.GetValue(ListItemProperty);
    }
    set
    {
        base.SetValue(ListItemProperty, value);
    }
}

public static DependencyProperty ListIdProperty = DependencyProperty.Register("ListId", typeof(string), typeof(MyActivity));
[ValidationOption(ValidationOption.Required)]
public string ListId
{
    get
    {
        return (string)base.GetValue(ListIdProperty);
    }
    set
    {
        base.SetValue(ListIdProperty, value);
    }
}

#endregion

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
    Guid listGuid = Helper.GetListGuid(__Context, ListId);
    SPList list = __Context.Web.Lists[listGuid];
    SPListItem item = __Context.GetListItem(list, ListItem);

    // 做自己的事 :)

    return ActivityExecutionStatus.Closed;
}

 其对应在 WSS.ACTIONS 中的节点配置如下:

<Action Name="测试Activity"
ClassName="TestActivities.MyActivity"
Assembly="TestActivities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=dd27a7cb343a4cac"
AppliesTo="list"
Category="我的自定义操作">
    <RuleDesigner Sentence="输出 %1 到数据库">
         <FieldBind Field="ListId,ListItem" Text="此列表" Id="1" DesignerType="ChooseDoclibItem" />
    </RuleDesigner>
    <Parameters>
        <Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions" Direction="In"/>
        <Parameter Name="ListId" Type="System.String, mscorlib" Direction="In" />
        <Parameter Name="ListItem" Type="System.Int32, mscorlib" Direction="In" />
    </Parameters>
</Action>

几点说明:

  • AppliesTo="list" 表示应用到列表,还可以有 AppliesTo="all" 表示应用到包括列表在内的所有sharepoint库表。
  • Category="我的自定义操作",就表示你在 SPD 2007中看到的 Actions 的分类。
  • Action 内属性还有 ListModeration="true" 表示是否要显示未经审核的项,UsesCurrentItem="true" 表示直接使用当前项。
  • DesignerType="ChooseDoclibItem" 表示点“此列表”后弹出选择对话框(ChooseDoclibItem限文档库,列表可用ChooseListItem),以选择参数 ListId 和 ListItem。DesignerType表示SPD 2007支持的各种类型,如整数Integer、字符串String,电子邮件Email(含Email关键参数,类似Field="To,CC,Subject,Body"),单个人员SinglePerson,多个人员Person,参数类型ParameterNames,待更新项类型UpdateListItem(类似Field="ListId,ListItem,ItemProperties"),还有一个我们第一个问题用的“向用户收集数据”用到的类型Survey。SPD 2007设计器都支持这些类型的直接设计,因为也才体现出其强大之处(当然也有不足,如不支持InfoPath,不支持调试,不支持StateMachine等)。
  • Id="1" 表示对应 Sentence 中的 %1。比如上面效果,你在SPD 2007将看到显示为“输出 此列表 到数据库”,点此列表后,将弹出让你选择你要的项。
  • 下面Parameters节点里就比较好理解了,只要注意 Direction 有 In 和 Out 作为输入参数和输出参数即可。

 SPD 2007 设计工作流基本也就这些东西,主要要扩展的还是需要你用 VS2005 来自定义 Activity 配合,才能达到最大灵活性。

剩下的就是发挥想象力动手吧。

posted @ | Feedback (3) |

Sunday, April 08, 2007

Sahil Malik 最近一连发表了10篇关于 MOSS BDC 的文章,真是让人振奋:

  1. SharePoint 2007: BDC - The Business Data Catalog
  2. SharePoint 2007: BDC - The Hello World Example
  3. SharePoint 2007: BDC - Extending the Hello World Example
  4. SharePoint 2007: BDC - Extending the "Hello World" example even further - adding specific finders
  5. SharePoint 2007: BDC - Using BDC Data in Lists
  6. SharePoint 2007: BDC - Custom Actions on your Entities
  7. SharePoint 2007: BDC - Introducing associations between entities
  8. SharePoint 2007: BDC - Enabling Search on business data
  9. SharePoint 2007: BDC - User Profiles
  10. SharePoint 2007: BDC - Writing Custom Code against the runtime object model

如果涉及到表单中托管代码(VSTA or VSTO 2005 SE)的编写使用,《InfoPath 2007 Document: Developing InfoPath 2007 Managed-Code Solutions》这篇文档你不得不看。

MOSS Workflow中,这里有一篇文章《A WorkFlow that Uploads a Document via a Task using an InfoPath Form》介绍了如何在InfoPath Task Form中上传处理附件。

谈到Workflow,上次在《Workflow 问题与互联网三化》中提到一本Workflow Foundation的书籍《Essential Windows Workflow Foundation》(简称EWF),前些日子,看了ccboy写的一篇对该书的书评,实在很精彩。同时,他还推荐了另外四本相关书,其中一本〈Programming Windows Workflow Foundation〉我也翻了一遍,感觉确实这本书挺适合作为初学者入门的好书,通俗易懂且覆盖面广。其他两本没看过,不过ccboy推荐,应该必属精品。

对于《Programming Windows Workflow Foundation》一书,相对深入浅出的EWF一书来说,这书的叙述顺序倒是中规中矩很适合入门,从Hello Workflow示例到说明XAML Workflow和Code Workflow的关系,从Workflow Runtime Services、Workflow Instance生命周期到Workflow Hosting,从每个具体的Activity讲述到如何自定义Activity,从Sequential Workflow到StateMachine Workflow……一步一步引导你到Workflow Foundation的大门里。

但是窃以为,在看完这些书后,你只是学到了如何使用Workflow Foundation这门技术,或者说开发平台来进行工作流的开发而已。而现实中的工作流往往需要理解业务相关的知识,需要站在用户的角度或者业务人员的角度来分析工作流,这才能真正达到工作流的要求。这点也是 Workflow Foundation的一大优势——DSL!关于这点,强烈建议看看Architecture Journal的一本期刊,了解工作流许多原理和业务场景。在学习Workflow Foundation的同时,在使用每个Activity的同时,想想这些Actitivy可以应用到哪些具体业务场景达到什么样的功能。否则,空有一身蛮力却无法应用自如,也是很痛苦的一件事。

posted @ | Feedback (5) | Filed Under [ 个人评论和作品 微软企业服务器 ]

Wednesday, March 28, 2007

对于普通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:

posted @ | Feedback (17) | Filed Under [ 微软企业服务器 ]

Saturday, March 17, 2007

在MOSS Document Library中的Page,有Basic Page和WebPart Page两种,前者更多的体现WCM特性,后者则更侧重体现Portal特性。

不管是Basic Page还是WebPart Page,都是直接和MOSS本身结合非常密切,都直接采用Site中的MasterPage。如果我们想把一个普通的ASP.NET Page也加到MOSS站点里运行,比如也放在Document Library里,或者放在Site某个文件夹下面,然后通过MOSS站点URL直接访问运行该ASP.NET Page,就需要做一些工作了。这里就准备介绍这么一个Tip来完成这件事。我想,这种应用方式主要是针对一些需要特殊页面效果,或者追求短平快的小量自定义的场景的,也不失为各类复杂应用场景提供一个可以方便Work Around的通道。正常应用场景中一般比较少用到。

1、首先从最简单的Hello World Page开始。点击此处查看 HelloWorld.aspx 源代码

2、将HelloWorld.aspx上传到Documents文档库中。此时,你直接点击文档库中的HelloWorld.aspx进行浏览,其URL类似http://localhost/Documents/HelloWorld.aspx,将出现“An error occurred during the processing of /Documents/helloworld.aspx. Code blocks are not allowed in this file.”的错误异常。通过这个异常信息也就知道,其实我们要做的就是允许在Page Server Code能被顺利编译执行

3、修改MOSS Site的web.config,比如C:\Inetpub\wwwroot\wss\VirtualDirectories\80\web.config。找到PageParserPaths这么一个节点,修改如下:

<PageParserPaths>
    <PageParserPath VirtualPath="/Documents/helloworld.aspx" CompilationMode="Always" AllowServerSideScript="true" />
</PageParserPaths>

4、重新浏览http://localhost/Documents/helloworld.aspx,页面正常被编译执行。

至此已经验证普通的ASP.NET Page是可以顺利集成在MOSS中被执行的。可以看到CompilationMode="Always"就意味着这个操作是属于“不得已而为之”的了,但这类不得已的场景现实应用中毕竟还是存在的。下面发散思维,扩展下思路。

5、我们把SharePoint的一些接口也写在这个普通ASP.NET Page里,从这个ASP.NET Page去操作SharePoint的库表等相关信息。点击此处查看 HelloSharePoint.aspx源代码