复制或移动SharePoint网站(续)——各种方式的调用
本文将接着上一次,继续分析复制和移动SharePoint网站的功能实现。我们将采用SharePoint提供的不同的开发方式,包括在应用程序页中实现,在管理工具如stsadm或PowerShell中实现。这样做的主要目的是为了使大家能熟悉不同的SharePoint开发角度。
注意:除了ISPStsadmCommand外,所有的例子都是使用Visual Studio 2010在SharePoint 2010上创建的。
ISPStsadmCommand
所有以前用过SharePoint的人都听说过,stsadm.exe是一个命令行工具,可供管理员在SharePoint服务器上执行某些操作。正如SharePoint非常容易配置和扩展一样,stsadm.exe同样可以根据需要添加自定义的命令。方法就是实现ISPStsadmCommand接口,位于Microsoft.SharePoint.StsAdmin命名空间下。
在参考资料中,包括了该接口的深入介绍。这里,我们仅仅演示该接口的基本实现。
public class HelloWorld : ISPStsadmCommand { #region ISPStsadmCommand Members public string GetHelpMessage(string command) { return "Help World"; } public int Run(string command, System.Collections.Specialized.StringDictionary keyValues, out string output) { output = "Hello, World"; return 0; } #endregion }
编译后的程序集部署在GAC里,同时还需要在...\12\CONFIG文件夹下添加一个XML文件。
<?xml version="1.0" encoding="utf-8" ?>
<commands>
<command name="hello"
class="HelloWorldCommand.HelloWorld,
HelloWorldCommand,
Version=1.1.1.1,
Culture=neutral,
PublicKeyToken=a9baec847ddb5ad1"/>
</commands>
同样,本文中不会对此进行深入介绍。详细内容请查看参考资料。详细的代码都在下载的包中。
PowerShell Cmdlets
很不幸,在SharePoint 2010里对扩展stsadm.exe的支持已经被废弃。因此上面的代码将无法运行。取而代之的是SharePoint 2010中的Windows PowerShell 和Cmdlet。新的特性带来的一个好处是和其他SharePoint项(如Feature,网站定义等)一样,可以通过SharePoint包WSP的方式部署。同时还可以继承Windows PowerShell的其他优点,这些就不在本文的讨论范围了。
实现一个SharePoint Cmdlet
创建一个SharePoint Cmdlet首先必须知道要用哪个类。有五个基类可控选择:SPNewCmdletBase, SPSetCmdletBase, SPGetCmdletBase,SPRemoveCmdletBase和 SPCmdlet。所有这些类都位于Microsoft.SharePoint.PowerShell命名空间。区别如下:
- SPNewCmdletbase<TCmdletObject>: 一个抽象基类,用于创建对象的新实例并将其保存到数据存储中。
- SPGetCmdletBase<TCmdletObject>:一个抽象基类,允许继承的类查找并返回一系列TCmdletObject类型的对象。
- SPSetCmdletBase<TCmdletObject>:一个抽象基类,允许继承的类更新数据存储中已有对象的属性。
- SPRemoveCmdletBase<TCmdletObjec>:一个抽象基类,允许从数据存储中删除一个已有的特定类型的数据对象。
- SPCmdlet:代表为一个SharePoint部署所编写的所有自定义Cmdlet的一个抽象基类,提供跨所有SharePoint Cmdlet的统一的行为。
如上所述,前四个基类是基本的增删改查操作,创建=SPNewCmdletBase,读取=SPGetCmdletBase,更新=SPSetCmdletBase,删除=SPRemoveCmdletBase。最后是一个用于自定义Cmdlet的基类。由于网站拷贝并不包含增删改查的操作,所以这里我们选择SPCmdlet做我们的基类。
SPCmdlet
为了创建SPCopyCmd,首先从一个空白SharePoint项目开始。
需要添加一个引用到Microsoft.SharePoint.PowerShell.dll。这里有个小技巧。这个dll位于GAC里,不像其他SharePoint相关的 dll一样可以在14\ISPAI下找到。你可以通过如下命令查找到该dll:
dir Microsoft.Sharepoint.Powershell.dll /s
找到后将其拷贝到其他位置,以便我们可以在项目中进行引用。建议将其拷到14\ISAPI下,这样将来找起来就很方便了。另一个需要引用的组件是System.Management.Automation.dll。虽然在添加引用对话框中的.Net标签下有System.Management,但那不是我们想要的。必须通过浏览,定位到C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0 找到它。
所有引用都添加好后,我们就可以编写代码了:
[SPCmdlet(RequireLocalFarmExist = true, RequireUserFarmAdmin = false)] public class SPCopyBase : SPCmdlet { protected override void InternalValidate() { if(string.IsNullOrEmpty(Source)) throw new ArgumentException("必须指定来源参数Source"); if(string.IsNullOrEmpty(Destination)) throw new ArgumentException("必须指定目标参数Destination"); } protected override void InternalProcessRecord() { // 具体实现 } #region Properties [Parameter(Position = 0, Mandatory = true)] public string Source { get; set; } [Parameter(Position = 1, Mandatory = true)] public string Destination { get; set; } protected bool IsCopy { get; set; } #endregion }
如上所示,该类继承自SPCmdlet,并实现了两个覆写,InternalValidate和InternalProcessRecord。如果该Cmdlet准备实现一系列读和写操作,我们会相应的选择覆写RetrieveDataObject或UpdateDataObject。然而,由于我们的Cmdlet并不进行增删改查类的操作,因此只需要实现这两个方法即可。同时,我们看到该类还用到SPCmdletAttribute。这里可以使用三个参数:RequireLocalFarmExists, RequireUserFarmAdmin 和 RequireUserMachineAdmin。通过名字应该不难猜出它们的意思吧。
为了告诉PowerShell存在这个Cmdlet,必须再创建一个XML文件并放在14\CONFIG\POWERSHELL\Registration 目录下。在VS201里添加至该文件夹变动十分容易。通过在项目点添加->SharePoint映射文件夹,然后导航到我们需要的文件夹,点OK即可。
创建好该文件夹后,添加一个XML文件。尽管你可以随便取名字,但最好还是起一个与该项目相关的名字。该XML文件会在SharePoint PowerShell启动时使用,用于加载所有可用的命令。
<ps:Config xmlns:ps="urn:Microsoft.SharePoint.PowerShell"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:Microsoft.SharePoint.PowerShell SPCmdletSchema.xsd">
<ps:Assembly Name="$SharePoint.Project.AssemblyFullName$">
<ps:Cmdlet>
<ps:VerbName>Copy-SPWeb</ps:VerbName>
<ps:ClassName>MANSoftDev.SharePoint.PowerShell.SPCopyCmd</ps:ClassName>
<ps:HelpFile>MANSoftDev.SharePoint.PowerShell.dll-help.xml</ps:HelpFile>
</ps:Cmdlet>
<ps:Cmdlet>
<ps:VerbName>Move-SPWeb</ps:VerbName>
<ps:ClassName>MANSoftDev.SharePoint.PowerShell.SPMoveCmd</ps:ClassName>
<ps:HelpFile>MANSoftDev.SharePoint.PowerShell.dll-help.xml</ps:HelpFile>
</ps:Cmdlet>
</ps:Assembly>
</ps:Config>
首先需要设置Assembly元素的Name属性,值为我们当前项目编译出的组件的完整名称。$SharePoint.Project.AssemblyFullName$将会自动在编译时替换成该名称。接下来,我们需要为组件中每个Cmdlet添加一个Cmdlet元素。VerbName元素告诉PowerShell该Cmdlet与什么谓词名(Verb-Name)关联,ClassName元素包含了实现该操作的类的完全限定名称。HelpFile元素是必须的,但是所指定的文件不要求必须存在。依照惯例,你可以使用组件的名字,这样如果想提供帮助文件时就会很容易了。本文不会涉及帮助文件部分。
实现该Cmdlet
由于我们编写的组件中既包含复制和又包含移动,PowerShell需要知道什么时候用什么类。这也正是CmdletAttribute的作用。其中需要两个参数来区分各自的动词和名词。VerbsCommon枚举中包含了常用的动词,比如Set,Get,Find等等。如果其中找不到适合你的,你也可以自己提供一个字符串。
[Cmdlet(VerbsCommon.Copy, "SPWeb")] public class SPCopyCmd : SPCopyBase { public SPCopyCmd() { base.IsCopy = true; } } [Cmdlet(VerbsCommon.Move, "SPWeb")] public class SPMoveCmd : SPCopyBase { public SPMoveCmd() { base.IsCopy = false; } }
所有复制或移动的工作都在上一篇的SPWeb类中实现了,因此在Cmdlet这边就非常简单了。直接调用:
protected override void InternalProcessRecord() { MANSoftDev.SharePoint.PowerShell.SPWeb copy = new MANSoftDev.SharePoint.PowerShell.SPWeb(); copy.SourceURL = Source; copy.DestinationURL = Destination; if(IsCopy) copy.Copy(); else copy.Move(); }
编译通过后,直接右击解决方案资源管理器中的项目,点部署。在此过程中,XML会自动拷贝到Registration目录中,组件自动放到GAC里。这时打开SharePoint 2010管理控制台,我们的Cmdlet就通过XML文件被加载上了。
当然,本文并未对Cmdlet开发进行完整论述,Cmdlet中还包括了很多可供我们利用的亮点。
应用程序页
尽管创建一个ISPStsadmCommand或SPCmdlet来实现复制和移动网站相对比较简单,但是对用户友好度不高。为了用他们,我们必须登录到SharePoint服务器上。为了以对用户更加友好的方式实现我们的功能,我们可以采用自定义网站操作或网站设置+应用程序页的设计。
对于曾经用过SharePoint 2007的开发者来说,使用Visual Studio 2010中的工具创建和部署解决方案包真是一件令人欣慰的事。这里我们会用到Visual Studio 2010 SharePoint工具中的部分内容,详细的工具介绍不在本文范围内。
为了创建一个应用程序页并将其关联到相应的菜单上,我们首先还是从创建空白SharePoint项目开始。然后在解决方案资源管理器中右击该项目,选择Add->SharePoint "Layouts" Mapped Folder。右击该文件夹,选择Add->New Item。
选中Application Page后取一个合适的名字,本例为SPCopy.aspx,点Add。当前的项目结构如下所示:
剩下就是在ASPX页面上添加合适的控件和绑定相应的事件了。
protected void OnMove(object sender, EventArgs e) { if(Destination.Text.Length != 0) { web.SourceURL = SPContext.Current.Web.Url; web.DestinationURL = Destination.Text; web.Move(); Response.Redirect(Destination.Text); } } protected void OnCopy(object sender, EventArgs e) { if(Destination.Text.Length != 0) { web.SourceURL = SPContext.Current.Web.Url; web.DestinationURL = Destination.Text; web.Move(); Response.Redirect(Destination.Text); } }
为了可以访问该页面,我将在网站设置页面的网站管理组下添加了一个链接。可以通过添加Element元素实现。在Visual Studio 2010中同样很简单。在解决方案资源管理器中右击我们的项目,选Add->New Item。在弹出的新建对话框中选择Empty Element。其中的XML内容如下。尽管逻辑上说我们应该添加到网站操作组下,但是由于没有找到其对应的GroupId,所以这里我们把它加到了网站管理分组下。
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="SPCopy"
RequireSiteAdministrator="True"
Location="Microsoft.SharePoint.SiteSettings"
GroupId="SiteAdministration"
Title="复制/移动网站"
Description="复制或移动该网站"
Sequence="1001">
<UrlAction Url="_layouts/mansoftdev/spcopy.aspx"/>
</CustomAction>
</Elements>
本文不会对SharePoint CumtomActions,Elements和Features进行详细介绍。从参考资料中可以了解更多相关信息。
兴趣所在
Visual Studio 2010在SharePoint开发方面的提高确实很惊人。基于该平台的开发变得越来越容易,越来越有趣了。
代码下载
参考资料
IStsadmCommand相关:如何扩展STSADM实用工具