レイヤー図へのカスタム アーキテクチャ検証の追加
Visual Studio Ultimate および Visual Studio Premium では、Visual Studio プロジェクトのソース コードをレイヤー モデルと対比して検証し、ソース コードがレイヤー図の依存関係に準拠していることを確認できます。 標準の検証アルゴリズムがありますが、Visual Studio Ultimate および Visual Studio Premium 用の独自の検証拡張機能を定義できます。
ユーザーがレイヤー図で [アーキテクチャの検証] を選択すると、標準の検証メソッドが呼び出された後、インストールされている検証拡張機能が呼び出されます。
注意
レイヤー図での検証は、UML 図での検証と同じではありません。レイヤー図での主要な目的は、図と、ソリューションの他の部分のプログラム コードを比較することです。
レイヤー検証拡張機能を Visual Studio Integration Extension (VSIX) にパッケージ化し、他の Visual Studio Ultimate ユーザーに配布できます。 検証機能は、単独で VSIX に配置することも、他の拡張機能と組み合わせて同じ VSIX に含めることもできます。 検証コントロールのコードは、他の拡張機能と同じプロジェクトではなく、専用の Visual Studio プロジェクトで作成する必要があります。
注意
検証プロジェクトを作成したら、このトピックの最後にあるコード例をコピーし、各自のニーズに合わせて編集してください。
要件
Visual Studio Ultimate
Visual Studio SDK
Visual Studio Visualization and Modeling SDK
新しい VSIX でレイヤー検証コントロールを定義する
最も簡単に検証コントロールを作成するには、プロジェクト テンプレートを使用します。 この方法では、コードと VSIX マニフェストが同じプロジェクトに配置されます。
プロジェクト テンプレートを使用して拡張機能を定義するには
[ファイル] メニューの [新しいプロジェクト] を使用して、新しいソリューションにプロジェクトを作成します。
[新しいプロジェクト] ダイアログ ボックスの [モデリング プロジェクト] で、[Layer Designer Validation Extension] (レイヤー デザイナー検証拡張機能) をクリックします。
このテンプレートでは、小さい例を含むプロジェクトが作成されます。
注意
テンプレートを正常に機能させるには:
-
LogValidationError の呼び出しを編集し、省略可能な引数 errorSourceNodes と errorTargetNodes を削除します。
-
カスタム プロパティを使用する場合は、「レイヤー図へのカスタム プロパティの追加」で説明されている更新プログラムを適用します。また、モデル ソリューションを開く前にアーキテクチャ エクスプローラーを開きます。
-
コードを編集して検証を定義します。 詳細については、「検証のプログラミング」を参照してください。
拡張機能をテストするには、「レイヤー検証のデバッグ」を参照してください。
注意
メソッドは特定の状況においてのみ呼び出され、ブレークポイントは自動的には動作しません。詳細については、「レイヤー検証のデバッグ」を参照してください。
Visual Studio のメイン インスタンスまたは別のコンピューターに拡張機能をインストールするには、bin\* で .vsix ファイルを探します。 このファイルをインストール先のコンピューターにコピーして、ダブルクリックします。 拡張機能をアンインストールするには、[ツール] メニューの [拡張機能マネージャー] を使用します。
レイヤー検証コントロールを別の VSIX に追加する
レイヤー検証コントロール、コマンド、および他の拡張機能を含む 1 つの VSIX を作成する場合は、VSIX を定義するプロジェクトとハンドラー用のプロジェクトを別にすることをお勧めします。 他の種類のモデリング拡張機能については、「UML モデルと図の拡張」を参照してください。
レイヤー検証を別の VSIX に追加するには
新規または既存の Visual Studio Ultimate ソリューションでクラス ライブラリ プロジェクトを作成します。 [新しいプロジェクト] ダイアログ ボックスで、[Visual C#] をクリックし、[クラス ライブラリ] をクリックします。 このプロジェクトには、レイヤー検証クラスが含められます。
ソリューションで VSIX プロジェクトを特定または作成します。 VSIX プロジェクトには、source.extension.vsixmanifest という名前のファイルが含まれます。 VSIX プロジェクトを追加する必要がある場合は、以下の手順に従います。
[新しいプロジェクト] ダイアログ ボックスで、[Visual C#]、[機能拡張]、[VSIX プロジェクト] の順にクリックします。
ソリューション エクスプローラーで、VSIX プロジェクトのショートカット メニューを開き、[スタートアップ プロジェクトに設定] をクリックします。
source.extension.vsixmanifest の [アセット] で、レイヤー検証プロジェクトを MEF コンポーネントとして追加します。
[新規作成] をクリックします。
[Add New Asset] (新しいアセットの追加) ダイアログ ボックスで、次のように設定します。
[種類] = Microsoft.VisualStudio.MefComponent
[ソース] = 現在のソリューション内のプロジェクト
[プロジェクト] = your validator project
また、このプロジェクトをレイヤー検証として追加する必要があります。
[新規作成] をクリックします。
[Add New Asset] (新しいアセットの追加) ダイアログ ボックスで、次のように設定します。
[種類] = Microsoft.VisualStudio.ArchitectureTools.Layer.Validator。 これは、ドロップダウン リストのオプションの 1 つではありません。 キーボードで入力する必要があります。
[ソース] = 現在のソリューション内のプロジェクト
[プロジェクト] = your validator project
レイヤー検証プロジェクトに戻り、次のプロジェクト参照を追加します。
参照
実行できる操作
Microsoft.VisualStudio.GraphModel.dll
アーキテクチャ グラフを読み取る
Microsoft.VisualStudio.ArchitectureTools.Extensibility.CodeSchema.dll
レイヤーと関連付けられているコード DOM を読み取る
Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer.dll
レイヤー モデルを読み取る
Microsoft.VisualStudio.ArchitectureTools.Extensibility
図形と図を読み取って更新する
System.ComponentModel.Composition
MEF (Managed Extensibility Framework) を使用して検証コンポーネントを定義する
Microsoft.VisualStudio.Modeling.Sdk.12.0
モデリング拡張機能を定義する
このトピックの最後にあるコード例を、検証ライブラリ プロジェクトのクラス ファイルにコピーして、検証のコードが含まれるようにします。 詳細については、「検証のプログラミング」を参照してください。
拡張機能をテストするには、「レイヤー検証のデバッグ」を参照してください。
注意
メソッドは特定の状況においてのみ呼び出され、ブレークポイントは自動的には動作しません。詳細については、「レイヤー検証のデバッグ」を参照してください。
Visual Studio のメイン インスタンスまたは別のコンピューターに VSIX をインストールするには、VSIX プロジェクトの bin ディレクトリで .vsix ファイルを探します。 このファイルを、VSIX をインストールするコンピューターにコピーします。 Windows エクスプローラーで、VSIX ファイルをダブルクリックします。これは Windows 8 のエクスプローラーです。
VSIX をアンインストールするには、[ツール] メニューの [拡張機能マネージャー] を使用します。
検証のプログラミング
レイヤー検証拡張機能を定義するには、以下の特性を備えたクラスを定義します。
宣言の全体的な形式を次に示します。
using System.ComponentModel.Composition; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.CodeSchema; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer; using Microsoft.VisualStudio.GraphModel; ... [Export(typeof(IValidateArchitectureExtension))] public partial class Validator1Extension : IValidateArchitectureExtension { public void ValidateArchitecture(Graph graph) { GraphSchema schema = graph.DocumentSchema; ... } }
エラーを検出したときは、LogValidationError() を使用して報告できます。
注意
LogValidationErrorの省略可能なパラメーターを使用しないでください。
ユーザーが [アーキテクチャの検証] を実行すると、レイヤーのランタイム システムがレイヤーとその成果物を分析して、グラフを生成します。 グラフは 4 つの部分で構成されます。
Visual Studio ソリューションのレイヤー モデルは、グラフではノードとリンクとして表されます。
ソリューションで定義されているコード、プロジェクト アイテム、および他の成果物は、ノードおよび分析システムによって検出された依存関係を示すリンクとして表されます。
レイヤー ノードからコード成果物ノードへのリンク。
検証コントロールによって検出されたエラーを表すノード。
グラフが作成されると、標準の検証メソッドが呼び出されます。 これが完了すると、インストールされているすべての拡張検証メソッドが、不定の順序で呼び出されます。 グラフを渡された各 ValidateArchitecture メソッドは、グラフをスキャンし、検出したエラーを報告します。
注意
これは、UML 図に適用される検証プロセスと同じではなく、特定領域言語で使用できる検証プロセスとも同じではありません。
検証メソッドでは、レイヤー モデルまたは検証対象のコードを変更することはできません。
グラフ モデルは、Microsoft.VisualStudio.GraphModel で定義されています。 そのプリンシパル クラスは、GraphNode および GraphLink です。
各ノードおよび各リンクには 1 つ以上のカテゴリがあり、それぞれが表す要素または関係の種類が指定されています。 標準的なグラフのノードには以下のカテゴリがあります。
Dsl.LayerModel
Dsl.Layer
Dsl.Reference
CodeSchema_Type
CodeSchema_Namespace
CodeSchema_Type
CodeSchema_Method
CodeSchema_Field
CodeSchema_Property
レイヤーからコード内の要素へのリンクのカテゴリは "Represents" です。
検証のデバッグ
レイヤー検証拡張機能をデバッグするには、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.ComponentModel.Composition;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.CodeSchema;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer;
using Microsoft.VisualStudio.GraphModel;
namespace Validator3
{
[Export(typeof(IValidateArchitectureExtension))]
public partial class Validator3Extension : IValidateArchitectureExtension
{
/// <summary>
/// Validate the architecture
/// </summary>
/// <param name="graph">The graph</param>
public void ValidateArchitecture(Graph graph)
{
if (graph == null) throw new ArgumentNullException("graph");
// Uncomment the line below to debug this extension during validation
// System.Windows.Forms.MessageBox.Show("Attach 2 to GraphCmd.exe with process id " + System.Diagnostics.Process.GetCurrentProcess().Id);
// Get all layers on the diagram
foreach (GraphNode layer in graph.Nodes.GetByCategory("Dsl.Layer"))
{
System.Threading.Thread.Sleep(100);
// Get the required regex property from the layer node
string regexPattern = "^[a-zA-Z]+$"; //layer[customPropertyCategory] as string;
if (!string.IsNullOrEmpty(regexPattern))
{
Regex regEx = new Regex(regexPattern);
// Get all referenced types in this layer including those from nested layers so each
// type is validated against all containing layer constraints.
foreach (GraphNode containedType in layer.FindDescendants().Where(node => node.HasCategory("CodeSchema_Type")))
{
// Check the type name against the required regex
CodeGraphNodeIdBuilder builder = new CodeGraphNodeIdBuilder(containedType.Id, graph);
string typeName = builder.Type.Name;
if (!regEx.IsMatch(typeName))
{
// Log an error
string message = string.Format(CultureInfo.CurrentCulture, Resources.InvalidTypeNameMessage, typeName);
this.LogValidationError(graph, typeName + "TypeNameError", message, GraphErrorLevel.Error, layer);
}
}
}
}
}
}
}