复制或移动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开发方面的提高确实很惊人。基于该平台的开发变得越来越容易,越来越有趣了。

 

代码下载

Stsadm.zip

Cmdlet.zip

ApplicationPage.zip

 

参考资料

Deploy and use SPCopy:Part2

IStsadmCommand相关:如何扩展STSADM实用工具

SPCmdlet相关:Microsoft.SharePoint.PowerShell命名空间

默认的CustomAction位置与ID

CustomAction Element

posted @ 2010-08-09 15:05  Sunmoonfire  阅读(3170)  评论(0编辑  收藏  举报