共用方式為


在圖層圖表中加入自訂架構驗證

更新:2010 年 12 月

在 Visual Studio 2010 Ultimate 和 Visual Studio 2010 Premium 中,使用者可以根據圖層模型驗證 Visual Studio 專案中的原始程式碼,以便確認原始程式碼是否符合圖層圖表的相依性。 雖然系統提供了標準驗證演算法,不過這個 Visual Studio 2010 功能套件可讓您針對 Visual Studio Ultimate 和 Visual Studio Premium 定義自己的驗證擴充功能。 如需詳細資訊,請參閱 Visual Studio 功能套件

當使用者在圖層圖表上選取 [驗證架構] 命令時,系統就會先叫用標準驗證方法,然後再叫用已經安裝的任何驗證擴充功能。

注意事項注意事項

圖層圖表中的驗證與 UML 圖表中的驗證不相同。 在圖層圖表中,其主要目的是要比較圖表與其他方案部分中的程式碼。

您可以將圖層驗證擴充功能封裝成 Visual Studio Integration Extension (VSIX),以便散發給其他 Visual Studio Ultimate 使用者。 您可以將驗證程式單獨置放在 VSIX 中,也可以在相同的 VSIX 中,將它與其他擴充功能結合。 您應該在驗證程式自己的 Visual Studio 專案 (而非其他擴充功能的相同專案) 中撰寫驗證程式的程式碼。

需求

如需相關需求和安裝指示,請參閱建立圖層圖表的擴充功能 中的需求

在新的 VSIX 中定義圖層驗證程式

建立驗證程式最快速的方法是使用專案範本。 這樣做會將程式碼和 VSIX 資訊清單放入相同的專案中。

若要使用專案範本定義擴充功能

  1. 使用 [檔案] 功能表上的 [新增專案] 命令,在新的方案中建立專案。

  2. 在 [新增專案] 對話方塊的 [模型專案] 底下,選取 [Layer Designer Validation Extension] (圖層設計工具驗證擴充功能)。

    此範本就會建立包含小型範例的專案。

  3. 編輯程式碼以定義驗證。 如需詳細資訊,請參閱驗證程式設計。

  4. 若要測試擴充功能,請參閱偵錯圖層驗證。

    注意事項注意事項

    您的方法只會在特定情況下呼叫,而且中斷點將無法自動運作。 如需詳細資訊,請參閱偵錯圖層驗證。

  5. 若要在 Visual Studio 的主要執行個體或其他電腦上安裝擴充功能,請在 bin\* 中尋找 .vsix 檔案。 將它複製到您想要安裝的目標電腦,然後按兩下該檔案。 若要解除安裝此元件,請使用 [工具] 功能表上的 [擴充管理員]。

將圖層驗證程式加入至個別 VSIX

如果您想要建立包含圖層驗證程式、命令和其他擴充功能的單一 VSIX,我們建議您建立單一專案來定義 VSIX,並且針對處理常式建立個別專案。 如需其他模型擴充功能類型的詳細資訊,請參閱擴充 UML 模型與圖表

若要將圖層驗證加入至個別 VSIX

  1. 在全新或現有的 Visual Studio Ultimate 方案中建立類別庫專案。 在 [新增專案] 對話方塊中,按一下 [Visual C#],然後按一下 [類別庫]。 這個專案將會包含圖層驗證類別。

  2. 在您的方案中識別或建立 VSIX 專案。 VSIX 專案會包含名為 source.extension.vsixmanifest 的檔案。 如果您必須加入 VSIX 專案,請執行下列步驟:

    1. 在 [新增專案] 對話方塊中,展開 [Visual C#]、按一下 [擴充性],然後按一下 [VSIX 專案]。

    2. 在 [方案總管] 中,以滑鼠右鍵按一下 VSIX 專案,然後按一下 [設定為啟始專案]。

    3. 按一下 [Select Editions] (選取版本) 並確定已核取 Visual Studio Ultimate。

  3. source.extension.vsixmanifest 的 [內容] 底下,加入圖層驗證專案當做 MEF 元件:

    1. 按一下 [加入內容]。

    2. 在 [選取內容類型] 中,選取 [MEF 元件]。

    3. 在 [Select a source] (選取來源) 中,按一下 [專案],然後選取命令或筆勢處理常式專案的名稱。

    4. 儲存檔案。

  4. 加入圖層驗證專案當做自訂擴充功能:

    1. 按一下 [加入內容]。

    2. 在 [選取內容類型] 中,選取 [自訂擴充功能類型]。

    3. 在 [類型] 中,輸入 Microsoft.VisualStudio.ArchitectureTools.Layer.Validator。

    4. 在 [Select a source] (選取來源) 中,按一下 [專案],然後選取驗證類別庫專案的名稱。

  5. 按一下 [參考] 底下 [加入參考] 並且選取這個功能套件的執行階段。

  6. 返回圖層驗證專案,然後加入下列專案參考:

    參考

    這可讓您執行的項目

    如果您已經安裝 Visual Studio 2010 Visualization and Modeling 功能套件:

    %LocalAppData%\Microsoft\VisualStudio\10.0\Extensions\Microsoft\Visualization and Modeling Feature Pack Runtime\1.0\Microsoft.VisualStudio.GraphModel.dll

    如果您已經安裝 Visual Studio 2010 Feature Pack 2:

    …\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Visualization and Modeling Feature Pack Runtime\1.0\Microsoft.VisualStudio.GraphModel.dll

    讀取架構圖形

    如果您已經安裝 Visual Studio 2010 Visualization and Modeling 功能套件:

    %LocalAppData%\Microsoft\VisualStudio\10.0\Extensions\Microsoft\Visualization and Modeling Feature Pack Runtime\1.0\Microsoft.VisualStudio.ArchitectureTools.Extensibility.CodeSchema.dll

    如果您已經安裝 Visual Studio 2010 Feature Pack 2:

    …\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\ Visualization and Modeling Feature Pack Runtime\1.0\Microsoft.VisualStudio.ArchitectureTools.Extensibility.CodeSchema.dll

    讀取與圖層相關聯的程式碼 DOM

    如果您已經安裝 Visual Studio 2010 Visualization and Modeling 功能套件:

    %LocalAppData%\Microsoft\VisualStudio\10.0\Extensions\Microsoft\Visualization and Modeling Feature Pack Runtime\1.0\Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer.dll

    如果您已經安裝 Visual Studio 2010 Feature Pack 2:

    …\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Visualization and Modeling Feature Pack Runtime\1.0\Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer.dll

    讀取圖層模型

    Microsoft.VisualStudio.Uml.Interfaces

    讀取圖層模型

    Microsoft.VisualStudio.ArchitectureTools.Extensibility

    讀取和更新圖案與圖表

    System.ComponentModel.Composition

    使用 Managed Extensibility Framework (MEF) 定義驗證元件

    Microsoft.VisualStudio.Modeling.Sdk.10.0

    定義模型擴充功能

    注意事項注意事項

    %LocalAppData% 通常是 DriveName:\Users\UserName\AppData\Local。 在 Windows XP 或 Windows 2003 上,請使用 %AppData% 而非 %LocalAppData%。

  7. 編輯 C# 類別庫專案中的類別檔案,以便包含驗證的程式碼。 如需詳細資訊,請參閱驗證程式設計。

  8. 若要測試擴充功能,請參閱偵錯圖層驗證。

    注意事項注意事項

    您的方法只會在特定情況下呼叫,而且中斷點將無法自動運作。 如需詳細資訊,請參閱偵錯圖層驗證。

  9. 若要在 Visual Studio 的主要執行個體或其他電腦上安裝 VSIX,請在 VSIX 專案的 bin 目錄中尋找 .vsix 檔案。 將它複製到您想要安裝 VSIX 的目標電腦。 在 [Windows 檔案總管] 中按兩下 VSIX 檔案。

    若要解除安裝此元件,請使用 [工具] 功能表上的 [擴充管理員]。

驗證程式設計

若要定義圖層驗證擴充功能,請定義具有下列特性的類別:

  • 宣告的整體格式如下:

      [Export(typeof(IValidateArchitectureExtension))]
      public partial class Validator1Extension :
                      IValidateArchitectureExtension
      {
        public void ValidateArchitecture(Graph graph)
        {
          var typeCategory = graph.DocumentSchema
                     .Categories.Get("CodeSchema_Type");
          var allTypes = graph.Nodes.GetByCategory(typeCategory);
        ...
          this.LogValidationError(graph, "SampleErrorId", 
             "Sample Validation Error", GraphErrorLevel.Error, allTypes);
        }
    
  • 當您發現錯誤時,可以使用 LogValidationError() 來報告錯誤。

當使用者叫用 [驗證架構] 功能表命令時,圖層執行階段系統就會分析圖層及其成品以產生圖形。 此圖形具有四個部分:

  • Visual Studio 方案的圖層模型,這些模型會在圖形中表示成節點和連結。

  • 定義於方案中而且表示成節點的程式碼、專案項目和其他成品,以及代表分析處理序所發現之相依性的連結。

  • 從圖層節點連至程式碼成品節點的連結。

  • 代表驗證程式所發現之錯誤的節點。

當系統已經建構圖形時,就會呼叫標準驗證方法。 完成此作業之後,系統就會按照未指定的順序呼叫任何已安裝的擴充功能驗證方法。 此圖形會傳遞給每個 ValidateArchitecture 方法,以便掃描圖形並報告它所發現的任何錯誤。

注意事項注意事項

這項作業與套用至 UML 圖表的驗證處理序不同,而且與可用於網域指定之語言的驗證處理序不同。

驗證方法不應該變更所驗證的圖層模型或程式碼。

圖形模型定義於 Microsoft.VisualStudio.GraphModel 中。 其主體類別為 Node 和 Link。

每個節點和每個連結都具有一個或多個分類,這些分類會指定它所代表的項目或關聯性類型。 一般圖形的節點具有下列分類:

  • Dsl.LayerModel

  • Dsl.Layer

  • Dsl.Reference

  • CodeSchema_Type

  • CodeSchema_Namespace

  • CodeSchema_Type

  • CodeSchema_Method

  • CodeSchema_Field

  • CodeSchema_Property

從圖層連至程式碼中項目的連結具有 "Represents" 分類。

下列程式碼是架構驗證擴充功能的一般範例。 它會確認在方案程式碼中宣告的每個型別至少都由圖層模型參考一次。 使用者可以透過設定模型的布林自訂屬性,控制這個驗證是否應該在每個圖層模型上執行。

如果發現錯誤,就會呼叫 LogValidationError。

偵錯驗證

若要偵錯圖層驗證擴充功能,請按下 CTRL+F5。 Visual Studio 的實驗執行個體隨即開啟。 在此執行個體中,開啟或建立圖層模型。 這個模型必須與程式碼相關聯,而且至少必須具有一個相依性。

使用包含相依性的方案進行測試

除非下列特性存在,否則系統不會執行驗證:

  • 圖層圖表至少具有一個相依性連結。

  • 模型具有與程式碼項目相關聯的圖層。

當您第一次啟動 Visual Studio 的實驗執行個體來測試驗證擴充功能時,請開啟或建立具有這些特性的方案。

驗證架構之前執行清除方案

每當您更新驗證程式碼時,請先在實驗方案中使用 [建置] 功能表上的 [清除方案] 命令,然後再測試 [驗證] 命令。 這是必要的步驟,因為系統會快取驗證的結果。 如果您尚未更新測試圖層圖表或其程式碼,系統就不會執行驗證方法。

明確啟動偵錯工具

驗證會在個別的處理序中執行。 因此,系統不會觸發驗證方法中的中斷點。 您必須在驗證啟動時,將偵錯工具明確附加至處理序。

若要將偵錯工具附加至驗證處理序,請在驗證方法的開頭插入 System.Diagnostics.Debugger.Launch() 的呼叫。 當偵錯對話方塊出現時,請選取 Visual Studio 的主要執行個體。

或者,您也可以插入 System.Windows.Forms.MessageBox.Show() 的呼叫。 當訊息方塊出現時,請移至 Visual Studio 的主要執行個體,然後按一下 [偵錯] 功能表上的 [附加至處理序]。接著,請選取名為 Graphcmd.exe 的處理序。

請務必按下 CTRL+F5 ([啟動但不偵錯]),藉以啟動實驗執行個體。

部署驗證擴充功能

若要在已安裝 Visual Studio Ultimate 或 Visual Studio Premium 的電腦上安裝您的驗證擴充功能,請在目標電腦上開啟 VSIX 檔案。 若要在已安裝 Team Foundation Build 的電腦上安裝,您必須將 VSIX 內容手動擷取至 Extensions 資料夾中。 如需詳細資訊,請參閱部署圖層模型擴充功能

範例

下列範例說明圖層驗證擴充功能。

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.CodeSchema;

using Microsoft.VisualStudio.GraphModel;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer;

namespace MyValidationExtensions
{ // This attribute identifies a layer validator:
  [Export(typeof(IValidateArchitectureExtension))]
  public partial class UnreferencedTypeValidatorExtension 
      : IValidateArchitectureExtension
  {
    private GraphCategory typeCategory = null;
    /// <summary>
    /// Validate the architecture
    /// </summary>
    /// <param name="graph">The graph</param>
    public void ValidateArchitecture(Graph graph)
    {
      // A good place to attach a debugger
      // System.Windows.Forms.MessageBox.Show("Attach - Unreferenced Type Validator");
      // To find the nodes that represent the code and the layers,
      // we need to filter by category.
      // Categories are identified by specific strings:
      if (typeCategory == null)
      {
        typeCategory = 
          graph.DocumentSchema.Categories.Get("CodeSchema_Type");
      }
      var layerModelCategory = 
        graph.DocumentSchema.Categories.Get("Dsl.LayerModel");
      var allLayerModels =
        graph.Nodes.GetByCategory(layerModelCategory);

      foreach (var layerModel in allLayerModels)
      {
        var allTypesMustBeReferencedProperty =
           ExtractProperty(layerModel, 
            AllTypesMustBeReferencedProperty.FullName);
        bool shouldAllTypesBeReferenced = 
          allTypesMustBeReferencedProperty == null 
          ? false 
          : Convert.ToBoolean(allTypesMustBeReferencedProperty);

        if (shouldAllTypesBeReferenced)
        {
          // Find all types referenced by layers:
          var referencedTypes = new HashSet<Node>();
          GetReferencedTypes(referencedTypes, layerModel);
          var allTypes = graph.Nodes.GetByCategory(typeCategory);

          foreach (var type in allTypes)
          {
            if (!referencedTypes.Contains(type))
            {
              // Filter out types that are not part of any 
              // assembly (for example referenced external types).
              if (type.GetContainmentSources(graph)
                .Where(n => n.HasCategory(graph.DocumentSchema
                .Categories.Get("CodeSchema_Assembly"))).Any())
              {
                // type is not referenced in the layer diagram
                this.LogValidationError(graph,
                    string.Format("{0}_UnreferencedTypeError_{1}",
                    GetFullyQualifiedTypeName(type), Guid.NewGuid()),
                    string.Format("AV1002 : Unreferenced type :"
                      + " {0}{2}Layer Diagram: {1}.layerdiagram.",
                        GetFullyQualifiedTypeName(type),
                        layerModel.Label,
                        Environment.NewLine),
                    GraphErrorLevel.Error,
                    new Node[] { type });
              }
            }
          }
        }
      }
    }

    private void GetReferencedTypes(HashSet<Node> referencedTypes, Node node)
    {
      foreach (Node containedNode in node.GetContainmentTargets(node.Owner))
      {
        if (referencedTypes.Contains(containedNode))
        {
          // We've seen this node before
          continue;
        }

        if (containedNode.HasCategory(typeCategory))
        {
          referencedTypes.Add(containedNode);
        }
        else
        {
          GetReferencedTypes(referencedTypes, containedNode);
        }
      }
    }
    public static string GetFullyQualifiedTypeName(Node typeNode)
    {
      try
      {
         string returnValue;
         CodeQualifiedIdentifierBuilder id = 
           new CodeQualifiedIdentifierBuilder(
                   typeNode.Id, typeNode.Owner);
         returnValue = id.GetFullyQualifiedLabel(
              CodeQualifiedIdentifierBuilder.LabelFormat
              .NoAssemblyPrefix);
        return returnValue;
      }
      catch { }
     return typeNode.Label;
  }

  public static object ExtractProperty
             (Node layerModel, string propertyName)
  {
    object propertyValue = null;
    var propertyCategory = 
        layerModel.Owner.DocumentSchema.GetProperty(propertyName);
    if (propertyCategory != null)
    {
      propertyValue = layerModel[propertyCategory];
    }
    return propertyValue;
  }
}

請參閱

其他資源

建立圖層圖表的擴充功能

變更記錄

日期

記錄

原因

2010 年 12 月

已針對 Visual Studio 2010 Feature Pack 2 更新。

資訊加強。