演练:扩展 SharePoint 项目项类型

可以使用**“业务数据连接模型”**项目项来为 SharePoint 中的业务数据连接 (BDC) 服务创建模型。 默认情况下,当使用此项目项创建模型时,不会向用户显示模型中的数据。 您还必须在 SharePoint 中创建一个外部列表,这样用户才能查看数据。

在本演练中,您将为**“业务数据连接模型”**项目项创建一个扩展。 开发人员可以使用此扩展在其项目中创建一个外部列表,以用来显示 BDC 模型中的数据。 本演练将演示以下任务:

  • 创建一个执行以下两大任务的 Visual Studio 扩展:

    • 此扩展生成一个用于显示 BDC 模型中的数据的外部列表。 此扩展使用 SharePoint 项目系统的对象模型来生成一个用于定义列表的 Elements.xml 文件。 此扩展还将该文件添加到项目中,以便将该文件与 BDC 模型一起部署。

    • 此扩展将一个快捷菜单项添加到**“解决方案资源管理器”“业务数据连接模型”**项目项中。 开发人员可以单击此菜单项来为 BDC 模型生成一个外部列表。

  • 生成 Visual Studio 扩展 (VSIX) 包来部署扩展程序集。

  • 测试扩展。

系统必备

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

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

  • Microsoft SharePoint Server 2010 中的 BDC 服务。 有关更多信息,请参见 BDC Architecture(BDC 体系结构)。

  • BDC 模型的 XML 架构。 有关更多信息,请参见 BDC Model Infrastructure(BDC 模型基础结构)。

创建项目

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

  • 一个用于创建 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. 在**“名称”**框中键入 GenerateExternalDataLists。

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

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

创建扩展项目

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

    提示

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

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

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

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

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

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

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

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

配置扩展项目

在编写代码以创建项目项扩展之前,请将代码文件和程序集引用添加到扩展项目中。

配置项目

  1. 在 BdcProjectItemExtension 项目中添加两个具有下列名称的代码文件:

    • ProjectItemExtension

    • GenerateExternalDataLists

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

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

    • Microsoft.VisualStudio.SharePoint

    • System.ComponentModel.Composition

    • WindowsBase

定义项目项扩展

创建一个定义**“业务数据连接模型”**项目项扩展的类。 若要定义扩展,此类应实现 ISharePointProjectItemTypeExtension 接口。 每当需要扩展现有类型的项目项时,就要实现此接口。

定义项目项扩展

  1. 双击 ProjectItemExtension 代码文件。

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

    提示

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

    Imports Microsoft.VisualStudio.SharePoint
    Imports System.ComponentModel.Composition
    
    Namespace Contoso.SharePointProjectItemExtensions.GenerateExternalDataLists
    
        ' Export attribute: Enables Visual Studio to discover and load this extension.
        ' SharePointProjectItemType attribute: Specifies the ID of the project item to extend.
        ' GenerateExternalDataListsExtension class: Defines the extension for the BDC project item.
        '     The other part of the partial class contains the logic for generating the external data lists. 
        <Export(GetType(ISharePointProjectItemTypeExtension))> _
        <SharePointProjectItemType("Microsoft.VisualStudio.SharePoint.BusinessDataConnectivity")> _
        Partial Friend Class GenerateExternalDataListsExtension
            Implements ISharePointProjectItemTypeExtension
    
            ' Creates the new shortcut menu item that the user clicks to generate the external data lists.
            Private Sub Initialize(ByVal SharePointProjectItemType As ISharePointProjectItemType) _
                Implements ISharePointProjectItemTypeExtension.Initialize
                AddHandler SharePointProjectItemType.ProjectItemMenuItemsRequested,
                    AddressOf SharePointProjectItemMenuItemsRequested
            End Sub
    
            Private Sub SharePointProjectItemMenuItemsRequested(ByVal Sender As Object, _
                ByVal e As SharePointProjectItemMenuItemsRequestedEventArgs)
                Dim generateListMenuItem As IMenuItem = e.ViewMenuItems.Add("Generate External Data List")
                AddHandler generateListMenuItem.Click, AddressOf GenerateExternalDataLists_Execute
            End Sub
        End Class
    End Namespace
    
    using Microsoft.VisualStudio.SharePoint;
    using System.ComponentModel.Composition;
    
    namespace Contoso.SharePointProjectItemExtensions.GenerateExternalDataLists
    {
        // Enables Visual Studio to discover and load this extension.
        [Export(typeof(ISharePointProjectItemTypeExtension))]
    
        // Specifies the ID of the project item to extend.
        [SharePointProjectItemType("Microsoft.VisualStudio.SharePoint.BusinessDataConnectivity")]
    
        // Defines the extension for the BDC project item. The other part of the partial class contains
        // the logic for generating the external data lists. 
        internal partial class GenerateExternalDataListsExtension : ISharePointProjectItemTypeExtension
        {
            // Implements IProjectItemTypeExtension.Initialize. Creates the new shortcut menu item that
            // the user clicks to generate the external data lists.
            public void Initialize(ISharePointProjectItemType projectItemType)
            {
                projectItemType.ProjectItemMenuItemsRequested += ProjectItemMenuItemsRequested;
            }
    
            private void ProjectItemMenuItemsRequested(object sender, SharePointProjectItemMenuItemsRequestedEventArgs e)
            {
                e.ViewMenuItems.Add("Generate External Data List").Click += GenerateExternalDataLists_Execute;
            }
        }
    }
    

创建外部数据列表

添加 GenerateExternalDataListsExtension 类的分部定义,该类为 BDC 模型中的每个实体创建一个外部数据列表。 若要创建外部数据列表,此代码应首先通过分析 BDC 模型文件中的 XML 数据,读取 BDC 模型中的实体数据。 然后,此代码基于 BDC 模型创建一个列表实例,并将此列表实例添加到项目中。

创建外部数据列表

  1. 双击 GenerateExternalDataLists 代码文件。

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

    Imports Microsoft.VisualStudio.SharePoint
    Imports Microsoft.VisualBasic
    Imports System
    Imports System.Collections.Generic
    Imports System.IO
    Imports System.Linq
    Imports System.Text
    Imports System.Xml.Linq
    
    Namespace Contoso.SharePointProjectItemExtensions.GenerateExternalDataLists
    
        ' Creates the external data lists for the BDC item. The other part of the partial class 
        ' defines the BDC project item extension.
        Partial Friend Class GenerateExternalDataListsExtension
    
            Private Const ModelFileNameString As String = "ModelFileName"
            Private Const EXTENSION_BDCM As String = ".bdcm"
            Private Const NamespaceString As String = "https://schemas.microsoft.com/windows/2007/BusinessDataCatalog"
            Private Shared ReadOnly BdcNamespace As XNamespace = XNamespace.Get(NamespaceString)
    
            ' Generates an external data list for each Entity in the BDC model. This event handler is called
            ' when the developer clicks the shortcut menu item that the extension adds to the BDC project item.
            Private Sub GenerateExternalDataLists_Execute(ByVal Sender As Object, ByVal e As MenuItemEventArgs)
    
                Dim projectItem As ISharePointProjectItem = CType(e.Owner, ISharePointProjectItem)
                Dim bdcmFile As ISharePointProjectItemFile = GetModelFile(projectItem)
    
                Dim doc As XDocument = XDocument.Load(bdcmFile.FullPath)
                Dim skippedEntities As List(Of XElement) = New List(Of XElement)()
    
                ' Try to generate an external data list for each entity defined in the BDC model file.
                For Each entity As XElement In doc.Root.Elements(BdcNamespace + "LobSystems").Elements( _
                    BdcNamespace + "LobSystem").Elements(BdcNamespace + "Entities").Elements(BdcNamespace + "Entity")
    
                    If False = GenerateExternalDataList(projectItem, entity) Then
                        skippedEntities.Add(entity)
                    End If
                Next
    
                ' Report skipped entities.
                If skippedEntities.Count <> 0 Then
                    Dim entityNameList As StringBuilder = Nothing
                    skippedEntities.ForEach(Function(entity As XElement)
                                                If (entityNameList Is Nothing) Then
                                                    entityNameList = New StringBuilder()
                                                Else
                                                    entityNameList.AppendLine(",")
                                                End If
                                                entityNameList.Append(entity.Attribute("Name").Value)
                                            End Function)
    
                    Dim message As String = String.Format("The following Entities were skipped because " &
                        "either a LobSystemInstance, SpecificFinder, or Finder was not found for them. \r\n{0}", _
                        entityNameList)
                    projectItem.Project.ProjectService.Logger.WriteLine(message, LogCategory.Warning)
                End If
            End Sub
    
            ' Gets the ISharePointProjectItemFile object for the BDC model file.
            Private Function GetModelFile(ByVal projectItem As ISharePointProjectItem) As ISharePointProjectItemFile
    
                Dim modelFileName As String = Nothing
                If projectItem.FeatureProperties.TryGetValue(ModelFileNameString, modelFileName) Then
                    modelFileName = Path.GetFileName(modelFileName)
                    Return (From file In projectItem.Files _
                            Where String.Compare(file.Name, modelFileName, StringComparison.OrdinalIgnoreCase) = 0 _
                            Select file).FirstOrDefault()
                Else
                    ' If we can't find the ModelFileName through the FeatureProperties, 
                    ' get the first file that has a '.bdcm' extension
                    Return (From file In projectItem.Files _
                            Where file.Name.EndsWith(EXTENSION_BDCM, StringComparison.OrdinalIgnoreCase) _
                            Select file).FirstOrDefault()
                End If
            End Function
    
            ' Boilerplate XML for the new list instance that is based on the BDC model.
            Private Const externalDataListContent As String = _
                "<?xml version=""1.0"" encoding=""utf-8""?>" & vbCrLf & _
                "        <Elements https://schemas.microsoft.com/sharepoint/"">" & vbCrLf & _
                "          <ListInstance Title=""$EntityName$DataList""" & vbCrLf & _
                "                        OnQuickLaunch=""TRUE""" & vbCrLf & _
                "                        TemplateType=""104""" & vbCrLf & _
                "                        FeatureId=""$SharePoint.Feature.Id$""" & vbCrLf & _
                "                        Url=""Lists/$EntityName$DataList""" & vbCrLf & _
                "                        Description=""Default List for $EntityName$."">" & vbCrLf & _
                "            <DataSource>" & vbCrLf & _
                "              <Property Name=""LobSystemInstance"" Value=""$LobSystemInstance$"" />" & vbCrLf & _
                "              <Property Name=""EntityNamespace"" Value=""$EntityNamespace$"" />" & vbCrLf & _
                "              <Property Name=""Entity"" Value=""$EntityName$"" />" & vbCrLf & _
                "              <Property Name=""SpecificFinder"" Value=""$SpecificFinder$"" />" & vbCrLf & _
                "              <Property Name=""Finder"" Value=""$Finder$"" />" & vbCrLf & _
                "            </DataSource>" & vbCrLf & _
                "          </ListInstance>" & vbCrLf & _
                "        </Elements>"
    
            ' Tries to generate an external data list for the specified BDC model project item and entity.
            Private Function GenerateExternalDataList(ByVal projectItem As ISharePointProjectItem, ByVal entity As XElement) As Boolean
    
                Dim lobSystemInstanceName As String = GetLobSystemInstanceName(entity)
                Dim specificFinderName As String = GetSpecificFinderName(entity)
                Dim finderName As String = GetFinderName(entity)
                Dim entityName As String = entity.Attribute("Name").Value
    
                If String.IsNullOrEmpty(lobSystemInstanceName) Or String.IsNullOrEmpty(specificFinderName) Or _
                    String.IsNullOrEmpty(finderName) Then
                    Return False
                End If
    
                Dim newExternalDataListName As String = entityName & "DataList"
                Dim existingProjectItem As ISharePointProjectItem = (From existingItem As ISharePointProjectItem In projectItem.Project.ProjectItems
                                                    Where existingItem.Name = newExternalDataListName
                                                    Select existingItem).FirstOrDefault()
    
                ' Add a new list instance and populate it with data from the BDC model.
                If existingProjectItem Is Nothing Then
                    Dim newExternalDataList As ISharePointProjectItem = projectItem.Project.ProjectItems.Add(newExternalDataListName, _
                        "Microsoft.VisualStudio.SharePoint.ListInstance")
    
                    Dim newExternalDataListString As String = externalDataListContent
                    newExternalDataListString = newExternalDataListString.Replace("$EntityName$", entityName)
                    newExternalDataListString = newExternalDataListString.Replace("$LobSystemInstance$", lobSystemInstanceName)
                    newExternalDataListString = newExternalDataListString.Replace("$EntityNamespace$", entity.Attribute("Namespace").Value)
                    newExternalDataListString = newExternalDataListString.Replace("$SpecificFinder$", specificFinderName)
                    newExternalDataListString = newExternalDataListString.Replace("$Finder$", finderName)
    
                    Dim elementsXmlPath As String = Path.Combine(newExternalDataList.FullPath, "Elements.xml")
                    File.WriteAllText(elementsXmlPath, newExternalDataListString)
                    Dim elementsFile As ISharePointProjectItemFile = newExternalDataList.Files.AddFromFile(elementsXmlPath)
                    elementsFile.DeploymentType = DeploymentType.ElementManifest
                End If
    
                Return True
            End Function
    
            Private Function GetLobSystemInstanceName(ByVal entity As XElement) As String
    
                Dim lobSystemInstances As XElement = entity.Parent.Parent.Element(BdcNamespace + "LobSystemInstances")
                If lobSystemInstances IsNot Nothing Then
                    Dim lobSystemInstance As XElement = lobSystemInstances.Elements(BdcNamespace + "LobSystemInstance").FirstOrDefault()
                    If lobSystemInstance IsNot Nothing Then
                        Return lobSystemInstance.Attribute("Name").Value
                    End If
                End If
                Return Nothing
            End Function
    
            Private Function GetSpecificFinderName(ByVal entity As XElement) As String
                Return GetMethodInstance(entity, "SpecificFinder")
            End Function
    
            Private Function GetFinderName(ByVal entity As XElement) As String
                Return GetMethodInstance(entity, "Finder")
            End Function
    
            Private Function GetMethodInstance(ByVal entity As XElement, ByVal methodInstanceType As String) As String
                Dim methods As XElement = entity.Element(BdcNamespace + "Methods")
                If methods IsNot Nothing Then
                    For Each method As XElement In methods.Elements(BdcNamespace + "Method")
                        Dim methodInstances As XElement = method.Element(BdcNamespace + "MethodInstances")
                        If methodInstances IsNot Nothing Then
                            For Each methodInstance As XElement In methodInstances.Elements(BdcNamespace + "MethodInstance")
                                If methodInstance.Attribute("Type").Value = methodInstanceType Then
                                    Return methodInstance.Attribute("Name").Value
                                End If
                            Next
                        End If
                    Next
                End If
                Return Nothing
            End Function
    
        End Class
    End Namespace
    
    using Microsoft.VisualStudio.SharePoint;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;
    
    namespace Contoso.SharePointProjectItemExtensions.GenerateExternalDataLists
    {
        // Creates the external data lists for the BDC item. The other part of the partial class 
        // defines the BDC project item extension.
        internal partial class GenerateExternalDataListsExtension
        {
            private const string ModelFileNameString = "ModelFileName";
            private const string EXTENSION_BDCM = ".bdcm";
            private const string NamespaceString = "https://schemas.microsoft.com/windows/2007/BusinessDataCatalog";
            private static readonly XNamespace BdcNamespace = XNamespace.Get(NamespaceString);
    
            // Generates an external data list for each Entity in the BDC model. This event handler is called
            // when the developer clicks the shortcut menu item that the extension adds to the BDC project item.
            private void GenerateExternalDataLists_Execute(object sender, MenuItemEventArgs e)
            {
                ISharePointProjectItem projectItem = (ISharePointProjectItem)e.Owner;
                ISharePointProjectItemFile bdcmFile = GetModelFile(projectItem);
    
                XDocument doc = XDocument.Load(bdcmFile.FullPath);
                List<XElement> skippedEntities = new List<XElement>();
    
                // Try to generate an external data list for each entity defined in the BDC model file.
                foreach (XElement entity in doc.Root.Elements(BdcNamespace + "LobSystems").Elements(
                    BdcNamespace + "LobSystem").Elements(BdcNamespace + "Entities").Elements(BdcNamespace + "Entity"))
                {
                    if (!GenerateExternalDataList(projectItem, entity))
                    {
                        skippedEntities.Add(entity);
                    }
                }
    
                // Report skipped entities.
                if (skippedEntities.Count != 0)
                {
                    StringBuilder entityNameList = null;
                    skippedEntities.ForEach(delegate(XElement entity)
                    {
                        if (entityNameList == null)
                        {
                            entityNameList = new StringBuilder();
                        }
                        else
                        {
                            entityNameList.AppendLine(",");
                        }
                        entityNameList.Append(entity.Attribute("Name").Value);
                    });
    
                    string message = string.Format("The following Entities were skipped because either a LobSystemInstance, " +
                        "SpecificFinder, or Finder was not found for them. \r\n{0}", entityNameList);
                    projectItem.Project.ProjectService.Logger.WriteLine(message, LogCategory.Warning);
                }
            }
    
            // Gets the ISharePointProjectItemFile object for the BDC model file.
            private ISharePointProjectItemFile GetModelFile(ISharePointProjectItem projectItem)
            {
                string modelFileName;
                if (projectItem.FeatureProperties.TryGetValue(ModelFileNameString, out modelFileName))
                {
                    modelFileName = Path.GetFileName(modelFileName);
                    return (from file in projectItem.Files
                            where string.Compare(file.Name, modelFileName, StringComparison.OrdinalIgnoreCase) == 0
                            select file).FirstOrDefault();
                }
                else
                {
                    // if we can't find the ModelFileName through the FeatureProperties, 
                    // get the first file that has a '.bdcm' extension
                    return (from file in projectItem.Files
                            where file.Name.EndsWith(EXTENSION_BDCM, StringComparison.OrdinalIgnoreCase)
                            select file).FirstOrDefault();
                }
            }
    
            // Boilerplate XML for the new list instance that is based on the BDC model.
            private const string externalDataListContent =
                @"<?xml version=""1.0"" encoding=""utf-8""?>
                <Elements https://schemas.microsoft.com/sharepoint/"">
                  <ListInstance Title=""$EntityName$DataList""
                                OnQuickLaunch=""TRUE""
                                TemplateType=""104""
                                FeatureId=""$SharePoint.Feature.Id$""
                                Url=""Lists/$EntityName$DataList""
                                Description=""Default List for $EntityName$."">
                    <DataSource>
                      <Property Name=""LobSystemInstance"" Value=""$LobSystemInstance$"" />
                      <Property Name=""EntityNamespace"" Value=""$EntityNamespace$"" />
                      <Property Name=""Entity"" Value=""$EntityName$"" />
                      <Property Name=""SpecificFinder"" Value=""$SpecificFinder$"" />
                      <Property Name=""Finder"" Value=""$Finder$"" />
                    </DataSource>
                  </ListInstance>
                </Elements>";
    
            // Tries to generate an external data list for the specified BDC model project item and entity.
            private bool GenerateExternalDataList(ISharePointProjectItem projectItem, XElement entity)
            {
                string lobSystemInstanceName = GetLobSystemInstanceName(entity);
                string specificFinderName = GetSpecificFinderName(entity);
                string finderName = GetFinderName(entity);
                string entityName = entity.Attribute("Name").Value;
    
                if (string.IsNullOrEmpty(lobSystemInstanceName) || string.IsNullOrEmpty(specificFinderName) || 
                    string.IsNullOrEmpty(finderName))
                {
                    return false;
                }
    
                string newExternalDataListName = entityName + "DataList";
                ISharePointProjectItem existingProjectItem = (from ISharePointProjectItem existingItem in projectItem.Project.ProjectItems
                                                    where existingItem.Name == newExternalDataListName
                                                    select existingItem).FirstOrDefault();
    
                // Add a new list instance and populate it with data from the BDC model.
                if (existingProjectItem == null)
                {
                    ISharePointProjectItem newExternalDataList = projectItem.Project.ProjectItems.Add(newExternalDataListName, 
                        "Microsoft.VisualStudio.SharePoint.ListInstance");
    
                    string newExternalDataListString = externalDataListContent;
                    newExternalDataListString = newExternalDataListString.Replace("$EntityName$", entityName);
                    newExternalDataListString = newExternalDataListString.Replace("$LobSystemInstance$", lobSystemInstanceName);
                    newExternalDataListString = newExternalDataListString.Replace("$EntityNamespace$", entity.Attribute("Namespace").Value);
                    newExternalDataListString = newExternalDataListString.Replace("$SpecificFinder$", specificFinderName);
                    newExternalDataListString = newExternalDataListString.Replace("$Finder$", finderName);
    
                    string elementsXmlPath = Path.Combine(newExternalDataList.FullPath, "Elements.xml");
                    File.WriteAllText(elementsXmlPath, newExternalDataListString);
                    ISharePointProjectItemFile elementsFile = newExternalDataList.Files.AddFromFile(elementsXmlPath);
                    elementsFile.DeploymentType = DeploymentType.ElementManifest;
                }
    
                return true;
            }
    
            private string GetLobSystemInstanceName(XElement entity)
            {
                XElement lobSystemInstances = entity.Parent.Parent.Element(BdcNamespace + "LobSystemInstances");
                if (lobSystemInstances != null)
                {
                    XElement lobSystemInstance = lobSystemInstances.Elements(BdcNamespace + "LobSystemInstance").FirstOrDefault();
                    if (lobSystemInstance != null)
                    {
                        return lobSystemInstance.Attribute("Name").Value;
                    }
                }
                return null;
            }
    
            private string GetSpecificFinderName(XElement entity)
            {
                return GetMethodInstance(entity, "SpecificFinder");
            }
    
            private string GetFinderName(XElement entity)
            {
                return GetMethodInstance(entity, "Finder");
            }
    
            private string GetMethodInstance(XElement entity, string methodInstanceType)
            {
                XElement methods = entity.Element(BdcNamespace + "Methods");
                if (methods != null)
                {
                    foreach (XElement method in methods.Elements(BdcNamespace + "Method"))
                    {
                        XElement methodInstances = method.Element(BdcNamespace + "MethodInstances");
                        if (methodInstances != null)
                        {
                            foreach (XElement methodInstance in methodInstances.Elements(BdcNamespace + "MethodInstance"))
                            {
                                if (methodInstance.Attribute("Type").Value == methodInstanceType)
                                {
                                    return methodInstance.Attribute("Name").Value;
                                }
                            }
                        }
                    }
                }
    
                return null;
            }
        }
    }
    

检查点

演练进行到此时,项目项扩展的所有代码都位于项目中。 生成解决方案以确保编译项目时不会出错。

生成解决方案

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

创建 VSIX 包以部署项目项扩展

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

配置并创建 VSIX 包

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

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

  2. 在**“产品名称”**框中键入“外部数据列表生成器”。

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

  4. 在**“说明”**框中,键入“可用于生成外部数据列表的业务数据连接模型项目项的扩展”。

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

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

    提示

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

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

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

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

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

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

测试项目项扩展

现在您可以对项目项扩展进行测试了。 首先,在 Visual Studio 的实验实例中开始调试扩展项目。 然后,在 Visual Studio 的实验实例中使用扩展以生成 BDC 模型的外部列表。 最后,打开 SharePoint 网站上的外部列表,以验证该列表是否按预期方式工作。

开始调试扩展

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

  2. 在 BdcProjectItemExtension 项目中,打开 ProjectItemExtension 代码文件,并在 Initialize 方法的代码行中添加一个断点。

  3. 打开 GenerateExternalDataLists 代码文件,并在 GenerateExternalDataLists_Execute 方法的第一行代码中添加一个断点。

  4. F5 开始调试。

    Visual Studio 将扩展安装到 %UserProfile%\AppData\Local\Microsoft\VisualStudio\10.0Exp\Extensions\Contoso\External Data List Generator\1.0 中,并启动 Visual Studio 的实验实例。 您将在此 Visual Studio 实例中测试项目项。

测试扩展

  1. 在 Visual Studio 的实验实例中,在**“文件”菜单上指向“新建”,然后单击“项目”**。

  2. 展开**“Visual C#”,再展开“SharePoint”,然后单击“2010”**。

  3. 在对话框顶部的组合框中,确保选定**“.NET Framework 3.5”**。 Microsoft SharePoint Server 2010 项目需要此版本的 .NET Framework。

  4. 在项目模板的列表中,单击**“业务数据连接模型”**。

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

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

  7. 在**“SharePoint 自定义向导”中,键入要用于调试的网站的 URL,并单击“完成”**。

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

  9. 在 Visual Studio 的实验实例中,按 F5以生成、部署和运行 TestBDCModel 项目。 Web 浏览器将打开用于调试的 SharePoint 网站的默认页面。

  10. 确认快速启动区域中的**“列表”**部分尚未包含基于项目中的默认 BDC 模型的列表。 您首先必须通过使用 SharePoint 用户界面或通过使用项目项扩展,创建一个外部数据列表。

  11. 关闭 Web 浏览器。

  12. 在打开 TestBDCModel 项目的 Visual Studio 实例中,右击**“解决方案资源管理器”中的“BdcModel1”节点,再单击“生成外部数据列表”**。

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

  14. Visual Studio 的实验实例将向 TestBDCModel 项目中添加名为**“Entity1DataList”的列表实例,并且还将为该列表实例生成一项名为“Feature2”**的功能。

  15. 按 F5 以生成、部署并运行 TestBDCModel 项目。 Web 浏览器将打开用于调试的 SharePoint 网站的默认页面。

  16. 确认快速启动中的**“列表”**部分现在包含一个名为 Entity1DataList 的列表。

  17. 单击**“Entity1DataList”**列表。

  18. 确认该列表包含名为 Identifier1 和 Message 的列,并包含一个“Identifier1”值为“0”且“Message”值为“Hello World”的项。 所有这些数据都是由**“业务数据连接模型”**项目模板生成的默认 BDC 模型提供的。

  19. 关闭 Web 浏览器。

清理开发计算机

完成测试项目项扩展之后,从 SharePoint 网站中移除外部列表和 BDC 模型,并从 Visual Studio 中移除项目项扩展。

从 SharePoint 网站中移除外部数据列表

  1. 在 SharePoint 网站的快速启动区域中,单击**“Entity1DataList”**列表。

  2. 在 SharePoint 网站上的功能区中,单击**“列表”**选项卡。

  3. 在**“列表”选项卡上的“设置”组中,单击“列表设置”**。

  4. 在**“权限和管理”下,单击“删除此列表”。 单击“确定”**以确认要将此列表发送到回收站。

  5. 关闭 Web 浏览器。

从 SharePoint 网站中移除 BDC 模型

  • 在 Visual Studio 的实验实例中,在**“生成”菜单上单击“收回”**。

    Visual Studio 将从 SharePoint 网站中移除 BDC 模型。

从 Visual Studio 中移除项目项扩展

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

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

  2. 在扩展列表中,单击**“外部数据列表生成器”,然后单击“卸载”**。

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

  4. 单击**“立即重新启动”**以完成卸载。

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

请参见

概念

扩展 SharePoint 项目系统

其他资源

创建业务数据连接模型

设计业务数据连接模型