逐步解說:擴充 SharePoint 專案項目類型

您可以使用 [商務資料連接模型] 專案項目在 SharePoint 中建立商務資料連接 (BDC) 服務的模型。 根據預設,當您使用此專案項目建立模型時,模型中的資料不會對使用者顯示。 您也必須在 SharePoint 中建立外部清單,才能讓使用者檢視資料。

在此逐步解說中,您將建立 [商務資料連接模型] 專案項目的擴充功能。 開發人員可以使用擴充功能在顯示 BDC 模型資料的專案中建立外部清單。 本逐步解說將示範下列工作:

  • 建立執行兩項主要工作的 Visual Studio 擴充功能:

    • 它會產生顯示 BDC 模型資料的外部清單。 擴充功能會使用 SharePoint 專案系統的物件模型產生定義清單的 Elements.xml 檔。 此外還會將檔案加入至專案,以便隨 BDC 模型一併部署。

    • 它會將捷徑功能表項目加入至 [方案總管] 中的 [商務資料連接模型] 專案項目。 開發人員按一下此功能表項目,就可以產生 BDC 模型的外部清單。

  • 建置 Visual Studio Extension (VSIX) Package 以部署擴充組件。

  • 測試擴充功能。

必要條件

開發電腦上需要下列元件才能完成此逐步解說:

了解下列概念有助於完成此逐步解說 (但非必要):

  • Microsoft SharePoint Server 2010 中的 BDC 服務。 如需詳細資訊,請參閱 BDC 架構 (英文)。

  • BDC 模型的 XML 結構描述。 如需詳細資訊,請參閱 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 的實驗執行個體會將名為 Entity1DataList 的清單執行個體加入至 TestBDCModel 專案,同時會針對清單執行個體產生名為 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 的實驗執行個體,以及其中有開啟 GenerateExternalDataLists 專案的執行個體)。

請參閱

概念

擴充 SharePoint 專案系統

其他資源

建立商務資料連接模型

設計商務資料連接模型