演练:在服务器资源管理器扩展中调入 SharePoint 客户端对象模型

本演练演示如何从**“服务器资源管理器”中的“SharePoint 连接”**节点扩展调用 SharePoint 客户端对象模型。 有关使用 SharePoint 客户端对象模型的更多信息,请参见调入 SharePoint 对象模型

本演练将演示以下任务:

  • 创建一个 Visual Studio 扩展,此扩展通过以下方式扩展**“服务器资源管理器”“SharePoint 连接”**节点:

    • 此扩展会在**“服务器资源管理器”中的每个 SharePoint 网站节点下添加一个新的“Web 部件库”**节点。 该新节点包含的每个子节点均表示网站上的 Web 部件库中的一个 Web 部件。

    • 此扩展会定义一个表示 Web 部件实例的新节点类型。 该新节点类型是新**“Web 部件库”节点下的子节点的基础。 该新 Web 部件节点类型在“属性”**窗口中显示有关其表示的 Web 部件的信息。

  • 生成 Visual Studio 扩展 (VSIX) 包以部署扩展。

  • 调试并测试扩展。

提示

您在本演练中创建的扩展与您在演练:扩展服务器资源管理器以显示 Web 部件中创建的扩展类似。 但是,该演练使用的是 SharePoint 服务器对象模型,而本演练通过使用客户端对象模型来完成相同的任务。

系统必备

您需要在开发计算机上安装以下组件才能完成本演练:

了解以下概念很有用,但对于完成本演练并不是必需的:

  • 使用 SharePoint 客户端对象模型。 有关更多信息,请参见 Managed Client Object Model(托管客户端对象模型)。

  • Microsoft SharePoint Services 中的 Web 部件。 有关更多信息,请参见 Web Parts Overview(Web 部件概述)。

创建项目

若要完成本演练,您需要创建以下两个项目:

  • 一个用于创建 VSIX 包以部署**“服务器资源管理器”**扩展的 VSIX 项目。

  • 一个用于实现**“服务器资源管理器”**扩展的类库项目。

从创建项目开始本演练。

创建 VSIX 项目

  1. 启动 Visual Studio。

  2. 在**“文件”菜单上指向“新建”,再单击“项目”**。

  3. 在**“新建项目”对话框中,展开“Visual C#”“Visual Basic”节点,然后单击“扩展性”**。

    提示

    只有在安装 Visual Studio 2010 SDK 之后,“扩展性”节点才可用。 有关更多信息,请参见前面的系统必备部分。

  4. 在对话框顶部的组合框中,选择**“.NET Framework 4”**。 SharePoint 工具扩展需要此版本的 .NET Framework 中的功能。

  5. 单击**“VSIX 项目”**模板。

  6. 在**“名称”**框中键入 WebPartNode。

  7. 单击**“确定”**。

    Visual Studio 将**“WebPartNode”项目添加到“解决方案资源管理器”**中。

创建扩展项目

  1. 在**“解决方案资源管理器”中,右击解决方案节点,单击“添加”,再单击“新建项目”**。

    提示

    在 Visual Basic 项目中,仅当在“选项”对话框 ->“项目和解决方案”->“常规”中选中“总是显示解决方案”复选框时,解决方案节点才会出现在“解决方案资源管理器”中。

  2. 在**“新建项目”对话框中,展开“Visual C#”“Visual Basic”节点,然后单击“Windows”**。

  3. 在对话框顶部的组合框中,选择**“.NET Framework 4”**。

  4. 选择**“类库”**项目模板。

  5. 在**“名称”**框中键入 WebPartNodeExtension。

  6. 单击**“确定”**。

    Visual Studio 将**“WebPartNodeExtension”**项目添加到解决方案中,并打开默认的 Class1 代码文件。

  7. 从项目中删除 Class1 代码文件。

配置扩展项目

在编写代码以创建扩展之前,您必须向项目中添加代码文件和程序集引用并更新默认命名空间。

配置项目

  1. 在**“WebPartNodeExtension”**项目中,添加具有下列名称的两段代码:

    • SiteNodeExtension

    • WebPartNodeTypeProvider

  2. 在**“项目”菜单上,单击“添加引用”**。

  3. 在**“.NET”选项卡上,按住 Ctrl 的同时选择下列程序集,然后单击“确定”**:

    • Microsoft.SharePoint.Client

    • Microsoft.SharePoint.Client.Runtime

    • Microsoft.VisualStudio.SharePoint

    • System.ComponentModel.Composition

    • System.Windows.Forms

  4. 在**“项目”菜单上选择“WebPartNodeExtension 属性”**。

    随即打开**“项目设计器”**。

  5. 单击**“应用程序”**选项卡。

  6. 在**“默认命名空间”框 (C#) 或“根命名空间”**框 (Visual Basic) 中,键入 ServerExplorer.SharePointConnections.WebPartNode。

为新节点创建图标

为**“服务器资源管理器”扩展创建两个图标:一个图标用于新的“Web 部件库”节点,另一个图标用于“Web 部件库”**节点下的每个子 Web 部件节点。 在本演练后面的部分中,您将编写代码以将这些图标与节点相关联。

为节点创建图标

  1. 在 WebPartNodeExtension 项目的**“项目设计器”中,单击“资源”**选项卡。

  2. 单击**“此项目不包含默认资源文件,单击此处创建一个资源文件。”**。

    Visual Studio 会创建一个资源文件并在设计器中打开此文件。

  3. 在设计器的顶部,单击**“添加”按钮上的下拉箭头,再单击“添加新图标”**。

  4. 为新图标名称键入 WebPartsNode,然后单击**“添加”**。

    新图标将在**“图像编辑器”**中打开。

  5. 编辑 16x16 版本的图标,使得设计出的图标可以让您轻松地识别。

  6. 单击 32x32 版本的图标。

  7. 在**“图像”菜单上单击“删除图像类型”**。

  8. 重复步骤 3 到步骤 7,将第二个图标添加到项目资源中。 将此图标命名为 WebPart。

  9. 在**“解决方案资源管理器”中的“WebPartNodeExtension”项目的“Resources”文件夹下,选择“WebPartsNode.ico”**。

  10. 在**“属性”窗口中,单击“生成操作”旁边的下拉箭头,然后选择“嵌入的资源”**。

  11. 对于**“WebPart.ico”**,重复最后两个步骤。

向服务器资源管理器中添加 Web 部件库节点

创建一个类,此类可将新的**“Web 部件库”节点添加到每个 SharePoint 网站节点中。 若要添加新节点,此类应实现 IExplorerNodeTypeExtension 接口。 每当需要扩展“服务器资源管理器”**中的现有节点的行为(例如向某个节点添加新的子节点)时,就要实现此接口。

向服务器资源管理器中添加 Web 部件库节点

  1. 在 WebPartNodeExtension 项目中,双击 SiteNodeExtension 代码文件。

  2. 将下面的代码粘贴到此文件中。

    提示

    添加此代码后,项目将会出现一些编译错误。 在添加后面的步骤中的代码之后,这些错误将消失。

    Imports System.Collections.Generic
    Imports System.ComponentModel.Composition
    Imports Microsoft.SharePoint.Client
    Imports Microsoft.VisualStudio.SharePoint
    Imports Microsoft.VisualStudio.SharePoint.Explorer
    
    Namespace ServerExplorer.SharePointConnections.WebPartNode
    
        ' Export attribute: Enables Visual Studio to discover and load this extension.
        ' ExplorerNodeType attribute: Indicates that this class extends SharePoint site nodes in Server Explorer.
        ' SiteNodeExtension class: Represents an extension of SharePoint site nodes in Server Explorer.
        <Export(GetType(IExplorerNodeTypeExtension))> _
        <ExplorerNodeType(ExplorerNodeTypes.SiteNode)> _
        Friend Class SiteNodeExtension
            Implements IExplorerNodeTypeExtension
    
            Private siteUrl As System.Uri = Nothing
    
            Private Sub Initialize(ByVal nodeType As IExplorerNodeType) _
                Implements IExplorerNodeTypeExtension.Initialize
    
                ' The NodeChildrenRequested event is raised when the user expands the
                ' SharePoint site node in Server Explorer.
                AddHandler nodeType.NodeChildrenRequested, AddressOf NodeChildrenRequested
            End Sub
    
            ' Creates the new Web Part Gallery node with the specified icon.
            Private Sub NodeChildrenRequested(ByVal Sender As Object, ByVal e As ExplorerNodeEventArgs)
    
                ' Get the site URL so that it can be used later to access the site
                ' by using the SharePoint client object model.
                siteUrl = e.Node.Context.SiteUrl
    
                ' The CreateWebPartNodes argument is a delegate that Visual Studio calls 
                ' to create the child nodes under the Web Part Gallery node.
                e.Node.ChildNodes.AddFolder("Web Part Gallery", My.Resources.WebPartsNode.ToBitmap(), _
                    AddressOf CreateWebPartNodes)
            End Sub
    
            ' Creates individual Web Part nodes under the new Web Part Gallery node.
            Private Sub CreateWebPartNodes(ByVal parentNode As IExplorerNode)
    
                ' Use the SharePoint client object model to get items from the Web Part gallery.
                Dim Context As ClientContext = New ClientContext(siteUrl.AbsoluteUri)
                Dim WebPartsGallery As List = Context.Web.GetCatalog(CType(ListTemplateType.WebPartCatalog, Integer))
                Dim WebParts As ListItemCollection = WebPartsGallery.GetItems(New CamlQuery())
    
                ' Request the FieldValuesAsText property values with the Web Part items.
                Context.Load(WebParts, Function(listItems) listItems.Include(Function(i) i.FieldValuesAsText))
                Context.ExecuteQuery()
    
                If WebParts IsNot Nothing Then
                    For Each WebPart As ListItem In WebParts
    
                        ' Create a new annotation object to store the current Web Part item with the new node.
                        Dim Annotations = New Dictionary(Of Object, Object)()
                        Annotations.Add(GetType(ListItem), WebPart)
    
                        ' Create the new node for the current Web Part item.
                        parentNode.ChildNodes.Add(WebPartNodeTypeProvider.WebPartNodeTypeId, _
                            WebPart.FieldValuesAsText.FieldValues("Title"), Annotations)
                    Next
                End If
            End Sub
        End Class
    End Namespace
    
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using Microsoft.SharePoint.Client;
    using Microsoft.VisualStudio.SharePoint;
    using Microsoft.VisualStudio.SharePoint.Explorer;
    
    namespace ServerExplorer.SharePointConnections.WebPartNode
    {
        // Enables Visual Studio to discover and load this extension.
        [Export(typeof(IExplorerNodeTypeExtension))]        
    
        // Indicates that this class extends SharePoint site nodes in Server Explorer.
        [ExplorerNodeType(ExplorerNodeTypes.SiteNode)]
    
        // Represents an extension of SharePoint site nodes in Server Explorer.
        internal class SiteNodeExtension : IExplorerNodeTypeExtension
        {
            private System.Uri siteUrl = null;
    
            public void Initialize(IExplorerNodeType nodeType)
            {
                // The NodeChildrenRequested event is raised when the user expands the
                // SharePoint site node in Server Explorer.
                nodeType.NodeChildrenRequested += NodeChildrenRequested;
            }
    
            // Creates the new Web Part Gallery node with the specified icon.
            private void NodeChildrenRequested(object sender, ExplorerNodeEventArgs e)
            {
                // Get the site URL so that it can be used later to access the site
                // by using the SharePoint client object model.
                siteUrl = e.Node.Context.SiteUrl;
    
                // The CreateWebPartNodes argument is a delegate that Visual Studio calls 
                // to create the child nodes under the Web Part Gallery node.
                e.Node.ChildNodes.AddFolder("Web Part Gallery", Properties.Resources.WebPartsNode.ToBitmap(), 
                    CreateWebPartNodes);
            }
    
            // Creates individual Web Part nodes under the new Web Part Gallery node.
            private void CreateWebPartNodes(IExplorerNode parentNode)
            {
                // Use the SharePoint client object model to get items from the Web Part gallery.
                ClientContext context = new ClientContext(siteUrl.AbsoluteUri);
                List webPartsGallery = context.Web.GetCatalog((int)ListTemplateType.WebPartCatalog);
                ListItemCollection webParts = webPartsGallery.GetItems(new CamlQuery());
    
                // Request the FieldValuesAsText property values with the Web Part items.
                context.Load(webParts, listItems => listItems.Include(i => i.FieldValuesAsText));
                context.ExecuteQuery();
    
                if (webParts != null)
                {
                    foreach (ListItem webPart in webParts)
                    {
                        // Create a new annotation object to store the current Web Part item with the new node.
                        var annotations = new Dictionary<object, object>() 
                        { 
                            { typeof(ListItem), webPart } 
                        };
    
                        // Create the new node for the current Web Part item.
                        parentNode.ChildNodes.Add(WebPartNodeTypeProvider.WebPartNodeTypeId,
                            webPart.FieldValuesAsText.FieldValues["Title"], annotations);
                    }
                }
            }
        }
    }
    

定义表示 Web 部件的节点类型

创建一个类,此类定义表示 Web 部件的新节点类型。 Visual Studio 使用此新节点类型来显示**“Web 部件库”**节点下的子节点。 其中的每个子节点均表示 SharePoint 网站上的一个 Web 部件。

若要定义新节点类型,此类应实现 IExplorerNodeTypeProvider 接口。 每当需要在**“服务器资源管理器”**中定义新的节点类型时,就要实现此接口。

定义 Web 部件节点类型

  1. 在 WebPartNodeExtension 项目中,双击 WebPartNodeTypeProvider 代码文件。

  2. 将下面的代码粘贴到此文件中。

    Imports System
    Imports System.Collections.Generic
    Imports System.Windows.Forms
    Imports System.ComponentModel.Composition
    Imports Microsoft.SharePoint.Client
    Imports Microsoft.VisualStudio.SharePoint
    Imports Microsoft.VisualStudio.SharePoint.Explorer
    
    Namespace ServerExplorer.SharePointConnections.WebPartNode
    
        ' Export attribute: Enables Visual Studio to discover and load this extension.
        ' ExplorerNodeType attribute: Specifies the ID for this new node type.
        ' WebPartNodeTypeProvider class: Defines a new node type that represents a Web Part on a SharePoint site.
        <Export(GetType(IExplorerNodeTypeProvider))> _
        <ExplorerNodeType(WebPartNodeTypeProvider.WebPartNodeTypeId)> _
        Friend Class WebPartNodeTypeProvider
            Implements IExplorerNodeTypeProvider
    
            Friend Const WebPartNodeTypeId As String = "Contoso.WebPart"
    
            Private Sub InitializeType(ByVal typeDefinition As IExplorerNodeTypeDefinition) _
            Implements IExplorerNodeTypeProvider.InitializeType
                typeDefinition.DefaultIcon = My.Resources.WebPart.ToBitmap()
                typeDefinition.IsAlwaysLeaf = True
    
                AddHandler typeDefinition.NodePropertiesRequested, AddressOf NodePropertiesRequested
                AddHandler typeDefinition.NodeMenuItemsRequested, AddressOf NodeMenuItemsRequested
            End Sub
    
            ' Retrieves properties that are displayed in the Properties window when
            ' a Web Part node is selected.
            Private Sub NodePropertiesRequested(ByVal Sender As Object, _
                ByVal e As ExplorerNodePropertiesRequestedEventArgs)
    
                Dim webPart = e.Node.Annotations.GetValue(Of ListItem)()
                Dim propertySource = e.Node.Context.CreatePropertySourceObject( _
                    webPart.FieldValuesAsText.FieldValues)
                e.PropertySources.Add(propertySource)
            End Sub
    
            Private Sub NodeMenuItemsRequested(ByVal Sender As Object, _
                ByVal e As ExplorerNodeMenuItemsRequestedEventArgs)
                Dim WebPartNodeMenuItem As IMenuItem = e.MenuItems.Add("Display Message")
                AddHandler WebPartNodeMenuItem.Click, AddressOf MenuItemClick
            End Sub
    
            Private Sub MenuItemClick(ByVal Sender As Object, ByVal e As MenuItemEventArgs)
                Dim ParentNode As IExplorerNode = TryCast(e.Owner, IExplorerNode)
                If ParentNode IsNot Nothing Then
                    Dim webPart = ParentNode.Annotations.GetValue(Of ListItem)()
                    MessageBox.Show("You clicked the context menu for the following Web part: " & _
                        webPart.FieldValuesAsText.FieldValues("Title") + ".", "Web Part Menu Command")
                End If
            End Sub
        End Class
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
    using System.ComponentModel.Composition;
    using Microsoft.SharePoint.Client;
    using Microsoft.VisualStudio.SharePoint;
    using Microsoft.VisualStudio.SharePoint.Explorer;
    
    namespace ServerExplorer.SharePointConnections.WebPartNode
    {
        // Enables Visual Studio to discover and load this extension.
        [Export(typeof(IExplorerNodeTypeProvider))]
    
        // Specifies the ID for this new node type.
        [ExplorerNodeType(WebPartNodeTypeProvider.WebPartNodeTypeId)]
    
        // Defines a new node type that represents a Web Part on a SharePoint site.
        internal class WebPartNodeTypeProvider : IExplorerNodeTypeProvider
        {
            internal const string WebPartNodeTypeId = "Contoso.WebPart";
    
            public void InitializeType(IExplorerNodeTypeDefinition typeDefinition)
            {
                typeDefinition.DefaultIcon = Properties.Resources.WebPart.ToBitmap();
                typeDefinition.IsAlwaysLeaf = true;
    
                typeDefinition.NodePropertiesRequested += NodePropertiesRequested;
                typeDefinition.NodeMenuItemsRequested += NodeMenuItemsRequested;
            }
    
            // Retrieves properties that are displayed in the Properties window when
            // a Web Part node is selected.
            private void NodePropertiesRequested(object sender,
                ExplorerNodePropertiesRequestedEventArgs e)
            {
                var webPart = e.Node.Annotations.GetValue<ListItem>();
                object propertySource = e.Node.Context.CreatePropertySourceObject(
                    webPart.FieldValuesAsText.FieldValues);
                e.PropertySources.Add(propertySource);
            }
    
            private void NodeMenuItemsRequested(
                object sender, ExplorerNodeMenuItemsRequestedEventArgs e)
            {
                e.MenuItems.Add("Display Message").Click += MenuItemClick;
            }
    
            private void MenuItemClick(object sender, MenuItemEventArgs e)
            {
                IExplorerNode parentNode = e.Owner as IExplorerNode;
    
                if (parentNode != null)
                {
                    var webPart = parentNode.Annotations.GetValue<ListItem>();
                    MessageBox.Show("You clicked the context menu for the following Web part: " +
                        webPart.FieldValuesAsText.FieldValues["Title"] + ".", "Web Part Menu Command");
                }
            }
        }
    }
    

检查点

演练进行到此时,**“Web 部件库”**节点的所有代码都位于项目中。 生成解决方案以确保编译项目时不会出错。

生成解决方案

  • 在**“生成”菜单上,选择“生成解决方案”**。

创建 VSIX 包以部署扩展

若要部署扩展,请使用解决方案中的 VSIX 项目来创建 VSIX 包。 首先,通过修改项目中包含的 source.extension.vsixmanifest 文件来配置 VSIX 包。 然后,通过生成解决方案来创建 VSIX 包。

配置 VSIX 包

  1. 在**“解决方案资源管理器”“WebPartNode”项目下,双击 WebPartNode 项目中的“source.extension.vsixmanifest”**文件。

    Visual Studio 将在清单编辑器中打开该文件。 source.extension.vsixmanifest 文件是所有 VSIX 包必需的 extension.vsixmanifest 文件的基础。 有关此文件的更多信息,请参见VSIX Extension Schema Reference

  2. 在**“产品名称”**框中,键入“服务器资源管理器的 Web 部件库节点”。

  3. 在**“作者”**框中键入 Contoso。

  4. 在**“说明”**框中,键入“向服务器资源管理器中的 SharePoint 连接节点添加自定义 Web 部件库节点”。

  5. 在编辑器的**“内容”部分中,单击“添加内容”**按钮。

  6. 在**“添加内容”对话框的“选择内容类型”列表框中,选择“MEF 组件”**。

    提示

    此值对应于 extension.vsixmanifest 文件中的 MefComponent 元素。 此元素指定 VSIX 包中的扩展程序集的名称。 有关更多信息,请参见 MEFComponent Element (VSX Schema)

  7. 在**“选择源”下,单击“项目”单选按钮,并在其旁边的列表框中选择“WebPartNodeExtension”**。

  8. 单击**“确定”**。

  9. 在**“生成”菜单上,单击“生成解决方案”**。 确保编译解决方案时不会出错。

  10. 打开 WebPartNode 项目的生成输出文件夹。 确保此文件夹此时包含 WebPartNode.vsix 文件。

    默认情况下,生成输出文件夹为 包含项目文件的文件夹下的 ..\bin\Debug 文件夹。

测试扩展

此时,您可以对**“服务器资源管理器”中的新“Web 部件库”节点进行测试。 首先,在 Visual Studio 的实验实例中开始调试扩展项目。 然后,在 Visual Studio 的实验实例中使用新的“Web 部件”**节点。

开始调试扩展

  1. 利用管理员特权重新启动 Visual Studio,并打开**“WebPartNode”**解决方案。

  2. 在 WebPartNodeExtension 项目中,打开 SiteNodeExtension 代码文件,并向 NodeChildrenRequested 和 CreateWebPartNodes 方法的第一个代码行中添加一个断点。

  3. 按 F5 开始调试。

    Visual Studio 将扩展安装到 %UserProfile%\AppData\Local\Microsoft\VisualStudio\10.0Exp\Extensions\Contoso\Web Part Gallery Node Extension for Server Explorer\1.0 中,并启动 Visual Studio 的实验实例。 您将在此 Visual Studio 实例中测试项目项。

测试扩展

  1. 在 Visual Studio 的实验实例中,在**“视图”菜单上单击“服务器资源管理器”**。

  2. 验证要用于测试的 SharePoint 网站是否显示在**“服务器资源管理器”中的“SharePoint 连接”**节点下。 如果未列出此网站,请执行下列步骤:

    1. 右击**“SharePoint 连接”并单击“添加连接”**。

    2. 在**“添加 SharePoint 连接”**对话框中,输入要连接到的 SharePoint 网站的 URL。 若要指定开发计算机上的 SharePoint 网站,请键入 https://localhost。

    3. 单击**“确定”**。

  3. 展开网站集节点(即显示网站的 URL 的节点),再展开子网站节点(例如**“团队网站”**)。

  4. 验证另一个 Visual Studio 实例中的代码是否会在您之前在 NodeChildrenRequested 方法中设置的断点处停止。 按 F5 以继续调试项目。

  5. 在 Visual Studio 的实验实例中,验证名为**“Web 部件库”的新节点是否显示在首要网站节点下。 展开“Web 部件库”**节点。

  6. 验证另一个 Visual Studio 实例中的代码是否会在您之前在 CreateWebPartNodes 方法中设置的断点处停止。 按 F5 以继续调试项目。

  7. 在 Visual Studio 的实验实例中,验证已连接网站上的所有 Web 部件是否都显示在**“服务器资源管理器”中的“Web 部件库”**节点下。

  8. 右击其中的某个 Web 部件,然后单击**“属性”**。

  9. 验证有关 Web 部件的详细信息是否显示在**“属性”**窗口中。

  10. 在**“服务器资源管理器”中,再次右击同一个 Web 部件,然后单击“显示消息”**。

    验证是否出现消息框。 在消息框中单击**“确定”**。

从 Visual Studio 中卸载扩展

测试完扩展后,请从 Visual Studio 卸载扩展。

卸载扩展

  1. 在 Visual Studio 的实验实例中,在**“工具”菜单上单击“扩展管理器”**。

    这将打开**“扩展管理器”**对话框。

  2. 在扩展列表中,单击“服务器资源管理器的 Web 部件库节点扩展”,然后单击**“卸载”**。

  3. 在出现的对话框中,单击**“是”**以确认您要卸载该扩展。

  4. 单击**“立即重新启动”**以完成卸载。 相应的项目项也会随之卸载。

  5. 关闭 Visual Studio 的两个实例(Visual Studio 的实验实例和 Visual Studio 的已打开 WebPartNode 解决方案的实例)。

请参见

任务

演练:扩展服务器资源管理器以显示 Web 部件

创建新位图或其他图像

参考

图像编辑器

概念

调入 SharePoint 对象模型

其他资源

扩展服务器资源管理器中的“SharePoint 连接”节点