使用过Microsoft SharePoint Portal Server 2003(简称SPS2003)或Windows SharePoint Services 2.0(简称WSS v2)的朋友可能还会记得,在SPS2003及WSS2.0的管理中心(或使用命令行)可以管理路径:管理包含的路径和排除的路径。通过这种方式可以明确把一些路径标识为可由SharePoint 负责管理(路径包含);也可以明确让SharePoint将忽略某些路径(路径排除),排除的路径可由其他应用程序使用,比如普通的asp.net应用程序可使用路径排序的功能来实现。
但从最近几年对SharePoint2007(很多时候我用“SharePoint2007”来代替MOSS2007或WSS3.0,如果所述内容在两者中有区别我会明确使用MOSS2007或WSS3.0)的使用来看,并没有发现在MOSS2007(或WSS3.0)中发现路径排除的功能,本周五下午与微软某一SharePoint技术人员交流,被告知“设计sharepoint2003中的‘路径排除功能’的人的脑子就有毛病,MOSS某些地方压根不能排除路径……”,呵呵,偶对此话不敢完全苟同,今天晚上经过一段时间研究,发现虽然在SharePoint2007的默认管理界面和命令行不能实现“路径排除”的功能,但通过一定的配置就可以轻松达到此目的。
那么如何做呢?
实现我们从相关的技术角度,了解一下Windows SharePoint Services 2.0与Windows SharePoint Services 3.0底层架构的不同:
1、Windows SharePoint Services 2.0(以下简称WSS2.0) 是基于ASP.NET 1.1 构建的,它大量使用了ASP.NET 1.1 的内置功能,但同时也使用了另外一项技术——对虚拟服务器进行了扩展。对于普通的(未扩展的)ASP.NET1.1的应用程序来说,当IIS 接收到HTTP 请求之后,它会将扩展名是.aspx/.asmx 等ASP.NET 相关扩展名的页面请求直接转发给ASP.NET 引擎,然后由ASP.NET 引擎处理相应的请求,比如解析.aspx 页面、编译代码等工作。ASP.NET 引擎将请求处理完成之后,再将返回的数据(比如HTML 文本)返回给IIS,最后由IIS 返回给发出请求的客户端。但如果一个虚拟服务器被WSS2.0扩展之后,当IIS 接收到HTTP请求时,该请求会被传送给“stsfltr”这个ISAPI 过滤器(这个筛选器就是WSS2.0 实现自己特殊功能的一个关键组件)。“stsfltr”过滤器会检测当前请求的页面路径是不是一个SharePoint 包含的路径,如果是,那么这个请求将不会直接传递给ASP.NET 引擎,而是交给WSS2.0进行处理。
WSS2.0得到这个HTTP 请求后,会根据配置数据库中的信息,从某个合适的地方(磁盘上的模板文件或者数据库中保存的页面文件)将页面载入,然后才会再将页面交给ASP.NET 引擎进行处理。也就是说,对于一个被WSS2.0扩展了的IIS站点,除了几个特定的路径之外,对其他路径的访问请求,都会被SharePoint 的ISAPI 扩展接管过去。这几个特定的路径被称为排除的路径。如果用户通过浏览器访问这几个排除的路径下的页面,那么将直接访问到磁盘相应目录的物理文件。管理员(或有权限的用户)也可以通过SharePoint 管理中心,自己定义SharePoint 包含的路径和排除的路径。WSS2.0的整体架构图如下:

2、Windows SharePoint Services 3.0 (以下简称WSS3.0) 在WSS2.0的基础上,对其底层架构进行了重大的更新。而更新的关键,就是从ASP.NET 1.1 到ASP.NET 2.0 的转变。ASP.NET 2.0 极大地增强了其扩展性和灵活性。比如,ASP.NET 2.0 中的很多模块都使用了Provider 模式,使开发人员可以灵活地用自己编写的定制模块取代ASP.NET 2.0 中自带的各种功能模板。WSS3.0 使用了ASP.NET中的HttpHandler和HttpModule 扩展技术,以及ASP.NET 2.0 中新增的Virtual Path Provider 功能,来实现WSS2.0 中的“stsfltr”以及ISAPI 扩展同样的功能。同时,WSS3.0 修改了这个虚拟网站的文件映射设置,将所有文件的请求全部转给ASP.NET 引擎处理。在一个普通的ASP.NET 站点中,通常只有ASP.NET 相关的应用程序文件访问请求,比如.aspx、.asmx,才会转给ASP.NET 引擎处理,而一些普通的文件访问请求,比如.doc、.zip,会由IIS 直接处理。IIS 通常从磁盘上读取文件内容,然后直接将文件内容返回给客户端。但是由于WSS是将所有的数据内容,包括文档库中的文件,都存放在数据库中的,因此,当客户端请求一个存放在SharePoint 站点中的文件时,必须首先将请求传递给ASP.NET 引擎,然后WSS3.0 中的模块会处理这个请求,从适当的地方载入适当的文件,再进行相应的处理。WSS3.0的整体架构图如下:
从上图可以明显看出,在WSS3.0下,所有的HTTP请求都由IIS经ASP.NET Hangdler提交给Windows SahrePoint Services3.0处理后再提交给默认的ASP.NET2.0引擎处理。那么具体点结合下图进行分析:
需要特别说明的是:WSS站点的根路径也相当于一个文件夹【这点请一定要特别注意】,也就是说,默认情况下,直接在类似C:\Inetpub\wwwroot\wss\VirtualDirectories\80下增加asp.net页面程序,如添加love9.aspx,那么通过http://webplat/love9.aspx也是不能访问到C:\Inetpub\wwwroot\wss\VirtualDirectories\80下的love9.aspx;而还是到SharePoint中去找相应页面。原因就是根文件下的所有文件默认情况下不能排除路径。我们称这类文件夹为“SharePoint2007默认不能排除路径的文件夹”!
除了“SharePoint2007默认不能排除路径的文件夹”,对于HTTP请求的文件,如本地ISS下Test文件夹下的Default.apsx,如果其在SharePoint数据库中应对应的路径Teat/Default.apsx,则先由WSS3.0得到SharePoint中的该文件后再交给ASP.NET2.0进行处理;但如果所请求的文件不在sharepoint数据库中,如love9_webplat.aspx,则WSS3.0将直接把该文件请求交于ASP.NET2.0进行处理。也就是说,在WSS3.0架构下,在非“SharePoint2007默认不能排除路径的文件夹”下,如果在sharepoint中不存在相应该文件,则将会直接到相应的物理磁盘上去找相应文件。所以,从这个角度来说,MOSS2007和WSS3.0根本不需要提供“路径排除”的功能。因为除了几个默认不能被排除的文件地址外(如根路径),其他默认情况下完全已提供路径排除的功能,只不过对于相同路径的相同文件,SharePoint文件优先!
从上面一些架构分析来看,不像微软某技术人员所说的“设计sharepoint2003中的‘路径排除功能’的人的脑子就有毛病””,实则是WSS2.0的底层架构做了更新所致。也不是“sharepoint2007某些地方压根不能排除路径”,实则是默认情况下SharePoint文件和普通ASP.NET文件完全一样对待,只不过对于且相同路径下的相同名称的文件,SharePoint文件优先!
呵呵,到现在为止,SharePoint2007为什么没有在管理中心提供“路径管理”的功能呢,我想就不用解释原因啦,哈哈
那么还需要解决一个问题,才能彻底自定义路径排除功能,那就是,"对于相同路径下的相同名称的文件,如果不让SharePoint文件优先?",也就是说“如何使本地磁盘文件的可优先被访问呢?”
假设一下应用场景:我有一个SharePoint站点,首页URL是http://webplat/default.aspx,也就是说,在SharePoint数据库中存在文件default.aspx(用SharePoint Designer打开站点http://webplat/就可以看见default.aspx),那么如果我想要在访问地址http://webplat/default.aspx的时候,不从SharePoint数据库里访问文件,而从本地磁盘中访问,比如C:\Inetpub\wwwroot\wss\VirtualDirectories\80下的default.aspx(其对应还可能存在default.aspx.cs),那要如何做呢?
1、进入C:\Inetpub\wwwroot\wss\VirtualDirectories\80,放入两个文件,一个default.aspx,一个default.aspx.cs,相应代码如下:
default.aspx代码:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="default.aspx.cs" Inherits="_Default" %>
- <html>
- <head runat="server">
- <title></title>
- </head>
- <body>
- <form id="form1" runat="server">
- <div>
- </div>
- <asp:Calendar ID="Calendar1" runat="server"></asp:Calendar>
- <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
- <asp:Label ID="Label1" runat="server"></asp:Label>
- </form>
- </body>
- </html>
default.aspx.cs代码:
- using System;
- using System.Collections.Generic;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
-
-
-
-
- public partial class _Default : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
-
- }
- protected void Button1_Click(object sender, EventArgs e)
- {
- this.Label1.Text = this.Calendar1.SelectedDate.ToString();
- }
- }
2、打开C:\Inetpub\wwwroot\wss\VirtualDirectories\80下的web.config(也就是SharePoint站点对应的Web Application下的web.config),找到如下几行代码:
- <httpHandlers>
- <remove verb="GET,HEAD,POST" path="*" />
在上面两行代码之间加入一行代码,修改后的代码如下:
- <httpHandlers>
- <!--文件排除:自定义本地文件优先 开始--><!--love9:2008年12月7日23:05:13-->
- <add verb="*" path="default.aspx" type="System.Web.UI.PageHandlerFactory" validate="false" />
- <!--文件排除:自定义本地文件优先 结束-->
- <remove verb="GET,HEAD,POST" path="*" />
3、设置IIS(仅仅是设置IIS,不是设置SharePoint为匿名):打开Web应用程序对应的站点(如“SharePoint - 80”),右键 | 属性 | 目录安全性 | 编辑 | 勾上“启用匿名访问”;此操作是保证普通的ASP.NET程序也能运行。
4、重启IIS之后(作用只是保证快速看到效果),再打开http://webplat/default.aspx,就会看到如下页面,哈哈,兴奋吧?!

哈哈,到现在位置,完美解决SharePoint文件与本地文件的优先级访问问题!那么有人可能会问,如果在某个文件下的某个文件有冲突,那么这种方法还有用吗?答案是肯定的,一样可以!方法:只需要在第二步中把web.config改为如下即可!
- <httpHandlers>
- <!--文件夹下的文件排除:自定义本地文件优先 开始--><!--love9:2008年12月7日23:15:13-->
- <add verb="*" path="/sites/site/default.aspx" type="System.Web.UI.PageHandlerFactory" validate="false" />
- <!--文件夹下的文件排除:自定义本地文件优先 结束-->
- <remove verb="GET,HEAD,POST" path="*" />
有心的朋友可以据此继续发散思维!
有问题的朋友可以留言给我,我会尽快回复邮件!
呵呵,周末写下此文与大家共享

Currently rated 3.6 by 9 people
- Currently 3.555556/5 Stars.
- 1
- 2
- 3
- 4
- 5