次の方法で共有


レイヤー図へのカスタム アーキテクチャ検証の追加

更新 : 2010 年 12 月

Visual Studio 2010 Ultimate および Visual Studio 2010 Premium では、Visual Studio プロジェクトのソース コードをレイヤー モデルと対比して検証し、ソース コードがレイヤー図の依存関係に準拠していることを確認できます。 標準の検証アルゴリズムがありますが、この Visual Studio 2010 Feature Pack を使用すると、Visual Studio Ultimate および Visual Studio Premium 用の独自の検証拡張機能を定義できます。 詳細については、「Visual Studio Feature Pack」を参照してください。

ユーザーがレイヤー図で [アーキテクチャの検証] を選択すると、標準の検証メソッドが呼び出された後、インストールされている検証拡張機能が呼び出されます。

注意

レイヤー図での検証は、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 に追加する

レイヤー検証コントロール、コマンド、および他の拡張機能を含む 1 つの VSIX を作成する場合は、VSIX を定義するプロジェクトとハンドラー用のプロジェクトを別にすることをお勧めします。 他の種類のモデリング拡張機能については、「UML モデルと図の拡張」を参照してください。

レイヤー検証を別の VSIX に追加するには

  1. 新規または既存の Visual Studio Ultimate ソリューションでクラス ライブラリ プロジェクトを作成します。 [新しいプロジェクト] ダイアログ ボックスで、[Visual C#] をクリックし、[クラス ライブラリ] をクリックします。 このプロジェクトには、レイヤー検証クラスが含められます。

  2. ソリューションで VSIX プロジェクトを特定または作成します。 VSIX プロジェクトには、source.extension.vsixmanifest という名前のファイルが含まれます。 VSIX プロジェクトを追加する必要がある場合は、以下の手順に従います。

    1. [新しいプロジェクト] ダイアログ ボックスで [Visual C#] を展開し、[拡張機能] をクリックして [VSIX Project] (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. [ソースの選択] で、[プロジェクト] をクリックし、検証クラス ライブラリ プロジェクトの名前を選択します。

  5. [参照][参照の追加] をクリックし、この Feature Pack のランタイムを選択します。

  6. レイヤー検証プロジェクトに戻り、次のプロジェクト参照を追加します。

    参照

    実行できる操作

    Visual Studio 2010 Visualization and Modeling Feature Pack がインストールされている場合:

    %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 Feature Pack がインストールされている場合:

    %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 Feature Pack がインストールされている場合:

    %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

    MEF (Managed Extensibility Framework) を使用して検証コンポーネントを定義する

    Microsoft.VisualStudio.Modeling.Sdk.10.0

    モデリング拡張機能を定義する

    注意

    %LocalAppData% は、通常は <ドライブ名>:\Users\<ユーザー名>\AppData\Local です。 Windows XP または Windows 2003 では、%LocalAppData% の代わりに %AppData% を使用します。

  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() を使用して報告できます。

ユーザーが [アーキテクチャの検証] を実行すると、レイヤーのランタイム システムがレイヤーとその成果物を分析して、グラフを生成します。 グラフは 4 つの部分で構成されます。

  • Visual Studio ソリューションのレイヤー モデルは、グラフではノードとリンクとして表されます。

  • ソリューションで定義されているコード、プロジェクト アイテム、および他の成果物は、ノードおよび分析システムによって検出された依存関係を示すリンクとして表されます。

  • レイヤー ノードからコード成果物ノードへのリンク。

  • 検証コントロールによって検出されたエラーを表すノード。

グラフが作成されると、標準の検証メソッドが呼び出されます。 これが完了すると、インストールされているすべての拡張検証メソッドが、不定の順序で呼び出されます。 グラフを渡された各 ValidateArchitecture メソッドは、グラフをスキャンし、検出したエラーを報告します。

注意

これは、UML 図に適用される検証プロセスと同じではなく、特定領域言語で使用できる検証プロセスとも同じではありません。

検証メソッドでは、レイヤー モデルまたは検証対象のコードを変更することはできません。

グラフ モデルは、Microsoft.VisualStudio.GraphModel で定義されています。 そのプリンシパル クラスは、Node および Link です。

各ノードおよび各リンクには 1 つ以上のカテゴリがあり、それぞれが表す要素または関係の種類が指定されています。 標準的なグラフのノードには以下のカテゴリがあります。

  • Dsl.LayerModel

  • Dsl.Layer

  • Dsl.Reference

  • CodeSchema_Type

  • CodeSchema_Namespace

  • CodeSchema_Type

  • CodeSchema_Method

  • CodeSchema_Field

  • CodeSchema_Property

レイヤーからコード内の要素へのリンクのカテゴリは "Represents" です。

次のコードは、アーキテクチャ検証拡張機能の一般的な例です。 ソリューションのコードで宣言されているすべての型がレイヤー モデルによって少なくとも 1 回は参照されていることを検証します。 ユーザーは、モデルの Boolean カスタム プロパティを設定することで、各レイヤー モデルで実行する必要のある検証を制御できます。

エラーが検出された場合は、LogValidationError が呼び出されます。

検証のデバッグ

レイヤー検証拡張機能をデバッグするには、Ctrl キーを押しながら F5 キーを押します。 Visual Studio の実験用のインスタンスが開きます。 このインスタンスで、レイヤー モデルを開くか作成します。 このモデルは、コードと関連付けられている必要があり、少なくとも 1 つの依存関係を含む必要があります。

依存関係を含むソリューションでのテスト

以下の特性が存在していない限り、検証は実行されません。

  • レイヤー図に、少なくとも 1 つの依存関係リンクが存在する。

  • コード要素と関連付けられたレイヤーがモデルに存在する。

初めて 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 ビルド がインストールされているコンピューターにインストールするには、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 用に更新。

情報の拡充