当程序员使用Visual Studio 2010为SharePoint 2010创建应用程序时,可以创建两种类型的解决方案,服务器场解决方案和沙盒解决方案。比如,打开Visual Studio 2010,新建一个空白SharePoint项目,你看到的第一个界面就是如下这个对话框。

SharePoint 2010中的沙盒解决方案(Sandboxed Solution)_Sandboxed

服务器场解决方案(或简称为场解决方案)和SharePoint 2007一样,是一种被完全信任的解决方案。场解决方案可以包含能放到解决方案包里面的所有SharePoint组件和元素,比如应用程序页、可视化Web部件等等。在SharePoint 2010系统上安装场解决方案包,需要系统管理员在SharePoint服务器上,打开命令提示符窗口或PowerShell窗口,输入相应的命令行指令或Cmdlet,将这个场解决方案包安装到SharePoint服务器场里面。

如果你的客户对SharePoint系统有严格的管控流程,那你就惨了。你辛辛苦苦的把代码里面的Bug全部修正之后,把项目打包成更新的解决方案包,然后,身为开发人员的你必须填写N张表格,接着就只能眼巴巴的等着管理服务器场的IT人员帮你把这个更新的解决方案包部署到服务器场里面,因为只有他们才有权限能在服务器上直接操作。如果客户每次还需要你去解释,到底每次更新都做了些什么,对服务器有何影响,那你就更加会头大了。

于是SharePoint 2010引入了沙盒解决方案的概念。说到“沙盒”,嗯,这可是好东东啊。这些年整个开发平台都在围着“沙盒”转,JVM就是一个“沙盒”,CLR也是一个“沙盒”。有了“沙盒”,就能将自定义代码限制在其中,即使它一不小心crash掉,也能最小化带来的影响。

SharePoint沙盒解决方案的作用也差不多。如果开发人员将自己的SharePoint 2010项目创建为沙盒解决方案,那么SharePoint 2010会在一个特定的“沙盒”中运行沙盒解决方案,并随时监控“沙盒”里面代码的运行情况。

对于场解决方案里面所包含的代码,除了少数组件外,其他大部分组件,例如Web部件、页面、事件处理程序之类的,都是被载入到w3wp.exe进程中运行。这个是理所当然的,因为SharePoint就是一个ASP.NET Web应用嘛,所以各种自定义代码自然会被ASP.NET Runtime给载入到w3wp.exe进程中。

但是如果是沙盒解决方案,其中所包含的代码将运行在一个单独的进程中(准确的说,有好几个进程都被用于运行沙盒解决方案里面的代码),而并非w3wp.exe进程。

例如,开发人员将一个自定义Web部件打包到一个沙盒解决方案包,部署到一个网站集并激活,然后将这个Web部件给放置到某个页面上。当有用户访问这个页面时,w3wp.exe就会发现,需要运行那个Web部件中所包含的自定义代码,这时,w3wp.exe进程会联系(本地或远程服务器上的)SPUCHostService.exe进程,告诉它需要以“沙盒”模型执行一些代码。SPUCHostService.exe进程会通知SPUCWorkerProcess.exe进程载入需要运行的代码,SPUCWorkerProcess.exe进程会通过SPUCWorkerProcessProxy.exe来完成对SharePoint对象模型的调用,并执行那个Web部件中的自定义代码。这些代码执行完成之后,会将执行结果最终返回到w3wp.exe进程,w3wp.exe拿到这个自定义Web部件的执行结果,就可以继续将页面执行下去了。

要想SharePoint 2010服务器场能执行沙盒解决方案,就需要在至少一台服务器上启动“Microsoft SharePoint Foundation沙盒代码服务”。从SharePoint 2010管理中心打开“服务器上的服务”页面,就可以将这个服务在指定的物理服务器上启动或停止。

SharePoint 2010中的沙盒解决方案(Sandboxed Solution)_SharePoint_02

如果你的服务器场包含了n台服务器,那么你既可以在所有物理服务器上启动“Microsoft SharePoint Foundation沙盒代码服务”,也可以只选择在某几台应用服务器上启动“Microsoft SharePoint Foundation沙盒代码服务”。甚至最极端的,你可以准备一台CPU和内存都很强大的服务器,加入到服务器场中,然后专门在这台服务器上运行“Microsoft SharePoint Foundation沙盒代码服务”。这样,无论服务器场中的哪一台前端服务器需要运行沙盒解决方案中的自定义代码,这些请求都会被发送到这台强大的物理服务器。万一沙盒解决方案里面的自定义代码很烂,会严重影响运行代码的服务器的CPU或内存资源,那么也只会影响到这一台特定的服务器。

当w3wp.exe进程需要找到一个地方运行沙盒代码时,它会基于某种预先制定的策略。SharePoint 2010有两种策略可用:1、总是在得到请求的同一台服务器上运行沙盒代码;2、使用一种内置的优化规则来传递执行请求。第1种策略非常简单,w3wp.exe总是会将执行沙盒代码的请求传递给自己这台服务器上的SPUCWorkerProcess.exe进程,也就是由当前服务器负责运行沙盒代码。第2种策略类似于一种“负载平衡”机制,SharePoint会检查服务器场中哪些服务器可以用来运行沙盒代码,然后按照一个优化规则,让w3wp.exe将执行代码的请求传递到某台服务器。这个优化规则简单来说就是,如果上次是服务器A执行了某个沙盒解决方案里面的一个Web部件代码,那下次会优先考虑继续让服务器A执行同一个Web部件里面的代码。

具体选择哪个策略,可以在SharePoint 2010管理中心打开“系统设置 - 管理用户解决方案”页面,然后就能选择2个策略中的某一个了。

SharePoint 2010中的沙盒解决方案(Sandboxed Solution)_Solution_03

沙盒解决方案中包含的代码除了会在单独的进程中运行之外,它还有很多的限制。首先,SharePoint 2010使用了CAS(Code Access Security)来限制了沙盒代码能做的事情。在“Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONFIG\wss_usercode.config”文件中定义了沙盒代码的CAS策略,沙盒代码的权限被这个CAS策略限制为:

●SecurityPermission.Execution:可以执行托管代码;
●AspNetHostingPermission = Minimal:可以在ASP.NET中运行,但不能访问服务器上的任何资源;
●SharePointPermission.ObjectModel:可以使用SharePoint对象模型。

由于CAS的限制,沙盒代码能够做的事情是很有限的,比如,它不能访问服务器上的任何文件,也不能访问数据库。除了这些限制之外,对于SharePoint对象模型的调用,SharePoint系统对沙盒代码进行了进一步的限制。

虽然CAS中给予了沙盒代码“SharePointPermission.ObjectModel”权限,但沙盒代码在单独的进程中运行之前,它们都会被经过预先检查,凡是不运行调用的对象模型出现在了代码中,就会直接抛出异常,中止代码运行。禁止在沙盒代码中使用的对象模型包括:

●SPSite的构造函数
●SPSecurity类
●Microsoft.SharePoint.Navigation命名空间下的所有类
●除了SPUtility.SendEmail()和SPUtility.GetNTFullNameandEmailFromLogin()之外的所有SPUtility所提供的方法
●其他...

在SharePoint 2010 SDK中有一个列表,列出了所有允许在沙盒解决方案中被使用的SharePoint对象模型,请参考:http://msdn.microsoft.com/en-us/library/ee537860.aspx

除了对代码的限制之外,对于能被包含在沙盒解决方案中的SharePoint元素,也有一些限制,下面这些元素都不能被包含在沙盒解决方案中:

●Web应用程序和服务器场级别的Feature
●代码工作流
●内容类型绑定
●<HideCustomAction>元素
●Custom Action group
●应用程序页
●可视化Web部件

SharePoint 2010会严格监控沙盒解决方案中的代码的运行状况。为了限制沙盒代码所占用的服务器资源,SharePoint 2010为每个网站集分配了一定的“点数”,随着沙盒代码的运行,这些“点数”会被逐渐消耗,如果一个网站集所分配的“点数”被消耗完了,那么这个网站集里面所有的沙盒解决方案将暂时不可用,直到第二天“点数”被自动重置为预设置为止。

管理员可以在SharePoint 2010管理中心的“应用程序管理 - 配置配额和锁定”页面为每个网站集指定其可用的“点数”配额。默认每个网站集每天可以消耗的“点数”配额是300。

 SharePoint 2010中的沙盒解决方案(Sandboxed Solution)_Sandboxed_04

那么SharePoint 2010是如何计算“点数”的呢?SharePoint 2010内置了一套计算规则,如果希望了解这些规则,可以打开服务器上的SharePoint 2010 Management Shell,然后输入一个Cmdlet指令:

[Microsoft.SharePoint.Administration.SPUserCodeService]::Local.ResourceMeasures | ft Name,ResourcesPerPoint,AbsoluteLimit

SharePoint 2010中的沙盒解决方案(Sandboxed Solution)_Solution_05 

上图所示的就是SharePoint 2010内置的“点数”计算规则。比如,“UnhandledExceptionCount 50 3”表示:每50个未捕获异常将消耗1个“点数”,而每天如果某个解决方案包由于未捕获异常的原因消耗了3个“点数”(也就是它发生了150次异常未捕获的情况),那么这个解决方案包将被直接中止运行,即使网站集当前还有剩余“点数”。

说了沙盒解决方案这么多的限制,那么为什么开发人员要使用沙盒解决方案呢?沙盒解决方案最大的好处,就是它的部署和管理不需要服务器场管理员的参与。网站集管理员可以打开“网站设置 - 解决方案”页面,就能直接上载沙盒解决方案,并对它们进行激活、停用等操作。

SharePoint 2010中的沙盒解决方案(Sandboxed Solution)_Sandboxed_06

由于网站集管理员就可以直接通过Web界面来部署和管理沙盒解决方案,从此网站集管理员(或开发人员)就不用每次求爷爷告奶奶的等着服务器场管理员进行解决方案部署了。当然,这是一种妥协,服务器场管理员利用SharePoint 2010系统对沙盒解决方案的种种限制、监控,来保证了沙盒解决方案能始终在一个安全的“沙盒”环境中运行,即使沙盒代码写得很糟糕,它也会能把前端服务器搞死。有了这些保证,服务器场管理员也就能放心的让网站集管理员自己开发、部署沙盒解决方案了。

(以上内容节选自正在撰写中的《SharePoint 2010应用程序开发指南》,略有修改。)